From eb629a3d78b070e74226164461140b6cec0f1478 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Sun, 18 May 2025 22:38:05 +0800 Subject: [PATCH] add blank_check command Add a command to perform a blank check on a device. This is an alternate method for devices that have ECC, where a blank device doesn't necessarily have a predetermined or homogenous bit pattern. Signed-off-by: Sean Cross --- Cargo.toml | 1 + src/lib.rs | 119 +++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 89 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ca22b36..3436fb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ description = "A crate to write CMSIS-DAP flash algorithms for flashing embedded [features] default = ["erase-chip", "panic-handler"] +blank-check = [] erase-chip = [] panic-handler = [] read-flash = [] diff --git a/src/lib.rs b/src/lib.rs index 948c4da..0394625 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { pub const FUNCTION_ERASE: u32 = 1; pub const FUNCTION_PROGRAM: u32 = 2; pub const FUNCTION_VERIFY: u32 = 3; +pub const FUNCTION_BLANKCHECK: u32 = 4; pub type ErrorCode = core::num::NonZeroU32; @@ -84,6 +85,15 @@ pub trait FlashAlgorithm: Sized + 'static { /// * `data` - The data. #[cfg(feature = "read-flash")] fn read_flash(&mut self, address: u32, data: &mut [u8]) -> Result<(), ErrorCode>; + + /// Verify that flash is blank. + /// + /// # Arguments + /// + /// * `address` - The start address of the flash to check. + /// * `size` - The length of the area to check. + #[cfg(feature = "blank-check")] + fn blank_check(&mut self, address: u32, size: u32) -> Result<(), ErrorCode>; } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -91,6 +101,7 @@ pub enum Function { Erase = 1, Program = 2, Verify = 3, + BlankCheck = 4, } /// A macro to define a new flash algoritm. @@ -121,20 +132,23 @@ macro_rules! algorithm { #[no_mangle] #[link_section = ".entry"] pub unsafe extern "C" fn Init(addr: u32, clock: u32, function: u32) -> u32 { - if _IS_INIT { - UnInit(); + unsafe { + if _IS_INIT { + UnInit(); + } + _IS_INIT = true; } - _IS_INIT = true; let function = match function { 1 => $crate::Function::Erase, 2 => $crate::Function::Program, 3 => $crate::Function::Verify, + 4 => $crate::Function::BlankCheck, _ => core::panic!("This branch can only be reached if the host library sent an unknown function code.") }; match <$type as $crate::FlashAlgorithm>::new(addr, clock, function) { Ok(inst) => { - _ALGO_INSTANCE.as_mut_ptr().write(inst); - _IS_INIT = true; + unsafe { _ALGO_INSTANCE.as_mut_ptr().write(inst) }; + unsafe { _IS_INIT = true }; 0 } Err(e) => e.get(), @@ -143,20 +157,24 @@ macro_rules! algorithm { #[no_mangle] #[link_section = ".entry"] pub unsafe extern "C" fn UnInit() -> u32 { - if !_IS_INIT { - return 1; + unsafe { + if !_IS_INIT { + return 1; + } + _ALGO_INSTANCE.as_mut_ptr().drop_in_place(); + _IS_INIT = false; } - _ALGO_INSTANCE.as_mut_ptr().drop_in_place(); - _IS_INIT = false; 0 } #[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(); + let this = unsafe { + if !unsafe { _IS_INIT } { + return 1; + } + &mut *_ALGO_INSTANCE.as_mut_ptr() + }; match <$type as $crate::FlashAlgorithm>::erase_sector(this, addr) { Ok(()) => 0, Err(e) => e.get(), @@ -165,11 +183,14 @@ macro_rules! algorithm { #[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(); - let data_slice: &[u8] = unsafe { core::slice::from_raw_parts(data, size as usize) }; + let (this, data_slice) = unsafe { + if !_IS_INIT { + return 1; + } + let this = &mut *_ALGO_INSTANCE.as_mut_ptr(); + let data_slice: &[u8] = core::slice::from_raw_parts(data, size as usize); + (this, data_slice) + }; match <$type as $crate::FlashAlgorithm>::program_page(this, addr, data_slice) { Ok(()) => 0, Err(e) => e.get(), @@ -178,6 +199,7 @@ macro_rules! algorithm { $crate::erase_chip!($type); $crate::read_flash!($type); $crate::verify!($type); + $crate::blank_check!($type); #[allow(non_upper_case_globals)] #[no_mangle] @@ -268,10 +290,12 @@ macro_rules! erase_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(); + let this = unsafe { + if !_IS_INIT { + return 1; + } + &mut *_ALGO_INSTANCE.as_mut_ptr() + }; match <$type as $crate::FlashAlgorithm>::erase_all(this) { Ok(()) => 0, Err(e) => e.get(), @@ -294,11 +318,14 @@ macro_rules! read_flash { #[no_mangle] #[link_section = ".entry"] pub unsafe extern "C" fn ReadFlash(addr: u32, size: u32, data: *mut u8) -> u32 { - if !_IS_INIT { - return 1; - } - let this = &mut *_ALGO_INSTANCE.as_mut_ptr(); - let data_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, size as usize) }; + let (this, data_slice) = unsafe { + if !_IS_INIT { + return 1; + } + let this = &mut *_ALGO_INSTANCE.as_mut_ptr(); + let data_slice: &mut [u8] = core::slice::from_raw_parts_mut(data, size as usize); + (this, data_slice) + }; match <$type as $crate::FlashAlgorithm>::read_flash(this, addr, data_slice) { Ok(()) => 0, Err(e) => e.get(), @@ -321,10 +348,12 @@ macro_rules! verify { #[no_mangle] #[link_section = ".entry"] pub unsafe extern "C" fn Verify(addr: u32, size: u32, data: *const u8) -> u32 { - if !_IS_INIT { - return 1; - } - let this = &mut *_ALGO_INSTANCE.as_mut_ptr(); + let this = unsafe { + if !_IS_INIT { + return 1; + } + &mut *_ALGO_INSTANCE.as_mut_ptr() + }; if data.is_null() { match <$type as $crate::FlashAlgorithm>::verify(this, addr, size, None) { @@ -343,6 +372,34 @@ macro_rules! verify { }; } +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "blank-check"))] +macro_rules! blank_check { + ($type:ty) => {}; +} +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "blank-check")] +macro_rules! blank_check { + ($type:ty) => { + #[no_mangle] + #[link_section = ".entry"] + pub unsafe extern "C" fn BlankCheck(addr: u32, size: u32) -> u32 { + let this = unsafe { + if !_IS_INIT { + return 1; + } + &mut *_ALGO_INSTANCE.as_mut_ptr() + }; + match <$type as $crate::FlashAlgorithm>::blank_check(this, addr, size) { + Ok(()) => 0, + Err(e) => e.get(), + } + } + }; +} + #[doc(hidden)] #[macro_export] macro_rules! count {