summaryrefslogtreecommitdiff
path: root/examples/boot/bootloader
diff options
context:
space:
mode:
authorUlf Lilleengen <ulf.lilleengen@gmail.com>2022-06-24 19:56:15 +0200
committerUlf Lilleengen <ulf.lilleengen@gmail.com>2022-06-24 19:56:15 +0200
commit776be79f7bb10b09e795e2ea93bb795a653c9b4c (patch)
tree269046d330ee503c84049bb8fc47baf0297ecb80 /examples/boot/bootloader
parent84628d36cf743193cbf0e7d47ef1cfa9fb590890 (diff)
downloadembassy-776be79f7bb10b09e795e2ea93bb795a653c9b4c.zip
Move bootloader main to examples
This should remove some confusion around embassy-boot-* being a library vs. a binary. The binary is now an example bootloader instead.
Diffstat (limited to 'examples/boot/bootloader')
-rw-r--r--examples/boot/bootloader/nrf/.cargo/config.toml20
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml58
-rw-r--r--examples/boot/bootloader/nrf/README.md11
-rw-r--r--examples/boot/bootloader/nrf/build.rs37
-rw-r--r--examples/boot/bootloader/nrf/memory-bm.x18
-rw-r--r--examples/boot/bootloader/nrf/memory-s140.x31
-rw-r--r--examples/boot/bootloader/nrf/memory.x18
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs48
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml57
-rw-r--r--examples/boot/bootloader/stm32/README.md11
-rw-r--r--examples/boot/bootloader/stm32/build.rs32
-rw-r--r--examples/boot/bootloader/stm32/memory.x18
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs46
13 files changed, 405 insertions, 0 deletions
diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml
new file mode 100644
index 00000000..1060800a
--- /dev/null
+++ b/examples/boot/bootloader/nrf/.cargo/config.toml
@@ -0,0 +1,20 @@
+[unstable]
+build-std = ["core"]
+build-std-features = ["panic_immediate_abort"]
+
+[target.'cfg(all(target_arch = "arm", target_os = "none"))']
+#runner = "./fruitrunner"
+runner = "probe-run --chip nrf52840_xxAA"
+
+rustflags = [
+ # Code-size optimizations.
+ "-Z", "trap-unreachable=no",
+ #"-C", "no-vectorize-loops",
+ "-C", "force-frame-pointers=yes",
+]
+
+[build]
+target = "thumbv7em-none-eabi"
+
+[env]
+DEFMT_LOG = "trace"
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
new file mode 100644
index 00000000..8eb98623
--- /dev/null
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -0,0 +1,58 @@
+[package]
+edition = "2021"
+name = "nrf-bootloader-example"
+version = "0.1.0"
+description = "Bootloader for nRF chips"
+
+[dependencies]
+defmt = { version = "0.3", optional = true }
+defmt-rtt = { version = "0.3", optional = true }
+
+embassy = { path = "../../../../embassy", default-features = false }
+embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] }
+embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false }
+cortex-m = { version = "0.7" }
+cortex-m-rt = { version = "0.7" }
+cfg-if = "1.0.0"
+
+[features]
+defmt = [
+ "dep:defmt",
+ "embassy-boot-nrf/defmt",
+ "embassy-nrf/defmt",
+]
+softdevice = [
+ "embassy-boot-nrf/softdevice",
+]
+debug = ["defmt-rtt"]
+
+[profile.dev]
+debug = 2
+debug-assertions = true
+incremental = false
+opt-level = 'z'
+overflow-checks = true
+
+[profile.release]
+codegen-units = 1
+debug = 2
+debug-assertions = false
+incremental = false
+lto = 'fat'
+opt-level = 'z'
+overflow-checks = false
+
+# do not optimize proc-macro crates = faster builds from scratch
+[profile.dev.build-override]
+codegen-units = 8
+debug = false
+debug-assertions = false
+opt-level = 0
+overflow-checks = false
+
+[profile.release.build-override]
+codegen-units = 8
+debug = false
+debug-assertions = false
+opt-level = 0
+overflow-checks = false
diff --git a/examples/boot/bootloader/nrf/README.md b/examples/boot/bootloader/nrf/README.md
new file mode 100644
index 00000000..23497a03
--- /dev/null
+++ b/examples/boot/bootloader/nrf/README.md
@@ -0,0 +1,11 @@
+# Bootloader for nRF
+
+The bootloader uses `embassy-boot` to interact with the flash.
+
+# Usage
+
+Flash the bootloader
+
+```
+cargo flash --features embassy-nrf/nrf52832 --release --chip nRF52832_xxAA
+```
diff --git a/examples/boot/bootloader/nrf/build.rs b/examples/boot/bootloader/nrf/build.rs
new file mode 100644
index 00000000..e1da6932
--- /dev/null
+++ b/examples/boot/bootloader/nrf/build.rs
@@ -0,0 +1,37 @@
+//! This build script copies the `memory.x` file from the crate root into
+//! a directory where the linker can always find it at build time.
+//! For many projects this is optional, as the linker always searches the
+//! project root directory -- wherever `Cargo.toml` is. However, if you
+//! are using a workspace or have a more complicated build setup, this
+//! build script becomes required. Additionally, by requesting that
+//! Cargo re-run the build script whenever `memory.x` is changed,
+//! updating `memory.x` ensures a rebuild of the application with the
+//! new memory settings.
+
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+ // Put `memory.x` in our output directory and ensure it's
+ // on the linker search path.
+ let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ File::create(out.join("memory.x"))
+ .unwrap()
+ .write_all(include_bytes!("memory.x"))
+ .unwrap();
+ println!("cargo:rustc-link-search={}", out.display());
+
+ // By default, Cargo will re-run a build script whenever
+ // any file in the project changes. By specifying `memory.x`
+ // here, we ensure the build script is only re-run when
+ // `memory.x` is changed.
+ println!("cargo:rerun-if-changed=memory.x");
+
+ println!("cargo:rustc-link-arg-bins=--nmagic");
+ println!("cargo:rustc-link-arg-bins=-Tlink.x");
+ if env::var("CARGO_FEATURE_DEFMT").is_ok() {
+ println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
+ }
+}
diff --git a/examples/boot/bootloader/nrf/memory-bm.x b/examples/boot/bootloader/nrf/memory-bm.x
new file mode 100644
index 00000000..8a32b905
--- /dev/null
+++ b/examples/boot/bootloader/nrf/memory-bm.x
@@ -0,0 +1,18 @@
+MEMORY
+{
+ /* NOTE 1 K = 1 KiBi = 1024 bytes */
+ FLASH : ORIGIN = 0x00000000, LENGTH = 24K
+ BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
+ ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
+ DFU : ORIGIN = 0x00017000, LENGTH = 68K
+ RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
+}
+
+__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
+__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
+
+__bootloader_active_start = ORIGIN(ACTIVE);
+__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);
+
+__bootloader_dfu_start = ORIGIN(DFU);
+__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
diff --git a/examples/boot/bootloader/nrf/memory-s140.x b/examples/boot/bootloader/nrf/memory-s140.x
new file mode 100644
index 00000000..105db997
--- /dev/null
+++ b/examples/boot/bootloader/nrf/memory-s140.x
@@ -0,0 +1,31 @@
+MEMORY
+{
+ /* NOTE 1 K = 1 KiBi = 1024 bytes */
+ MBR : ORIGIN = 0x00000000, LENGTH = 4K
+ SOFTDEVICE : ORIGIN = 0x00001000, LENGTH = 155648
+ ACTIVE : ORIGIN = 0x00027000, LENGTH = 425984
+ DFU : ORIGIN = 0x0008F000, LENGTH = 430080
+ FLASH : ORIGIN = 0x000f9000, LENGTH = 24K
+ BOOTLOADER_STATE : ORIGIN = 0x000ff000, LENGTH = 4K
+ RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 0x2fff8
+ uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
+}
+
+__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
+__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
+
+__bootloader_active_start = ORIGIN(ACTIVE);
+__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);
+
+__bootloader_dfu_start = ORIGIN(DFU);
+__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
+
+__bootloader_start = ORIGIN(FLASH);
+
+SECTIONS
+{
+ .uicr_bootloader_start_address :
+ {
+ LONG(__bootloader_start)
+ } > uicr_bootloader_start_address
+}
diff --git a/examples/boot/bootloader/nrf/memory.x b/examples/boot/bootloader/nrf/memory.x
new file mode 100644
index 00000000..8a32b905
--- /dev/null
+++ b/examples/boot/bootloader/nrf/memory.x
@@ -0,0 +1,18 @@
+MEMORY
+{
+ /* NOTE 1 K = 1 KiBi = 1024 bytes */
+ FLASH : ORIGIN = 0x00000000, LENGTH = 24K
+ BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
+ ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
+ DFU : ORIGIN = 0x00017000, LENGTH = 68K
+ RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
+}
+
+__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
+__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
+
+__bootloader_active_start = ORIGIN(ACTIVE);
+__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);
+
+__bootloader_dfu_start = ORIGIN(DFU);
+__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
new file mode 100644
index 00000000..bc7e0755
--- /dev/null
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -0,0 +1,48 @@
+#![no_std]
+#![no_main]
+
+use cortex_m_rt::{entry, exception};
+#[cfg(feature = "defmt")]
+use defmt_rtt as _;
+use embassy_boot_nrf::*;
+use embassy_nrf::nvmc::Nvmc;
+
+#[entry]
+fn main() -> ! {
+ let p = embassy_nrf::init(Default::default());
+
+ // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
+ // as it prevents a hard fault when accessing flash 'too early' after boot.
+ /*
+ for i in 0..10000000 {
+ cortex_m::asm::nop();
+ }
+ */
+
+ let mut bl = BootLoader::default();
+ let start = bl.prepare(&mut SingleFlashProvider::new(&mut WatchdogFlash::start(
+ Nvmc::new(p.NVMC),
+ p.WDT,
+ 5,
+ )));
+ unsafe { bl.load(start) }
+}
+
+#[no_mangle]
+#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
+unsafe extern "C" fn HardFault() {
+ cortex_m::peripheral::SCB::sys_reset();
+}
+
+#[exception]
+unsafe fn DefaultHandler(_: i16) -> ! {
+ const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
+ let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
+
+ panic!("DefaultHandler #{:?}", irqn);
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ cortex_m::asm::udf();
+}
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
new file mode 100644
index 00000000..b99a8fbc
--- /dev/null
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -0,0 +1,57 @@
+[package]
+edition = "2021"
+name = "stm32-bootloader-example"
+version = "0.1.0"
+description = "Example bootloader for STM32 chips"
+
+[dependencies]
+defmt = { version = "0.3", optional = true }
+defmt-rtt = { version = "0.3", optional = true }
+
+embassy = { path = "../../../../embassy", default-features = false }
+embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] }
+embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false }
+cortex-m = { version = "0.7" }
+cortex-m-rt = { version = "0.7" }
+embedded-storage = "0.3.0"
+embedded-storage-async = "0.3.0"
+cfg-if = "1.0.0"
+
+[features]
+defmt = [
+ "dep:defmt",
+ "embassy-boot-stm32/defmt",
+ "embassy-stm32/defmt",
+]
+debug = ["defmt-rtt"]
+
+[profile.dev]
+debug = 2
+debug-assertions = true
+incremental = false
+opt-level = 'z'
+overflow-checks = true
+
+[profile.release]
+codegen-units = 1
+debug = 2
+debug-assertions = false
+incremental = false
+lto = 'fat'
+opt-level = 'z'
+overflow-checks = false
+
+# do not optimize proc-macro crates = faster builds from scratch
+[profile.dev.build-override]
+codegen-units = 8
+debug = false
+debug-assertions = false
+opt-level = 0
+overflow-checks = false
+
+[profile.release.build-override]
+codegen-units = 8
+debug = false
+debug-assertions = false
+opt-level = 0
+overflow-checks = false
diff --git a/examples/boot/bootloader/stm32/README.md b/examples/boot/bootloader/stm32/README.md
new file mode 100644
index 00000000..a82b730b
--- /dev/null
+++ b/examples/boot/bootloader/stm32/README.md
@@ -0,0 +1,11 @@
+# Bootloader for STM32
+
+The bootloader uses `embassy-boot` to interact with the flash.
+
+# Usage
+
+Flash the bootloader
+
+```
+cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx
+```
diff --git a/examples/boot/bootloader/stm32/build.rs b/examples/boot/bootloader/stm32/build.rs
new file mode 100644
index 00000000..3997702f
--- /dev/null
+++ b/examples/boot/bootloader/stm32/build.rs
@@ -0,0 +1,32 @@
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+ // Put `memory.x` in our output directory and ensure it's
+ // on the linker search path.
+ let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ File::create(out.join("memory.x"))
+ .unwrap()
+ .write_all(include_bytes!("memory.x"))
+ .unwrap();
+ println!("cargo:rustc-link-search={}", out.display());
+
+ // By default, Cargo will re-run a build script whenever
+ // any file in the project changes. By specifying `memory.x`
+ // here, we ensure the build script is only re-run when
+ // `memory.x` is changed.
+ println!("cargo:rerun-if-changed=memory.x");
+
+ println!("cargo:rustc-link-arg-bins=--nmagic");
+ println!("cargo:rustc-link-arg-bins=-Tlink.x");
+ if env::var("CARGO_FEATURE_DEFMT").is_ok() {
+ println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
+ }
+
+ let target = env::var("TARGET").unwrap();
+ if target.starts_with("thumbv6m-") {
+ println!("cargo:rustc-cfg=armv6m");
+ }
+}
diff --git a/examples/boot/bootloader/stm32/memory.x b/examples/boot/bootloader/stm32/memory.x
new file mode 100644
index 00000000..110c2325
--- /dev/null
+++ b/examples/boot/bootloader/stm32/memory.x
@@ -0,0 +1,18 @@
+MEMORY
+{
+ /* NOTE 1 K = 1 KiBi = 1024 bytes */
+ FLASH : ORIGIN = 0x08000000, LENGTH = 24K
+ BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
+ ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K
+ DFU : ORIGIN = 0x08010000, LENGTH = 36K
+ RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
+}
+
+__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH);
+__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH);
+
+__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH);
+__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH);
+
+__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(FLASH);
+__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(FLASH);
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
new file mode 100644
index 00000000..45c511ce
--- /dev/null
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -0,0 +1,46 @@
+#![no_std]
+#![no_main]
+
+use cortex_m_rt::{entry, exception};
+#[cfg(feature = "defmt")]
+use defmt_rtt as _;
+use embassy_boot_stm32::*;
+use embassy_stm32::flash::{Flash, ERASE_SIZE};
+
+#[entry]
+fn main() -> ! {
+ let p = embassy_stm32::init(Default::default());
+
+ // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
+ // as it prevents a hard fault when accessing flash 'too early' after boot.
+ /*
+ for i in 0..10000000 {
+ cortex_m::asm::nop();
+ }
+ */
+
+ let mut bl: BootLoader<ERASE_SIZE> = BootLoader::default();
+ let mut flash = Flash::unlock(p.FLASH);
+ let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash));
+ core::mem::drop(flash);
+ unsafe { bl.load(start) }
+}
+
+#[no_mangle]
+#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
+unsafe extern "C" fn HardFault() {
+ cortex_m::peripheral::SCB::sys_reset();
+}
+
+#[exception]
+unsafe fn DefaultHandler(_: i16) -> ! {
+ const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
+ let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
+
+ panic!("DefaultHandler #{:?}", irqn);
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ cortex_m::asm::udf();
+}