From a06df504a678c0739160512d9d990579653bf02e Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Thu, 28 Nov 2024 00:41:29 +0100 Subject: [PATCH] initial commit --- .cargo/config.toml | 40 +++ .envrc | 1 + .gitignore | 3 + Cargo.lock | 598 +++++++++++++++++++++++++++++++++++ Cargo.toml | 26 ++ Makefile | 10 + memory.x | 15 + shell.nix | 9 + src/main.rs | 290 +++++++++++++++++ src/serial_number.rs.example | 1 + 10 files changed, 993 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 Makefile create mode 100644 memory.x create mode 100644 shell.nix create mode 100644 src/main.rs create mode 100644 src/serial_number.rs.example diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..a4dff55 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,40 @@ +# +# Cargo Configuration for the https://github.com/rp-rs/rp-hal.git repository. +# +# Copyright (c) The RP-RS Developers, 2021 +# +# You might want to make a similar file in your own repository if you are +# writing programs for Raspberry Silicon microcontrollers. +# +# This file is MIT or Apache-2.0 as per the repository README.md file +# + +[build] +# Set the default target to match the Cortex-M0+ in the RP2040 +target = "thumbv6m-none-eabi" + +# Target specific options +[target.thumbv6m-none-eabi] +# Pass some extra options to rustc, some of which get passed on to the linker. +# +# * linker argument --nmagic turns off page alignment of sections (which saves +# flash space) +# * linker argument -Tlink.x tells the linker to use link.x as the linker +# script. This is usually provided by the cortex-m-rt crate, and by default +# the version in that crate will include a file called `memory.x` which +# describes the particular memory layout for your specific chip. +# * no-vectorize-loops turns off the loop vectorizer (seeing as the M0+ doesn't +# have SIMD) +rustflags = [ + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + "-C", "no-vectorize-loops", +] + +# This runner will make a UF2 file and then copy it to a mounted RP2040 in USB +# Bootloader mode: +runner = "elf2uf2-rs -d" + +# This runner will find a supported SWD debug probe and flash your RP2040 over +# SWD: +# runner = "probe-rs run --chip RP2040" diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2105e7c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +/.direnv +/src/serial_number.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4337a5d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,598 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield 0.13.2", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "crc-any" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62ec9ff5f7965e4d7280bd5482acd20aadb50d632cf6c1d74493856b011fa73" +dependencies = [ + "debug-helper", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "debug-helper" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" + +[[package]] +name = "defmt" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9112096fbf91d9458d3dc1bca22e87e2684cad608c032f80135e2471614ceebe" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e40098d5ffbf1b3c88dff66c3b168a7dc4f3e8ff8604a00441660040a134e20" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "defmt-parser" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" +dependencies = [ + "thiserror", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "embedded-dma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "frunk" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874b6a17738fc273ec753618bac60ddaeac48cb1d7684c3e7bd472e57a28b817" +dependencies = [ + "frunk_core", + "frunk_derives", +] + +[[package]] +name = "frunk_core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3529a07095650187788833d585c219761114005d5976185760cf794d265b6a5c" + +[[package]] +name = "frunk_derives" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e99b8b3c28ae0e84b604c75f721c21dc77afb3706076af5e8216d15fd1deaae3" +dependencies = [ + "frunk_proc_macro_helpers", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "frunk_proc_macro_helpers" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05a956ef36c377977e512e227dcad20f68c2786ac7a54dacece3746046fea5ce" +dependencies = [ + "frunk_core", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "fugit" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" +dependencies = [ + "gcd", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pio" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3" +dependencies = [ + "arrayvec", + "num_enum 0.5.11", + "paste", +] + +[[package]] +name = "portable-atomic" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rp-pico" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9342d3ac7011ac688300979e9b52a81f0add1d05feb02868cf94bfee0705b28" +dependencies = [ + "cortex-m-rt", + "fugit", + "rp2040-boot2", + "rp2040-hal", + "usb-device", +] + +[[package]] +name = "rp2040-boot2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c92f344f63f950ee36cf4080050e4dce850839b9175da38f9d2ffb69b4dbb21" +dependencies = [ + "crc-any", +] + +[[package]] +name = "rp2040-hal" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11e711940087f2cdff8aeae9f4b902e2014c06a00b39a1092686b81ec973d6f" +dependencies = [ + "bitfield 0.14.0", + "cortex-m", + "critical-section", + "embedded-dma", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-io", + "frunk", + "fugit", + "itertools", + "nb 1.1.0", + "paste", + "pio", + "rand_core", + "rp2040-hal-macros", + "rp2040-pac", + "usb-device", + "vcell", + "void", +] + +[[package]] +name = "rp2040-hal-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86479063e497efe1ae81995ef9071f54fd1c7427e04d6c5b84cde545ff672a5e" +dependencies = [ + "cortex-m-rt", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rp2040-pac" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83cbcd3f7a0ca7bbe61dc4eb7e202842bee4e27b769a7bf3a4a72fa399d6e404" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "vcell", +] + +[[package]] +name = "rp2040-usb-ramdisk" +version = "0.1.0" +dependencies = [ + "cortex-m-rt", + "embedded-hal 1.0.0", + "rp-pico", + "rp2040-boot2", + "rp2040-hal", + "usb-device", + "usbd-storage", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "usb-device" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" +dependencies = [ + "defmt", + "heapless", + "portable-atomic", +] + +[[package]] +name = "usbd-storage" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee23ab04c7d76b63c417cf2fa672d720477d2e71c6822ac6e5ceaf526f48f394" +dependencies = [ + "defmt", + "num_enum 0.6.1", + "usb-device", +] + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1e78573 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "rp2040-usb-ramdisk" +version = "0.1.0" +edition = "2024" + +[dependencies] +cortex-m-rt = { version = "0.7.5", optional = true } +embedded-hal = "1.0.0" +rp-pico = "0.9.0" +rp2040-boot2 = { version = "0.3.0", optional = true } +rp2040-hal = "0.10.2" +usb-device = "0.3.2" +usbd-storage = { version = "1.0.0", features = ["scsi", "bbb", "defmt"] } + +[features] +default = ["boot2", "rt", "critical-section-impl"] +boot2 = ["rp2040-boot2"] +rt = ["cortex-m-rt","rp2040-hal/rt"] +critical-section-impl = ["rp2040-hal/critical-section-impl"] +cortex-m-rt = ["dep:cortex-m-rt"] + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bf3f24f --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +.PHONY: flash +flash: target/thumbv6m-none-eabi/release/ramdisk-rs + elf2uf2-rs --deploy $< + +target/thumbv6m-none-eabi/release/ramdisk-rs: src/main.rs Cargo.toml + cargo build --target thumbv6m-none-eabi --release + +target/thumbv6m-none-eabi/release/ramdisk-rs.uf2: target/thumbv6m-none-eabi/release/ramdisk-rs + elf2uf2-rs $< $@ + diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..4077aab --- /dev/null +++ b/memory.x @@ -0,0 +1,15 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} + +EXTERN(BOOT2_FIRMWARE) + +SECTIONS { + /* ### Boot loader */ + .boot2 ORIGIN(BOOT2) : + { + KEEP(*(.boot2)); + } > BOOT2 +} INSERT BEFORE .text; diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..da585a2 --- /dev/null +++ b/shell.nix @@ -0,0 +1,9 @@ +{ pkgs ? import {} }: +pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + elf2uf2-rs + gcc + gnumake + rustup + ]; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..4e5fa05 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,290 @@ +#![no_std] +#![no_main] + +use rp_pico::entry; + +use embedded_hal::digital::OutputPin; + +use rp_pico::hal::pac; + +use rp_pico::hal; + +use usb_device::{class_prelude::*, prelude::*}; + +use usbd_storage::subclass::scsi::{Scsi, ScsiCommand}; +use usbd_storage::subclass::Command; +use usbd_storage::transport::bbb::{BulkOnly, BulkOnlyError}; +use usbd_storage::transport::TransportError; + +mod serial_number; + +const DISK_BLOCK_SIZE: u32 = 512; +const DISK_BLOCK_NUM: u32 = 500; + +const USB_PACKET_SIZE: u16 = 64; // 8,16,32,64 +const MAX_LUN: u8 = 0; // max 0x0F + +#[derive(Default)] +struct State { + storage_offset: usize, + sense_key: Option, + sense_key_code: Option, + sense_qualifier: Option, +} + +impl State { + fn reset(&mut self) { + self.storage_offset = 0; + self.sense_key = None; + self.sense_key_code = None; + self.sense_qualifier = None; + } +} + +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + //defmt::error!("{}", defmt::Display2Format(info)); + loop {} +} + +#[entry] +fn main() -> ! { + let mut storage: [u8; (DISK_BLOCK_SIZE * DISK_BLOCK_NUM) as usize] = [0u8; (DISK_BLOCK_SIZE * DISK_BLOCK_NUM) as usize]; + + // Initialize Boot Sector (Block 0) + storage[0x000..0x03E].copy_from_slice(&[ + /* 000 */ 0xEB, 0x3C, 0x90, b'm', b'k', b'f', b's', b'.', b'f', b'a', b't', 0x00, 0x02, 0x04, 0x01, 0x00, + /* 010 */ 0x02, 0x00, 0x02, (DISK_BLOCK_NUM & 0xff) as u8, + (DISK_BLOCK_NUM >> 8) as u8, + 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 020 */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0xDE, 0xAD, 0xBE, 0xEF, b'R', b'A', b'M', b'_', b'U', + /* 030 */ b'S', b'B', b' ', b' ', b' ', b' ', b'F', b'A', b'T', b'1', b'2', b' ', b' ', b' ' + ]); + storage[0x1FE..0x200].copy_from_slice(&[0x55, 0xAA]); + storage[0x200..0x203].copy_from_slice(&[0xF8, 0xFF, 0xFF]); + storage[0x400..0x403].copy_from_slice(&[0xF8, 0xFF, 0xFF]); + storage[0x600..0x61A].copy_from_slice(&[ + /* 600 */ b'R', b'A', b'M', b'_', b'U', b'S', b'B', b' ', b' ', b' ', b' ', 0x08, 0x00, 0x00, 0xF9, 0x98, + /* 610 */ 0x3A, 0x58, 0x3A, 0x58, 0x00, 0x00, 0xF9, 0x98, 0x3A, 0x58 + ]); + + let mut state: State = State { + storage_offset: 0, + sense_key: None, + sense_key_code: None, + sense_qualifier: None, + }; + + let mut pac = pac::Peripherals::take().unwrap(); + + let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); + + let clocks = hal::clocks::init_clocks_and_plls( + rp_pico::XOSC_CRYSTAL_FREQ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let sio = hal::Sio::new(pac.SIO); + let pins = rp_pico::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + let mut led_pin = pins.led.into_push_pull_output(); + + let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( + pac.USBCTRL_REGS, + pac.USBCTRL_DPRAM, + clocks.usb_clock, + true, + &mut pac.RESETS, + )); + + let mut usb_transport_buf: [u8; 512] = [0; 512]; + let mut scsi = usbd_storage::subclass::scsi::Scsi::new(&usb_bus, USB_PACKET_SIZE, MAX_LUN, usb_transport_buf.as_mut_slice()).unwrap(); + + let mut usb_device = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0xcafe, 0x4002)) + .strings(&[StringDescriptors::new(LangID::EN) + .manufacturer("jalr") + .product("RAM Mass Storage") + .serial_number(serial_number::SERIAL)]) + .unwrap() + .device_class(0x08) + .self_powered(false) + .build(); + + loop { + led_pin.set_high().unwrap(); + + if !usb_device.poll(&mut [&mut scsi]) { + continue; + } + + if matches!(usb_device.state(), UsbDeviceState::Default) { + state.reset(); + } + + let _ = scsi.poll(|command| { + led_pin.set_low().unwrap(); + if let Err(err) = process_command(command, &mut state, &mut storage) { + //defmt::error!("{}", err); + } + }); + } +} + + +fn process_command( + mut command: Command>>, + state: &mut State, + storage: &mut [u8; (DISK_BLOCK_SIZE * DISK_BLOCK_NUM) as usize] +) -> Result<(), TransportError> { + //defmt::info!("Handling: {}", command.kind); + + static DISK_MODEL: [u8; 16] = *b"USB RAM disk "; + + match command.kind { + ScsiCommand::TestUnitReady { .. } => { + command.pass(); + } + ScsiCommand::Inquiry { .. } => { + command.try_write_data_all(&[ + 0x00, // periph qualifier, periph device type + 0x80, // Removable + 0x04, // SPC-2 compliance + 0x02, // NormACA, HiSu, Response data format + 0x20, // 36 bytes in total + 0x00, // additional fields, none set + 0x00, // additional fields, none set + 0x00, // additional fields, none set + b'j', b'a', b'l', b'r', b' ', b' ', b' ', b' ', // 8-byte T-10 vendor id + ])?; + command.try_write_data_all(&DISK_MODEL)?; + command.try_write_data_all(&[ + b'1', b'.', b'2', b'3', // 4-byte product revision + ])?; + command.pass(); + } + ScsiCommand::RequestSense { .. } => { + command.try_write_data_all(&[ + 0x70, // RESPONSE CODE. Set to 70h for information on current errors + 0x00, // obsolete + state.sense_key.unwrap_or(0), // Bits 3..0: SENSE KEY. Contains information describing the error. + 0x00, + 0x00, + 0x00, + 0x00, // INFORMATION. Device-specific or command-specific information. + 0x00, // ADDITIONAL SENSE LENGTH. + 0x00, + 0x00, + 0x00, + 0x00, // COMMAND-SPECIFIC INFORMATION + state.sense_key_code.unwrap_or(0), // ASC + state.sense_qualifier.unwrap_or(0), // ASCQ + 0x00, + 0x00, + 0x00, + 0x00, + ])?; + state.reset(); + command.pass(); + }, + ScsiCommand::ReadCapacity10 { .. } => { + let mut data = [0u8; 8]; + let _ = &mut data[0..4].copy_from_slice(&u32::to_be_bytes(DISK_BLOCK_NUM - 1)); + let _ = &mut data[4..8].copy_from_slice(&u32::to_be_bytes(DISK_BLOCK_SIZE)); + command.try_write_data_all(&data)?; + command.pass(); + } + ScsiCommand::ReadCapacity16 { .. } => { + let mut data = [0u8; 16]; + let _ = &mut data[0..8].copy_from_slice(&u32::to_be_bytes(DISK_BLOCK_NUM - 1)); + let _ = &mut data[8..12].copy_from_slice(&u32::to_be_bytes(DISK_BLOCK_SIZE)); + command.try_write_data_all(&data)?; + command.pass(); + } + ScsiCommand::ReadFormatCapacities { .. } => { + let mut data = [0u8; 12]; + let _ = &mut data[0..4].copy_from_slice(&[ + 0x00, 0x00, 0x00, 0x08, // capacity list length + ]); + let _ = &mut data[4..8].copy_from_slice(&u32::to_be_bytes(DISK_BLOCK_NUM as u32)); // number of blocks + data[8] = 0x01; //unformatted media + let block_length_be = u32::to_be_bytes(DISK_BLOCK_SIZE); + data[9] = block_length_be[1]; + data[10] = block_length_be[2]; + data[11] = block_length_be[3]; + + command.try_write_data_all(&data)?; + command.pass(); + } + ScsiCommand::Read { lba, len } => { + let lba = lba as u32; + let len = len as u32; + if state.storage_offset != (len * DISK_BLOCK_SIZE) as usize { + let start = (DISK_BLOCK_SIZE * lba) as usize + state.storage_offset; + let end = (DISK_BLOCK_SIZE * lba) as usize + (DISK_BLOCK_SIZE * len) as usize; + + // Uncomment this in order to push data in chunks smaller than a USB packet. + // let end = min(start + USB_PACKET_SIZE as usize - 1, end); + + //defmt::info!("Data transfer >>>>>>>> [{}..{}]", start, end); + let count = command.write_data(&mut storage[start..end])?; + state.storage_offset += count; + } else { + command.pass(); + state.storage_offset = 0; + } + }, + ScsiCommand::Write { lba, len } => { + let lba = lba as u32; + let len = len as u32; + if state.storage_offset != (len * DISK_BLOCK_SIZE) as usize { + let start = (DISK_BLOCK_SIZE * lba) as usize + state.storage_offset; + let end = (DISK_BLOCK_SIZE * lba) as usize + (DISK_BLOCK_SIZE * len) as usize; + //defmt::info!("Data transfer <<<<<<<< [{}..{}]", start, end); + let count = command.read_data(&mut storage[start..end])?; + state.storage_offset += count; + + if state.storage_offset == (len * DISK_BLOCK_SIZE) as usize { + command.pass(); + state.storage_offset = 0; + } + } else { + command.pass(); + state.storage_offset = 0; + } + }, + ScsiCommand::ModeSense6 { .. } => { + command.try_write_data_all(&[ + 0x03, // number of bytes that follow + 0x00, // the media type is SBC + 0x00, // not write-protected, no cache-control bytes support + 0x00, // no mode-parameter block descriptors + ])?; + command.pass(); + } + ScsiCommand::ModeSense10 { .. } => { + command.try_write_data_all(&[0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])?; + command.pass(); + } + ref unknown_scsi_kind => { + //defmt::error!("Unknown SCSI command: {}", unknown_scsi_kind); + state.sense_key.replace(0x05); // illegal request Sense Key + state.sense_key_code.replace(0x20); // Invalid command operation ASC + state.sense_qualifier.replace(0x00); // Invalid command operation ASCQ + command.fail(); + } + } + + Ok(()) +} diff --git a/src/serial_number.rs.example b/src/serial_number.rs.example new file mode 100644 index 0000000..e61eae8 --- /dev/null +++ b/src/serial_number.rs.example @@ -0,0 +1 @@ +pub const SERIAL: &str = "example-4711";