diff --git a/advanced/firmware/.cargo/config b/advanced/firmware/.cargo/config index c4e7eee..7bf7723 100644 --- a/advanced/firmware/.cargo/config +++ b/advanced/firmware/.cargo/config @@ -1,5 +1,5 @@ [target.thumbv7em-none-eabi] -runner = "dk-run" +runner = "probe-run --chip nRF52840_xxAA" rustflags = [ "-C", "link-arg=-Tlink.x", ] diff --git a/beginner/apps/.cargo/config b/beginner/apps/.cargo/config index 4e40aab..426f55a 100644 --- a/beginner/apps/.cargo/config +++ b/beginner/apps/.cargo/config @@ -1,5 +1,5 @@ [target.thumbv7em-none-eabi] -runner = "dk-run" +runner = "probe-run --chip nRF52840_xxAA" rustflags = [ "-C", "link-arg=-Tlink.x", ] diff --git a/boards/dk/src/lib.rs b/boards/dk/src/lib.rs index 6e092c1..2da358c 100644 --- a/boards/dk/src/lib.rs +++ b/boards/dk/src/lib.rs @@ -301,7 +301,7 @@ fn RTC0() { unsafe { core::mem::transmute::<_, RTC0>(()).events_ovrflw.reset() } } -/// Exits the application and prints a backtrace when the program is executed through the `dk-run` +/// Exits the application and prints a backtrace when the program is executed through the `probe-run` /// Cargo runner pub fn exit() -> ! { log::info!("`dk::exit() called; exiting ...`"); diff --git a/embedded-workshop-book/src/hello-world.md b/embedded-workshop-book/src/hello-world.md index 8fc3dc1..bb901dc 100644 --- a/embedded-workshop-book/src/hello-world.md +++ b/embedded-workshop-book/src/hello-world.md @@ -15,8 +15,8 @@ If you are not using VS code run the `cargo run --bin hello` command from the `a > NOTE if you run into an error along the lines of "Debug power request failed" retry the operation and the error should disappear -The `firmware` workspace has been configured to cross-compile applications to the ARM Cortex-M architecture and then run them through the `dk-run` custom Cargo runner. The `dk-run` tool will load and run the embedded application on the microcontroller and collect logs from the microcontroller. +The `firmware` workspace has been configured to cross-compile applications to the ARM Cortex-M architecture and then run them using the `probe-run` custom Cargo runner. The `probe-run` tool will load and run the embedded application on the microcontroller and collect logs from the microcontroller. -The `dk-run` process will terminate when the microcontroller enters the "halted" state. From the embedded application, one can enter the "halted" state using the `asm::bkpt` function. For convenience, an `exit` function is provided in the `dk` Hardware Abstraction Layer (HAL). This function is divergent like `std::process::exit` (`fn() -> !`) and can be used to halt the device and terminate the `dk-run` process. +The `probe-run` process will terminate when the microcontroller enters the "halted" state. From the embedded application, one can enter the "halted" state using the `asm::bkpt` function. For convenience, an `exit` function is provided in the `dk` Hardware Abstraction Layer (HAL). This function is divergent like `std::process::exit` (`fn() -> !`) and can be used to halt the device and terminate the `probe-run` process. -Note that when the `dk-run` tool sees the device enter the halted state it will proceed to *reset-halt* the device. This is particularly important when writing USB applications because simply leaving the device in a halted state will make it appear as an unresponsive USB device to the host. Some OSes (e.g. Linux) will try to make an unresponsive device respond by power cycling the entire USB bus -- this will cause all other USB devices on the bus to be re-enumerated. Reset-halting the device will cause it to be electrically disconnected from the host USB bus and avoid the "power cycle the whole USB bus" scenario. +Note that when the `probe-run` tool sees the device enter the halted state it will proceed to *reset-halt* the device. This is particularly important when writing USB applications because simply leaving the device in a halted state will make it appear as an unresponsive USB device to the host. Some OSes (e.g. Linux) will try to make an unresponsive device respond by power cycling the entire USB bus -- this will cause all other USB devices on the bus to be re-enumerated. Reset-halting the device will cause it to be electrically disconnected from the host USB bus and avoid the "power cycle the whole USB bus" scenario. diff --git a/embedded-workshop-book/src/installation.md b/embedded-workshop-book/src/installation.md index 3cee48f..be1d222 100644 --- a/embedded-workshop-book/src/installation.md +++ b/embedded-workshop-book/src/installation.md @@ -147,6 +147,10 @@ Installed package `cargo-binutils v0.3.0` (..) $ cargo install cargo-bloat (..) Installed package `cargo-bloat v0.9.3` (..) + +$ cargo install probe-run +(..) +Installed package `probe-run v0.1.0` (..) ``` ## Python diff --git a/embedded-workshop-book/src/running-from-vsc.md b/embedded-workshop-book/src/running-from-vsc.md index 58d0151..8bb3b0f 100644 --- a/embedded-workshop-book/src/running-from-vsc.md +++ b/embedded-workshop-book/src/running-from-vsc.md @@ -1,6 +1,6 @@ # Running the Program from VS Code -Both `cargo-embed` and `cargo-flash` are tools based on the `probe-rs` library. This library exposes an API to communicate with the J-Link and perform all the operations exposed by the JTAG protocol. For this workshop we have developed a small Cargo runner that uses the `probe-rs` library to streamline the process of running a program and printing logs, like `cargo-embed`, while also having better integration into VS code. +Both `cargo-embed` and `cargo-flash` are tools based on the `probe-rs` library. This library exposes an API to communicate with the J-Link and perform all the operations exposed by the JTAG protocol. We have developed a small Cargo runner called [probe-run](https://github.com/knurling-rs/probe-run) that uses the `probe-rs` library to streamline the process of running a program and printing logs, like `cargo-embed`, while also having better integration into VS code. We'll be using it in this workshop, and you can utilize it in your future projects too. ✅ Open the `src/bin/hello.rs` file and click the "Run" button that's hovering over the `main` function. @@ -21,6 +21,6 @@ stack backtrace: 3: 0x00001ba2 - Reset ``` -`cargo run` will compile the application and then invoke the `dk-run` tool with its argument set to the path of the output ELF file. +`cargo run` will compile the application and then invoke `probe-run` with its argument set to the path of the output ELF file. -Unlike `cargo-embed`, `dk-run` will terminate when the program reaches a breakpoint (`asm::bkpt`) that halts the device. Before exiting `dk-run` will print a stack backtrace of the program starting from the breakpoint. This can be used to write small test programs that are meant to perform some work and then terminate. +Unlike `cargo-embed`, `probe-run` will terminate when the program reaches a breakpoint (`asm::bkpt`) that halts the device. Before exiting, `probe-run` will print a stack backtrace of the program starting from the breakpoint. This can be used to write small test programs that are meant to perform some work and then terminate. diff --git a/embedded-workshop-book/src/tooling-check.md b/embedded-workshop-book/src/tooling-check.md index c891d29..79810a8 100644 --- a/embedded-workshop-book/src/tooling-check.md +++ b/embedded-workshop-book/src/tooling-check.md @@ -28,7 +28,6 @@ nrfutil version 6.1.0 From the `tools` folder run these commands *from different terminals so they'll run in parallel*: -- `cargo install --path dk-run` - `cargo install --path usb-list` - `cargo install --path dongle-flash` - `cargo install --path serial-term` @@ -40,7 +39,6 @@ Leave the processes running in the background. From the `tools` folder run these commands *from different terminals so they'll run in parallel*: -- `cargo install --path dk-run` - `cargo install --path usb-list` Leave the processes running in the background. diff --git a/embedded-workshop-book/src/troubleshoot-cargo-run-error.md b/embedded-workshop-book/src/troubleshoot-cargo-run-error.md index ea0fe4b..43f8417 100644 --- a/embedded-workshop-book/src/troubleshoot-cargo-run-error.md +++ b/embedded-workshop-book/src/troubleshoot-cargo-run-error.md @@ -7,7 +7,7 @@ You may get one of these errors: ``` console $ cargo run --bin usb-4 -Running `dk-run target/thumbv7em-none-eabi/debug/usb-4` +Running `probe-run target/thumbv7em-none-eabi/debug/usb-4` Error: An error specific to a probe type occured: USB error while taking control over USB device: Access denied (insufficient permissions) Caused by: @@ -16,7 +16,7 @@ Caused by: ``` console $ cargo run --bin usb-4 -Running `dk-run target/thumbv7em-none-eabi/debug/usb-4` +Running `probe-run target/thumbv7em-none-eabi/debug/usb-4` Error: An error specific to a probe type occured: USB error while taking control over USB device: Resource busy Caused by: diff --git a/tools/Cargo.lock b/tools/Cargo.lock index 0ee2f71..b451f6d 100644 --- a/tools/Cargo.lock +++ b/tools/Cargo.lock @@ -42,41 +42,6 @@ version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "base64" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d1ccbaf7d9ec9537465a97bf19edc1a4e158ecb49fc16178202238c569cc42" - [[package]] name = "bit-set" version = "0.5.2" @@ -92,24 +57,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3" -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - [[package]] name = "cc" version = "1.0.54" @@ -155,33 +108,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "derivative" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" -dependencies = [ - "proc-macro2", - "quote 1.0.7", - "syn 1.0.31", -] - -[[package]] -name = "dk-run" -version = "0.0.0" -dependencies = [ - "anyhow", - "arrayref", - "ctrlc", - "env_logger", - "gimli 0.21.0", - "log", - "probe-rs", - "probe-rs-rtt", - "rustc-demangle", - "xmas-elf", -] - [[package]] name = "dongle-flash" version = "0.0.0" @@ -193,42 +119,6 @@ dependencies = [ "xmas-elf", ] -[[package]] -name = "dtoa" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" - -[[package]] -name = "enum-primitive-derive" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b90e520ec62c1864c8c78d637acbfe8baf5f63240f2fb8165b8325c07812dd" -dependencies = [ - "num-traits 0.1.43", - "quote 0.3.15", - "syn 0.11.11", -] - -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - [[package]] name = "filetime" version = "0.2.10" @@ -241,18 +131,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "flate2" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" -dependencies = [ - "cfg-if", - "crc32fast", - "libc", - "miniz_oxide", -] - [[package]] name = "getrandom" version = "0.1.14" @@ -264,51 +142,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gimli" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dd6190aad0f05ddbbf3245c54ed14ca4aa6dd32f22312b70d8f168c3e3e633" -dependencies = [ - "arrayvec", - "byteorder", - "fallible-iterator", - "indexmap", - "smallvec", - "stable_deref_trait", -] - -[[package]] -name = "gimli" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" -dependencies = [ - "fallible-iterator", - "indexmap", - "stable_deref_trait", -] - -[[package]] -name = "goblin" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" -dependencies = [ - "log", - "plain", - "scroll", -] - -[[package]] -name = "hermit-abi" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" -dependencies = [ - "libc", -] - [[package]] name = "hidapi" version = "1.2.2" @@ -320,51 +153,12 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - [[package]] name = "ihex" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9394ec1fbc3afbdfb357ba267a7fffdc39f6e3d8ba88c0af6d9476e6d3c889d5" -[[package]] -name = "indexmap" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe" -dependencies = [ - "autocfg", -] - -[[package]] -name = "jaylink" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7303af61073160fc72f7f56ae5bf39234ea85387441101229224a8d64b2057b" -dependencies = [ - "bitflags", - "byteorder", - "log", - "rusb", -] - -[[package]] -name = "jep106" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f57cd08ee4fbc8043949150a59e34ea5f2afeb172f875db9607689e48600c653" -dependencies = [ - "serde", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -423,21 +217,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linked-hash-map" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" - -[[package]] -name = "log" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -dependencies = [ - "cfg-if", -] - [[package]] name = "mach" version = "0.1.2" @@ -462,15 +241,6 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - [[package]] name = "nix" version = "0.14.1" @@ -497,35 +267,6 @@ dependencies = [ "void", ] -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.11", -] - -[[package]] -name = "num-traits" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5666bbb90bc4d1e5bdcb26c0afda1822d25928341e9384ab187a9b37ab69e36" -dependencies = [ - "flate2", - "target-lexicon", - "wasmparser", -] - [[package]] name = "pids" version = "0.0.0" @@ -536,101 +277,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "ppv-lite86" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" -[[package]] -name = "probe-rs" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4508248f016eb7f7a50751b9c3e8f9e25add169feac006aef5115dbb5e42be" -dependencies = [ - "base64", - "bitfield", - "derivative", - "enum-primitive-derive", - "gimli 0.20.0", - "goblin", - "hidapi", - "ihex", - "jaylink", - "jep106", - "lazy_static", - "log", - "num-traits 0.2.11", - "object", - "probe-rs-t2rust", - "rusb", - "scroll", - "serde", - "serde_yaml", - "svg", - "thiserror", -] - -[[package]] -name = "probe-rs-rtt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823c43c9553ebea43672d38c4756fe360305225f2b649b0e0bf28319354ca01d" -dependencies = [ - "probe-rs", - "scroll", - "thiserror", -] - -[[package]] -name = "probe-rs-t2rust" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0e2d177a33e8c8a46d98767fb01877f1c466826b9c25f88749f35140d0aae0" -dependencies = [ - "base64", - "proc-macro2", - "quote 1.0.7", - "scroll", - "serde_yaml", -] - -[[package]] -name = "proc-macro2" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" -dependencies = [ - "unicode-xid 0.2.0", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - [[package]] name = "rand" version = "0.7.3" @@ -722,64 +374,6 @@ dependencies = [ "libusb1-sys", ] -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" - -[[package]] -name = "scroll" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" -dependencies = [ - "proc-macro2", - "quote 1.0.7", - "syn 1.0.31", -] - -[[package]] -name = "serde" -version = "1.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" -dependencies = [ - "proc-macro2", - "quote 1.0.7", - "syn 1.0.31", -] - -[[package]] -name = "serde_yaml" -version = "0.8.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5" -dependencies = [ - "dtoa", - "linked-hash-map", - "serde", - "yaml-rust", -] - [[package]] name = "serial-term" version = "0.0.0" @@ -807,55 +401,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "smallvec" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" - -[[package]] -name = "stable_deref_trait" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" - -[[package]] -name = "svg" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3685c82a045a6af0c488f0550b0f52b4c77d2a52b0ca8aba719f9d268fa96965" - -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -dependencies = [ - "quote 0.3.15", - "synom", - "unicode-xid 0.0.4", -] - -[[package]] -name = "syn" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" -dependencies = [ - "proc-macro2", - "quote 1.0.7", - "unicode-xid 0.2.0", -] - -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -dependencies = [ - "unicode-xid 0.0.4", -] - [[package]] name = "take_mut" version = "0.2.2" @@ -874,12 +419,6 @@ dependencies = [ "xattr", ] -[[package]] -name = "target-lexicon" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" - [[package]] name = "tempfile" version = "3.1.0" @@ -894,35 +433,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "termcolor" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" -dependencies = [ - "proc-macro2", - "quote 1.0.7", - "syn 1.0.31", -] - [[package]] name = "thread_local" version = "1.0.1" @@ -932,18 +442,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" - [[package]] name = "usb-list" version = "0.0.0" @@ -971,12 +469,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasmparser" -version = "0.51.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" - [[package]] name = "winapi" version = "0.3.8" @@ -993,15 +485,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1026,15 +509,6 @@ dependencies = [ "zero", ] -[[package]] -name = "yaml-rust" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "zero" version = "0.1.2" diff --git a/tools/Cargo.toml b/tools/Cargo.toml index cdf9600..031aa66 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ "change-channel", - "dk-run", "dongle-flash", "serial-term", "usb-list", diff --git a/tools/dk-run/Cargo.toml b/tools/dk-run/Cargo.toml deleted file mode 100644 index ce4b502..0000000 --- a/tools/dk-run/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["Jorge Aparicio "] -edition = "2018" -license = "MIT OR Apache-2.0" -name = "dk-run" -version = "0.0.0" - -[dependencies] -anyhow = "1.0.31" -arrayref = "0.3.6" -ctrlc = "3.1.4" -env_logger = "0.7.1" -gimli = "0.21.0" -log = "0.4.8" -probe-rs = "0.6.2" -probe-rs-rtt = "0.1.0" -rustc-demangle = "0.1.16" -xmas-elf = "0.7.0" \ No newline at end of file diff --git a/tools/dk-run/src/main.rs b/tools/dk-run/src/main.rs deleted file mode 100644 index bea155d..0000000 --- a/tools/dk-run/src/main.rs +++ /dev/null @@ -1,531 +0,0 @@ -use core::{ - cmp, - convert::{TryFrom, TryInto}, - mem, - ops::Range, - sync::atomic::{AtomicBool, Ordering}, -}; -use std::{ - collections::{btree_map, BTreeMap}, - env, fs, - io::{self, Write as _}, - path::Path, - process, - rc::Rc, -}; - -use anyhow::{anyhow, bail}; -use arrayref::array_ref; -use gimli::{ - read::{CfaRule, DebugFrame, UnwindSection}, - BaseAddresses, EndianSlice, LittleEndian, RegisterRule, UninitializedUnwindContext, -}; -use probe_rs::{ - flashing::{self, Format}, - Core, CoreRegisterAddress, Probe, -}; -use probe_rs_rtt::{Rtt, ScanRegion}; -use xmas_elf::{program::Type, sections::SectionData, symbol_table::Entry, ElfFile}; - -fn main() -> Result<(), anyhow::Error> { - notmain().map(|code| process::exit(code)) -} - -fn notmain() -> Result { - env_logger::init(); - - let args = env::args().skip(1 /* program name */).collect::>(); - - if args.len() != 1 { - bail!("expected exactly one argument") - } - - let path = &args[0]; - - let bytes = fs::read(path)?; - let elf = ElfFile::new(&bytes).map_err(|s| anyhow!("{}", s))?; - - // sections used in cortex-m-rt - // NOTE we won't load `.uninit` so it is not included here - // NOTE we don't load `.bss` because the app (cortex-m-rt) will zero it - let candidates = [".vector_table", ".text", ".rodata"]; - - let text = elf - .section_iter() - .zip(0..) - .filter_map(|(sect, shndx)| { - if sect.get_name(&elf) == Ok(".text") { - Some(shndx) - } else { - None - } - }) - .next(); - - let mut debug_frame = None; - let mut range_names = None; - let mut rtt_addr = None; - let mut sections = vec![]; - let mut dotdata = None; - let mut registers = None; - for sect in elf.section_iter() { - if let Ok(name) = sect.get_name(&elf) { - if name == ".debug_frame" { - debug_frame = Some(sect.raw_data(&elf)); - continue; - } - - if name == ".symtab" { - if let Ok(symtab) = sect.get_data(&elf) { - let (rn, rtt_addr_) = range_names_from(&elf, symtab, text)?; - range_names = Some(rn); - rtt_addr = rtt_addr_; - } - } - - let size = sect.size(); - // skip empty sections - if candidates.contains(&name) && size != 0 { - let start = sect.address(); - if size % 4 != 0 || start % 4 != 0 { - // we could support unaligned sections but let's not do that now - bail!("section `{}` is not 4-byte aligned", name); - } - - let start = start.try_into()?; - let data = sect - .raw_data(&elf) - .chunks_exact(4) - .map(|chunk| u32::from_le_bytes(*array_ref!(chunk, 0, 4))) - .collect::>(); - - if name == ".vector_table" { - registers = Some(Registers { - vtor: start, - // Initial stack pointer - sp: data[0], - // Reset handler - pc: data[1], - }); - } else if name == ".data" { - // don't put .data in the `sections` variable; it is specially handled - dotdata = Some(Data { - phys: start, - virt: start, - data, - }); - continue; - } - - sections.push(Section { start, data }); - } - } - } - - if let Some(data) = dotdata.as_mut() { - // patch up `.data` physical address - let mut patched = false; - for ph in elf.program_iter() { - if ph.get_type() == Ok(Type::Load) { - if u32::try_from(ph.virtual_addr())? == data.virt { - patched = true; - data.phys = ph.physical_addr().try_into()?; - break; - } - } - } - - if !patched { - bail!("couldn't extract `.data` physical address from the ELF"); - } - } - - let registers = registers.ok_or_else(|| anyhow!("`.vector_table` section is missing"))?; - - let probes = Probe::list_all(); - if probes.is_empty() { - // TODO improve error message - bail!("nRF52840 Development Kit appears to not be connected") - } - log::debug!("found {} probes", probes.len()); - let probe = probes[0].open()?; - log::info!("opened probe"); - let sess = probe.attach("nRF52840_xxAA")?; - log::info!("started session"); - let core = sess.attach_to_core(0)?; - log::info!("attached to core"); - - core.reset_and_halt()?; - log::info!("reset and halted the core"); - - eprintln!("flashing program .."); - - // load program into memory - for section in §ions { - core.write_32(section.start, §ion.data)?; - } - if let Some(section) = dotdata { - core.write_32(section.phys, §ion.data)?; - } - - // adjust registers - // this is the link register reset value; it indicates the end of the call stack - if registers.vtor >= 0x2000_0000 { - // program lives in RAM - core.write_core_reg(LR, LR_END)?; - core.write_core_reg(SP, registers.sp)?; - core.write_core_reg(PC, registers.pc)?; - core.write_word_32(VTOR, registers.vtor)?; - - log::info!("loaded program into RAM"); - - eprintln!("DONE"); - - core.run()?; - } else { - // XXX the device may have already loaded SP and PC at this point in this case? - - // program lives in Flash - flashing::download_file(&sess, Path::new(path), Format::Elf)?; - - log::info!("flashed program"); - - eprintln!("DONE"); - - core.reset()?; - } - - eprintln!("resetting device"); - - let core = Rc::new(core); - let rtt_addr_res = rtt_addr.ok_or_else(|| anyhow!("RTT control block not available"))?; - let mut rtt_res: Result = - Err(probe_rs_rtt::Error::ControlBlockNotFound); - const NUM_RETRIES: usize = 5; // picked at random, increase if necessary - - for try_index in 0..=NUM_RETRIES { - rtt_res = Rtt::attach_region(core.clone(), &sess, &ScanRegion::Exact(rtt_addr_res)); - match rtt_res { - Ok(_) => { - log::info!("Successfully attached RTT"); - break; - } - Err(probe_rs_rtt::Error::ControlBlockNotFound) => { - if try_index < NUM_RETRIES { - log::info!("Could not attach because the target's RTT control block isn't initialized (yet). retrying"); - } else { - log::info!("Max number of RTT attach retries exceeded. Did you call dk::init() first thing in your program?"); - return Err(anyhow!(probe_rs_rtt::Error::ControlBlockNotFound)); - } - } - Err(e) => { - return Err(anyhow!(e)); - } - } - } - - let channel = rtt_res - .expect("unreachable") // this block is only executed when rtt was successfully attached before - .up_channels() - .take(0) - .ok_or_else(|| anyhow!("RTT up channel 0 not found"))?; - - static CONTINUE: AtomicBool = AtomicBool::new(true); - - ctrlc::set_handler(|| { - CONTINUE.store(false, Ordering::Relaxed); - })?; - - // wait for breakpoint - let stdout = io::stdout(); - let mut stdout = stdout.lock(); - let mut read_buf = [0; 1024]; - let mut was_halted = false; - while CONTINUE.load(Ordering::Relaxed) { - let n = channel.read(&mut read_buf)?; - - if n != 0 { - stdout.write_all(&read_buf[..n])?; - } - - let is_halted = core.core_halted()?; - - if is_halted && was_halted { - break; - } - was_halted = is_halted; - } - drop(stdout); - - // Ctrl-C was pressed; stop the microcontroller - if !CONTINUE.load(Ordering::Relaxed) { - core.halt()?; - } - - let pc = core.read_core_reg(PC)?; - - let debug_frame = debug_frame.ok_or_else(|| anyhow!("`.debug_frame` section not found"))?; - - let range_names = range_names.ok_or_else(|| anyhow!("`.symtab` section not found"))?; - - // print backtrace - backtrace(&core, pc, debug_frame, &range_names)?; - - core.reset_and_halt()?; - - Ok(0) -} - -fn backtrace( - core: &Core, - mut pc: u32, - debug_frame: &[u8], - range_names: &RangeNames, -) -> Result<(), anyhow::Error> { - fn gimli2probe(reg: &gimli::Register) -> CoreRegisterAddress { - CoreRegisterAddress(reg.0) - } - - struct Registers<'c> { - cache: BTreeMap, - core: &'c Core, - } - - impl<'c> Registers<'c> { - fn new(lr: u32, sp: u32, core: &'c Core) -> Self { - let mut cache = BTreeMap::new(); - cache.insert(LR.0, lr); - cache.insert(SP.0, sp); - Self { cache, core } - } - - fn get(&mut self, reg: CoreRegisterAddress) -> Result { - Ok(match self.cache.entry(reg.0) { - btree_map::Entry::Occupied(entry) => *entry.get(), - btree_map::Entry::Vacant(entry) => *entry.insert(self.core.read_core_reg(reg)?), - }) - } - - fn insert(&mut self, reg: CoreRegisterAddress, val: u32) { - self.cache.insert(reg.0, val); - } - - fn update_cfa( - &mut self, - rule: &CfaRule>, - ) -> Result { - match rule { - CfaRule::RegisterAndOffset { register, offset } => { - let cfa = (i64::from(self.get(gimli2probe(register))?) + offset) as u32; - let ok = self.cache.get(&SP.0) != Some(&cfa); - self.cache.insert(SP.0, cfa); - Ok(ok) - } - - // NOTE not encountered in practice so far - CfaRule::Expression(_) => todo!("CfaRule::Expression"), - } - } - - fn update( - &mut self, - reg: &gimli::Register, - rule: &RegisterRule>, - ) -> Result<(), anyhow::Error> { - match rule { - RegisterRule::Undefined => unreachable!(), - - RegisterRule::Offset(offset) => { - let cfa = self.get(SP)?; - let addr = (i64::from(cfa) + offset) as u32; - self.cache.insert(reg.0, self.core.read_word_32(addr)?); - } - - _ => unimplemented!(), - } - - Ok(()) - } - } - - let mut debug_frame = DebugFrame::new(debug_frame, LittleEndian); - // 32-bit ARM -- this defaults to the host's address size which is likely going to be 8 - debug_frame.set_address_size(mem::size_of::() as u8); - - let sp = core.read_core_reg(SP)?; - let lr = core.read_core_reg(LR)?; - - // statically linked binary -- there are no relative addresses - let bases = &BaseAddresses::default(); - let ctx = &mut UninitializedUnwindContext::new(); - - let mut frame = 0; - let mut registers = Registers::new(lr, sp, core); - println!("stack backtrace:"); - loop { - println!( - "{:>4}: {:#010x} - {}", - frame, - pc, - range_names - .binary_search_by(|rn| if rn.0.contains(&pc) { - cmp::Ordering::Equal - } else if pc < rn.0.start { - cmp::Ordering::Greater - } else { - cmp::Ordering::Less - }) - .map(|idx| &*range_names[idx].1) - .unwrap_or("") - ); - - let fde = debug_frame.fde_for_address(bases, pc.into(), DebugFrame::cie_from_offset)?; - let uwt_row = fde.unwind_info_for_address(&debug_frame, bases, ctx, pc.into())?; - - let cfa_changed = registers.update_cfa(uwt_row.cfa())?; - - for (reg, rule) in uwt_row.registers() { - registers.update(reg, rule)?; - } - - let lr = registers.get(LR)?; - if lr == LR_END { - break; - } - - if !cfa_changed && lr == pc { - println!("error: the stack appears to be corrupted beyond this point"); - return Ok(()); - } - - if lr > 0xffff_fff0 { - println!(" "); - - let sp = registers.get(SP)?; - let stacked = Stacked::read(core, sp)?; - - registers.insert(LR, stacked.lr); - // adjust the stack pointer for stacked registers - registers.insert(SP, sp + mem::size_of::() as u32); - pc = stacked.pc; - } else { - if lr & 1 == 0 { - bail!("bug? LR ({:#010x}) didn't have the Thumb bit set", lr) - } - pc = lr & !1; - } - - frame += 1; - } - - Ok(()) -} - -/// Registers stacked on exception entry -// XXX assumes that the floating pointer registers are NOT stacked (which may not be the case for HF -// targets) -#[derive(Debug)] -struct Stacked { - r0: u32, - r1: u32, - r2: u32, - r3: u32, - r12: u32, - lr: u32, - pc: u32, - xpsr: u32, -} - -impl Stacked { - fn read(core: &Core, sp: u32) -> Result { - let mut registers = [0; 8]; - core.read_32(sp, &mut registers)?; - - Ok(Stacked { - r0: registers[0], - r1: registers[1], - r2: registers[2], - r3: registers[3], - r12: registers[4], - lr: registers[5], - pc: registers[6], - xpsr: registers[7], - }) - } -} -// FIXME this might already exist in the DWARF data; we should just use that -/// Map from PC ranges to demangled Rust names -type RangeNames = Vec<(Range, String)>; -type Shndx = u16; - -fn range_names_from( - elf: &ElfFile, - sd: SectionData, - text: Option, -) -> Result<(RangeNames, Option), anyhow::Error> { - let mut range_names = vec![]; - let mut rtt = None; - if let SectionData::SymbolTable32(entries) = sd { - for entry in entries { - if let Ok(name) = entry.get_name(elf) { - if name == "_SEGGER_RTT" { - rtt = Some(entry.value() as u32); - } - - if Some(entry.shndx()) == text && entry.size() != 0 { - let mut name = rustc_demangle::demangle(name).to_string(); - // clear the thumb bit - let start = entry.value() as u32 & !1; - - // strip the hash (e.g. `::hd881d91ced85c2b0`) - let hash_len = "::hd881d91ced85c2b0".len(); - if let Some(pos) = name.len().checked_sub(hash_len) { - let maybe_hash = &name[pos..]; - if maybe_hash.starts_with("::h") { - // FIXME avoid this allocation - name = name[..pos].to_string(); - } - } - - range_names.push((start..start + entry.size() as u32, name)); - } - } - } - } - - range_names.sort_unstable_by(|a, b| a.0.start.cmp(&b.0.start)); - - Ok((range_names, rtt)) -} - -const LR: CoreRegisterAddress = CoreRegisterAddress(14); -const PC: CoreRegisterAddress = CoreRegisterAddress(15); -const SP: CoreRegisterAddress = CoreRegisterAddress(13); -const VTOR: u32 = 0xE000_ED08; - -const LR_END: u32 = 0xFFFF_FFFF; - -/// ELF section to be loaded onto the target -#[derive(Debug)] -struct Section { - start: u32, - data: Vec, -} - -/// The .data section has a physical address different that its virtual address; we want to load the -/// data into the physical address (which would normally be in FLASH) so that cortex-m-rt doesn't -/// corrupt the variables in .data during initialization -- it would be best if we could disable -/// cortex-m-rt's `init_data` call but there's no such feature -#[derive(Debug)] -struct Data { - phys: u32, - virt: u32, - data: Vec, -} - -/// Registers to update before running the program -struct Registers { - sp: u32, - pc: u32, - vtor: u32, -}