diff --git a/.cargo/config.toml b/.cargo/config.toml index a4240eb..2fbea76 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,7 @@ +[unstable] +build-std = ["core"] +build-std-features = ["panic_immediate_abort"] + [target.'cfg(all(target_arch = "arm", target_os = "none"))'] runner = "probe-rs run --chip RP2040" diff --git a/Cargo.lock b/Cargo.lock index 0b464e9..067d094 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -131,6 +131,31 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "bootloader" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "defmt", + "defmt-rtt", + "embassy-boot-rp", + "embassy-rp", + "embassy-sync", + "embassy-time", + "embedded-storage", + "embedded-storage-async", +] + [[package]] name = "bytemuck" version = "1.13.1" @@ -176,6 +201,7 @@ checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ "bare-metal", "bitfield", + "critical-section", "embedded-hal 0.2.7", "volatile-register", ] @@ -227,10 +253,20 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + [[package]] name = "cyw43" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "atomic-polyfill 0.1.11", "cortex-m", @@ -248,7 +284,7 @@ dependencies = [ [[package]] name = "cyw43-pio" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "cyw43", "defmt", @@ -347,6 +383,16 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -390,10 +436,39 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "embassy-boot" +version = "0.1.1" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" +dependencies = [ + "defmt", + "digest", + "embassy-embedded-hal", + "embassy-sync", + "embedded-storage", + "signature", +] + +[[package]] +name = "embassy-boot-rp" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" +dependencies = [ + "cfg-if", + "cortex-m", + "cortex-m-rt", + "defmt", + "embassy-boot", + "embassy-rp", + "embassy-sync", + "embassy-time", + "embedded-storage", +] + [[package]] name = "embassy-embedded-hal" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "embassy-futures", "embassy-sync", @@ -409,7 +484,7 @@ dependencies = [ [[package]] name = "embassy-executor" version = "0.3.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "atomic-polyfill 1.0.3", "cortex-m", @@ -424,7 +499,7 @@ dependencies = [ [[package]] name = "embassy-futures" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "defmt", ] @@ -432,7 +507,7 @@ dependencies = [ [[package]] name = "embassy-hal-internal" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "cortex-m", "critical-section", @@ -443,7 +518,7 @@ dependencies = [ [[package]] name = "embassy-macros" version = "0.2.1" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "darling", "proc-macro2", @@ -454,7 +529,7 @@ dependencies = [ [[package]] name = "embassy-net" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "as-slice 0.2.1", "atomic-polyfill 1.0.3", @@ -476,7 +551,7 @@ dependencies = [ [[package]] name = "embassy-net-driver" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "defmt", ] @@ -484,7 +559,7 @@ dependencies = [ [[package]] name = "embassy-net-driver-channel" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "embassy-futures", "embassy-net-driver", @@ -494,7 +569,7 @@ dependencies = [ [[package]] name = "embassy-rp" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "atomic-polyfill 1.0.3", "cfg-if", @@ -530,7 +605,7 @@ dependencies = [ [[package]] name = "embassy-sync" version = "0.2.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "cfg-if", "critical-section", @@ -541,8 +616,8 @@ dependencies = [ [[package]] name = "embassy-time" -version = "0.1.2" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +version = "0.1.3" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "atomic-polyfill 1.0.3", "cfg-if", @@ -558,7 +633,7 @@ dependencies = [ [[package]] name = "embassy-usb" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "defmt", "embassy-futures", @@ -573,7 +648,7 @@ dependencies = [ [[package]] name = "embassy-usb-driver" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy#f8299d10f7c0387416989e00acc02d99661537fb" +source = "git+https://github.com/embassy-rs/embassy#9d8c527308522698bfb6596bdb67bec826e0fb5a" dependencies = [ "defmt", ] @@ -693,9 +768,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -996,9 +1071,9 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" [[package]] name = "nb" @@ -1283,25 +1358,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] @@ -1312,9 +1387,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "rp" @@ -1396,9 +1471,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.9" +version = "0.38.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" dependencies = [ "bitflags 2.4.0", "errno", @@ -1448,9 +1523,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.187" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7fe14252655bd1e578af19f5fa00fe02fd0013b100ca6b49fde31c41bae4c" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -1468,15 +1543,21 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.187" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46b2a6ca578b3f1d4501b12f78ed4692006d79d82a1a7c561c12dbc3d625eb8" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", "syn 2.0.29", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[package]] name = "siphasher" version = "0.3.11" diff --git a/Cargo.toml b/Cargo.toml index 3d5fa7c..e87a78d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,8 @@ name = "rp" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] +members = ["bootloader"] [dependencies] cortex-m = { version = "0.7", features = ["inline-asm"] } @@ -78,6 +79,8 @@ embassy-net = { git = "https://github.com/embassy-rs/embassy" } embassy-sync = { git = "https://github.com/embassy-rs/embassy" } embassy-futures = { git = "https://github.com/embassy-rs/embassy" } +embassy-boot-rp = { git = "https://github.com/embassy-rs/embassy" } + rust-mqtt = { path = "../rust-mqtt" } [build-dependencies] @@ -90,3 +93,4 @@ exclude_firmwares = [] [profile.release] debug = true +opt-level = 's' diff --git a/bootloader/Cargo.toml b/bootloader/Cargo.toml new file mode 100644 index 0000000..80dce99 --- /dev/null +++ b/bootloader/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "bootloader" +version = "0.1.0" +edition = "2021" + +[dependencies] +defmt = { version = "0.3", optional = true } +defmt-rtt = { version = "0.4", optional = true } + +embassy-rp = { version = "0.1", features = ["nightly"] } +embassy-boot-rp = { version = "0.1" } +embassy-sync = { version = "0.2" } +embassy-time = { version = "0.1", features = ["nightly"] } + +cortex-m = { version = "0.7", features = [ + "inline-asm", + "critical-section-single-core", +] } +cortex-m-rt = { version = "0.7" } +embedded-storage = "0.3.0" +embedded-storage-async = "0.4.0" + +[features] +defmt = ["dep:defmt", "embassy-boot-rp/defmt", "embassy-rp/defmt"] +debug = ["defmt-rtt", "defmt"] diff --git a/bootloader/build.rs b/bootloader/build.rs new file mode 100644 index 0000000..07d2655 --- /dev/null +++ b/bootloader/build.rs @@ -0,0 +1,36 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // By default cortex-m-rt expects memory.x, however this causes issues with workspaces as it + // will pick the first file that is found. + // In order to get around this we make a dummy memory.x file + File::create(out.join("memory.x")).unwrap(); + + // Use memory.x.in as a template for the actual memory.x + let memory = include_str!("../memory.x.in") + .replace("{BOOTLOADER}", "FLASH") + .replace("{ACTIVE}", "ACTIVE"); + + // And then include it with a unique name + File::create(out.join("memory_boot.x")) + .unwrap() + .write_all(memory.as_bytes()) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=../memory.x.in"); + + // And link with that one + println!("cargo:rustc-link-arg-bins=-Tmemory_boot.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } +} diff --git a/bootloader/src/main.rs b/bootloader/src/main.rs new file mode 100644 index 0000000..b14e444 --- /dev/null +++ b/bootloader/src/main.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use cortex_m_rt::{entry, exception}; +#[cfg(feature = "defmt")] +use defmt_rtt as _; +use embassy_boot_rp::*; +use embassy_rp::flash::{Blocking, Flash}; +use embassy_sync::blocking_mutex::Mutex; + +const FLASH_SIZE: usize = 2 * 1024 * 1024; + +#[entry] +fn main() -> ! { + let p = embassy_rp::init(Default::default()); + + let flash = Flash::<_, Blocking, FLASH_SIZE>::new_blocking(p.FLASH); + let flash = Mutex::new(RefCell::new(flash)); + + let config = BootLoaderConfig::from_linkerfile_blocking(&flash); + let active_offset = config.active.offset(); + let bl: BootLoader = BootLoader::prepare(config); + + unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) } +} + +#[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/build.rs b/build.rs index caef35c..70e99b0 100644 --- a/build.rs +++ b/build.rs @@ -1,37 +1,34 @@ -//! 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")) + + // By default cortex-m-rt expects memory.x, however this causes issues with workspaces as it + // will pick the first file that is found. + // In order to get around this we make a dummy memory.x file + File::create(out.join("memory.x")).unwrap(); + + // Use memory.x.in as a template for the actual memory.x + let memory = include_str!("memory.x.in") + .replace("{BOOTLOADER}", "BOOTLOADER") + .replace("{ACTIVE}", "FLASH"); + + // And then include it with a unique name + File::create(out.join("memory_app.x")) .unwrap() - .write_all(include_bytes!("memory.x")) + .write_all(memory.as_bytes()) .unwrap(); println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x.in"); - // 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"); + // And link with that one + println!("cargo:rustc-link-arg-bins=-Tmemory_app.x"); println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); - println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); if let Ok(dotenv_path) = dotenvy::dotenv() { diff --git a/memory.x b/memory.x deleted file mode 100644 index 9c3f0c5..0000000 --- a/memory.x +++ /dev/null @@ -1,10 +0,0 @@ -MEMORY { - BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 - 256k -8k - FW : ORIGIN = 0x101BE000, LENGTH = 256k - CLM : ORIGIN = 0x101FE000, LENGTH = 8k - RAM : ORIGIN = 0x20000000, LENGTH = 256K -} - -__fw_start = ORIGIN(FW); -__clm_start = ORIGIN(CLM); diff --git a/memory.x.in b/memory.x.in new file mode 100644 index 0000000..9decd72 --- /dev/null +++ b/memory.x.in @@ -0,0 +1,22 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + {BOOTLOADER} : ORIGIN = 0x10000100, LENGTH = 24k - 0x100 + BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4k + {ACTIVE} : ORIGIN = 0x10007000, LENGTH = 876k + DFU : ORIGIN = 0x100E2000, LENGTH = 880k + FW : ORIGIN = 0x101BE000, LENGTH = 256k + CLM : ORIGIN = 0x101FE000, LENGTH = 8k + RAM : ORIGIN = 0x20000000, LENGTH = 264K +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2); + +__bootloader_active_start = ORIGIN({ACTIVE}) - ORIGIN(BOOT2); +__bootloader_active_end = ORIGIN({ACTIVE}) + LENGTH({ACTIVE}) - ORIGIN(BOOT2); + +__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2); + +__fw_start = ORIGIN(FW); +__clm_start = ORIGIN(CLM);