diff --git a/.cargo/config b/.cargo/config index 2253c32..8b2fc36 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,7 +1,3 @@ -[unstable] -build-std = ["core"] -build-std-features = ["panic_immediate_abort"] - [target.'cfg(all(target_arch = "arm", target_os = "none"))'] rustflags = [ @@ -9,7 +5,6 @@ rustflags = [ "-C", "link-arg=-Tlink.x", # Code-size optimizations. - "-Z", "trap-unreachable=no", "-C", "inline-threshold=5", "-C", "no-vectorize-loops", "-C", "force-frame-pointers=no", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63a3527..20fc9e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,17 +11,12 @@ env: jobs: build: - runs-on: ubuntu-latest - steps: - uses: actions/checkout@v2 - name: Install Dependencies run: | - sudo apt update - rustup component add rust-src cargo install cargo-binutils - rustup component add llvm-tools-preview - name: Build run: | ./build.sh diff --git a/Cargo.toml b/Cargo.toml index 735f340..8352dcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ version = "0.1.0" [dependencies] cortex-m = "0.7.0" +flash-algorithm = "0.4.0" # this lets you use `cargo fix`! [[bin]] diff --git a/README.md b/README.md index 2587111..ecdea3e 100644 --- a/README.md +++ b/README.md @@ -5,23 +5,27 @@ It implements the CMSIS-Pack ABI, so it's compatible with any tools that use it, ## Dependencies -Run the following requirements: +Run the following to install the requirements: + ```bash -cargo install cargo-binutils && rustup component add llvm-tools-preview rust-src +cargo install cargo-binutils ``` -## Building -Building requires nightly Rust. +The `rust-toolchain` file will get you the targets and components you need. + +## Building Just run `build.sh`. It spits out the flash algo in the probe-rs YAML format: - flash-algo$ ./build.sh +```console +flash-algo$ ./build.sh instructions: sLUUIACIGUoBRguI...wRwAgcEc= pc_init: 0x00000000 pc_uninit: 0x0000007c pc_program_page: 0x00000088 pc_erase_sector: 0x00000084 pc_erase_all: 0x00000080 +``` ## Hacking @@ -30,7 +34,7 @@ the glue functions for a given struct implementing it. This is generic for all c `main.rs` has the actual implementation for RP2040. -# License +## License This thingy is licensed under either of diff --git a/rust-toolchain b/rust-toolchain index bf867e0..2861012 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1,5 @@ -nightly +[toolchain] +channel = "stable" +components = [ "llvm-tools" ] +profile = "minimal" +targets = ["thumbv6m-none-eabi"] diff --git a/src/algo.rs b/src/algo.rs deleted file mode 100644 index bf548bb..0000000 --- a/src/algo.rs +++ /dev/null @@ -1,103 +0,0 @@ -#![macro_use] - - -use core::arch::asm; -use core::num::NonZeroU32; - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - unsafe { - asm!("udf #0"); - core::hint::unreachable_unchecked(); - } -} - -pub const FUNCTION_ERASE: u32 = 1; -pub const FUNCTION_PROGRAM: u32 = 2; -pub const FUNCTION_VERIFY: u32 = 3; - -pub type ErrorCode = NonZeroU32; - -pub trait FlashAlgo: Sized + 'static { - /// Initialize the flash algorithm. - fn new(address: u32, clock: u32, function: u32) -> Result; - - /// Erase entire chip. May only be called after init() with FUNCTION_ERASE - fn erase_all(&mut self) -> Result<(), ErrorCode>; - - /// Erase sector. May only be called after init() with FUNCTION_ERASE - fn erase_sector(&mut self, addr: u32) -> Result<(), ErrorCode>; - - /// Program bytes. May only be called after init() with FUNCTION_PROGRAM - fn program_page(&mut self, addr: u32, size: u32, data: *const u8) -> Result<(), ErrorCode>; -} - -#[macro_export] -macro_rules! algo { - ($type:ty) => { - static mut _IS_INIT: bool = false; - static mut _ALGO_INSTANCE: MaybeUninit<$type> = MaybeUninit::uninit(); - - #[no_mangle] - #[link_section = ".entry"] - pub unsafe extern "C" fn Init(addr: u32, clock: u32, function: u32) -> u32 { - if _IS_INIT { - UnInit(); - } - match <$type as FlashAlgo>::new(addr, clock, function) { - Ok(inst) => { - _ALGO_INSTANCE.as_mut_ptr().write(inst); - _IS_INIT = true; - 0 - } - Err(e) => e.get(), - } - } - #[no_mangle] - #[link_section = ".entry"] - pub unsafe extern "C" fn UnInit() -> u32 { - if !_IS_INIT { - return 1; - } - _ALGO_INSTANCE.as_mut_ptr().drop_in_place(); - _IS_INIT = false; - 0 - } - #[no_mangle] - #[link_section = ".entry"] - pub unsafe extern "C" fn EraseChip() -> u32 { - if !_IS_INIT { - return 1; - } - let this = &mut *_ALGO_INSTANCE.as_mut_ptr(); - match <$type as FlashAlgo>::erase_all(this) { - Ok(()) => 0, - Err(e) => e.get(), - } - } - #[no_mangle] - #[link_section = ".entry"] - pub unsafe extern "C" fn EraseSector(addr: u32) -> u32 { - if !_IS_INIT { - return 1; - } - let this = &mut *_ALGO_INSTANCE.as_mut_ptr(); - match <$type as FlashAlgo>::erase_sector(this, addr) { - Ok(()) => 0, - Err(e) => e.get(), - } - } - #[no_mangle] - #[link_section = ".entry"] - pub unsafe extern "C" fn ProgramPage(addr: u32, size: u32, data: *const u8) -> u32 { - if !_IS_INIT { - return 1; - } - let this = &mut *_ALGO_INSTANCE.as_mut_ptr(); - match <$type as FlashAlgo>::program_page(this, addr, size, data) { - Ok(()) => 0, - Err(e) => e.get(), - } - } - }; -} diff --git a/src/main.rs b/src/main.rs index 0f88c89..9477de2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,30 +1,25 @@ #![no_std] #![no_main] -mod algo; - -use core::mem; -use core::mem::MaybeUninit; - -use self::algo::*; - -fn find_func(tag: [u8; 2]) -> T { - let tag = u16::from_le_bytes(tag); - +use flash_algorithm::*; + +fn find_func(tag: [u8; 2]) -> Option { + let tag = u16::from_le_bytes(tag) as u32; + type RomTableLookupFn = unsafe extern "C" fn(table: *const u16, code: u32) -> usize; + /// This location in flash holds a 16-bit truncated pointer for the ROM lookup function + const ROM_TABLE_LOOKUP_PTR: *const u16 = 0x0000_0018 as _; + /// This location in flash holds a 16-bit truncated pointer for the ROM function table + /// (there's also a ROM data table which we don't need) + const FUNC_TABLE: *const u16 = 0x0000_0014 as _; unsafe { - let mut entry = *(0x00000014 as *const u16) as *const u16; - loop { - let entry_tag = entry.read(); - if entry_tag == 0 { - panic!("Func not found"); - } - entry = entry.add(1); - let entry_addr = entry.read(); - entry = entry.add(1); - if entry_tag == tag { - return mem::transmute_copy(&(entry_addr as u32)); - } + let lookup_func = ROM_TABLE_LOOKUP_PTR.read() as usize; + let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func); + let table = FUNC_TABLE.read() as usize; + let result = lookup_func(table as *const u16, tag); + if result == 0 { + return None; } + Some(core::mem::transmute_copy(&result)) } } @@ -38,15 +33,15 @@ struct ROMFuncs { } impl ROMFuncs { - fn load() -> Self { - ROMFuncs { - connect_internal_flash: find_func(*b"IF"), - flash_exit_xip: find_func(*b"EX"), - flash_range_erase: find_func(*b"RE"), - flash_range_program: find_func(*b"RP"), - flash_flush_cache: find_func(*b"FC"), - flash_enter_cmd_xip: find_func(*b"CX"), - } + fn load() -> Option { + Some(ROMFuncs { + connect_internal_flash: find_func(*b"IF")?, + flash_exit_xip: find_func(*b"EX")?, + flash_range_erase: find_func(*b"RE")?, + flash_range_program: find_func(*b"RP")?, + flash_flush_cache: find_func(*b"FC")?, + flash_enter_cmd_xip: find_func(*b"CX")?, + }) } } @@ -54,18 +49,26 @@ struct RP2040Algo { funcs: ROMFuncs, } -algo!(RP2040Algo); +algorithm!(RP2040Algo, { + flash_address: 0x1000_0000, + flash_size: 0x0100_0000, + page_size: 0x100, + empty_value: 0xFF, + sectors: [{ + size: 0x1000, + address: 0x10000000, + }] +}); const BLOCK_SIZE: u32 = 65536; const SECTOR_SIZE: u32 = 4096; -const PAGE_SIZE: u32 = 256; const BLOCK_ERASE_CMD: u8 = 0xd8; -const FLASH_BASE: u32 = 0x1000_0000; - -impl FlashAlgo for RP2040Algo { - fn new(_address: u32, _clock: u32, _function: u32) -> Result { - let funcs = ROMFuncs::load(); +impl FlashAlgorithm for RP2040Algo { + fn new(_address: u32, _clock: u32, _function: Function) -> Result { + let Some(funcs) = ROMFuncs::load() else { + return Err(ErrorCode::new(1).unwrap()); + }; (funcs.connect_internal_flash)(); (funcs.flash_exit_xip)(); Ok(Self { funcs }) @@ -77,12 +80,21 @@ impl FlashAlgo for RP2040Algo { } fn erase_sector(&mut self, addr: u32) -> Result<(), ErrorCode> { - (self.funcs.flash_range_erase)(addr - FLASH_BASE, SECTOR_SIZE, BLOCK_SIZE, BLOCK_ERASE_CMD); + (self.funcs.flash_range_erase)( + addr - FlashDevice.dev_addr, + SECTOR_SIZE, + BLOCK_SIZE, + BLOCK_ERASE_CMD, + ); Ok(()) } - fn program_page(&mut self, addr: u32, size: u32, data: *const u8) -> Result<(), ErrorCode> { - (self.funcs.flash_range_program)(addr - FLASH_BASE, data, size); + fn program_page(&mut self, addr: u32, data: &[u8]) -> Result<(), ErrorCode> { + (self.funcs.flash_range_program)( + addr - FlashDevice.dev_addr, + data.as_ptr(), + data.len() as u32, + ); Ok(()) } }