From 9ecb6bd9deedccd39b3e51d5fef649a68702a99a Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sat, 9 Dec 2023 16:05:57 +0000 Subject: [PATCH 1/2] Use the flash_algorithm crate. I wasn't sure what the error code should be for ROM Func load failure. --- Cargo.toml | 1 + src/algo.rs | 124 ---------------------------------------------------- src/main.rs | 37 +++++++++++----- 3 files changed, 26 insertions(+), 136 deletions(-) delete mode 100644 src/algo.rs 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/src/algo.rs b/src/algo.rs deleted file mode 100644 index 19d8b4e..0000000 --- a/src/algo.rs +++ /dev/null @@ -1,124 +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 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(); - - /// Initialise the Flash Algorithm - /// - /// # Safety - /// - /// Will disable execution from Flash. Ensure you are running from SRAM - /// and do not call any flash-based based functions. - #[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(), - } - } - /// Uninitialise the Flash Algorithm - #[no_mangle] - #[link_section = ".entry"] - pub extern "C" fn UnInit() -> u32 { - unsafe { - if !_IS_INIT { - return 1; - } - _ALGO_INSTANCE.as_mut_ptr().drop_in_place(); - _IS_INIT = false; - } - 0 - } - /// Erase the flash chip. - /// - /// # Safety - /// - /// Will erase the flash chip. Ensure you really want to erase the - /// flash chip. - #[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(), - } - } - /// Erase the a sector on the flash chip. - /// - /// # Safety - /// - /// Will erase the given sector. Pass a valid sector address. - #[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(), - } - } - /// Write to a page on the flash chip. - /// - /// # Safety - /// - /// Will program the given page. Pass a valid page address, and a - /// valid pointer to at least `size` bytes of data. - #[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 d181a73..9477de2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,7 @@ #![no_std] #![no_main] -mod algo; - -use core::mem::MaybeUninit; - -use self::algo::*; +use flash_algorithm::*; fn find_func(tag: [u8; 2]) -> Option { let tag = u16::from_le_bytes(tag) as u32; @@ -53,15 +49,23 @@ 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 BLOCK_ERASE_CMD: u8 = 0xd8; -const FLASH_BASE: u32 = 0x1000_0000; -impl FlashAlgo for RP2040Algo { - fn new(_address: u32, _clock: u32, _function: u32) -> Result { +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()); }; @@ -76,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(()) } } From ddd970807e1241b760abd1ce2d9a06abfb43121b Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:39:45 +1100 Subject: [PATCH 2/2] Add PrgData and DevDscr linker sections + data --- link.x | 24 ++++++++++++++++++++++++ src/main.rs | 10 ++++++++++ 2 files changed, 34 insertions(+) diff --git a/link.x b/link.x index f2f2ee4..3918a45 100644 --- a/link.x +++ b/link.x @@ -35,6 +35,30 @@ SECTIONS { . = ALIGN(4); } + /* Section for data, specified by flashloader standard. */ + PrgData : { + /* + * We're explicitly putting a single object here (PRGDATA_Start in main.c) as this is required by some tools. + * It is not used by this algorithm + */ + KEEP(*(PrgData)) + + . = ALIGN(4); + } + + /* Description of the flash algorithm */ + DevDscr . : { + /* The device data content is only for external tools, + * and usually not referenced by the code. + * All rules have exceptions: device data is used by this flash algo. + * + * The KEEP statement ensures it's not removed by accident. + */ + KEEP(*(DeviceData)) + + . = ALIGN(4); + } + /DISCARD/ : { /* Unused exception related info that only wastes space */ *(.ARM.exidx); diff --git a/src/main.rs b/src/main.rs index 9477de2..50446f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -105,3 +105,13 @@ impl Drop for RP2040Algo { (self.funcs.flash_enter_cmd_xip)(); } } + +/// Some tools (eg Segger's debugger) require the PrgData section to exist in the target binary +/// +/// They scan the flashloader binary for this symbol to determine the section location +/// If they cannot find it, the tool exits. This variable serves no other purpose +#[allow(non_upper_case_globals)] +#[no_mangle] +#[used] +#[link_section = "PrgData"] +pub static mut PRGDATA_Start: usize = 0;