From b3a0dceabda7f6ca6530e8174e443fc0b301ea9a Mon Sep 17 00:00:00 2001 From: pdobbins23 <146784496+pdobbins23@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:03:26 -0800 Subject: [PATCH 01/32] Add write guard, fix some code duplication --- hal/src/peripherals/flash_controller.rs | 120 ++++++++++++++---------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 400c4f3..3e5dc93 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -111,6 +111,52 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { Ok(()) } + /// Busy loop until FLC is ready. + /// + /// This MUST be called BEFORE any FLC operation EXCEPT clearing interrupts. + fn wait_until_ready(&self) { + while !self.flc.ctrl().read().pend().bit_is_clear() {} + } + + /// Clear any stale errors in the FLC Interrupt Register + /// + /// This can be called without waiting for the FLC to be ready. + fn clear_interrupts(&self) { + self.flc.intr().modify(|_, w| w.af().clear_bit()); + } + + /// Prepares the FLC for a write operation. + /// + /// Procedure: + /// - Wait until FLC ready + /// - Disable icc0 + /// - Clear FLC interrupts + /// - Set clock divisor + /// - Unlock write protection + /// - EXECUTE OPERATION (CLOSURE) + /// - Wait until FLC ready + /// - Lock write protection + /// - Flush ICC + /// - Enable icc0 + fn write_guard ()>(&self, sys_clk: &SystemClock, operation: F) -> Result<(), FlashErr> { + // Pre-write + self.wait_until_ready(); + self.disable_icc0(); + self.clear_interrupts(); + self.set_clock_divisor(sys_clk)?; + self.unlock_write_protection(); + + operation(); + + // Post-write + self.wait_until_ready(); + self.lock_write_protection(); + self.flush_icc()?; + self.enable_icc0(); + + Ok(()) + } + /// Flushes the flash line buffer and arm instruction cache. /// /// This MUST be called after any write/erase flash controller operations. @@ -123,6 +169,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { let mut empty_buffer = [0; 4]; self.read_bytes(ptr, &mut empty_buffer)?; self.read_bytes(ptr + FLASH_PAGE_SIZE, &mut empty_buffer)?; + Ok(()) } @@ -175,7 +222,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { } for byte in word_chunk.into_remainder() { - // SAFETY: + // SAFETY:CLOSURE // * src is valid for reads. Because read range is checked at the // beginning of function. // @@ -214,10 +261,6 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { ) -> Result<(), FlashErr> { self.check_address_bounds(address..(address + data.len() as u32))?; - self.set_clock_divisor(sys_clk)?; - - self.disable_icc0(); - // Check alignment let mut physical_addr = address; let bytes_unaligned = if (address & 0xF) > 0 { @@ -229,7 +272,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { // Write unaligned data if bytes_unaligned > 0 { let unaligned_data = &data[0..core::cmp::min(bytes_unaligned, data.len())]; - self.write_lt_128_unaligned(physical_addr, unaligned_data)?; + self.write_lt_128_unaligned(physical_addr, unaligned_data, sys_clk)?; physical_addr += unaligned_data.len() as u32; } @@ -244,25 +287,21 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { let mut buffer_128_bits: [u32; 4] = [0; 4]; word.enumerate() .for_each(|(idx, chunk)| buffer_128_bits[idx] = chunk); - self.write128(physical_addr, &buffer_128_bits)?; + self.write128(physical_addr, &buffer_128_bits, sys_clk)?; physical_addr += 16; } // remainder from chunks if !chunk_8.remainder().is_empty() { - self.write_lt_128_unaligned(physical_addr, chunk_8.remainder())?; + self.write_lt_128_unaligned(physical_addr, chunk_8.remainder(), sys_clk)?; } - self.flush_icc()?; - - self.enable_icc0(); - Ok(()) } /// Writes less than 128 bits (16 bytes) of data to flash. Data needs to fit /// within one flash word (16 bytes). - fn write_lt_128_unaligned(&self, address: u32, data: &[u8]) -> Result<(), FlashErr> { + unsafe fn write_lt_128_unaligned(&self, address: u32, data: &[u8], sys_clk: &SystemClock) -> Result<(), FlashErr> { // Get byte idx within 128-bit word let byte_idx = (address & 0xF) as usize; @@ -284,34 +323,28 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { new_data[idx] = u32::from_le_bytes(word_chunk.try_into().unwrap()) }); - self.write128(aligned_addr, &new_data) + self.write128(aligned_addr, &new_data, sys_clk) } /// Writes 128 bits (16 bytes) of data to flash. - // make sure to disable ICC with ICC_Disable(); before Running this function - fn write128(&self, address: u32, data: &[u32; 4]) -> Result<(), FlashErr> { + unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk: &SystemClock) -> Result<(), FlashErr> { // Check if adddress is 128-bit aligned if address & 0xF > 0 { return Err(FlashErr::AddressNotAligned128); } - self.unlock_write_protection(); + self.write_guard(sys_clk, || { + self.flc.addr().modify(|_, w| w.addr().variant(address)); + self.flc.data(0).modify(|_, w| w.data().variant(data[0])); + self.flc.data(1).modify(|_, w| w.data().variant(data[1])); + self.flc.data(2).modify(|_, w| w.data().variant(data[2])); + self.flc.data(3).modify(|_, w| w.data().variant(data[3])); - // Clear stale errors - self.flc.intr().modify(|_, w| w.af().clear_bit()); - - while !self.flc.ctrl().read().pend().bit_is_clear() {} + self.flc.ctrl().modify(|_, w| w.wr().set_bit()); - self.flc.addr().modify(|_, w| w.addr().variant(address)); - self.flc.data(0).modify(|_, w| w.data().variant(data[0])); - self.flc.data(1).modify(|_, w| w.data().variant(data[1])); - self.flc.data(2).modify(|_, w| w.data().variant(data[2])); - self.flc.data(3).modify(|_, w| w.data().variant(data[3])); - - self.flc.ctrl().modify(|_, w| w.wr().set_bit()); - while !self.flc.ctrl().read().wr().is_complete() {} - - self.lock_write_protection(); + // Wait until write completes + while !self.flc.ctrl().read().wr().is_complete() {} + })?; Ok(()) } @@ -327,27 +360,12 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { pub unsafe fn page_erase(&self, address: u32, sys_clk: &SystemClock) -> Result<(), FlashErr> { self.check_address_bounds(address..address)?; - if self.set_clock_divisor(sys_clk).is_err() { - return Err(FlashErr::FlcClkErr); - } + self.write_guard(sys_clk, || { + self.flc.addr().modify(|_, w| w.addr().variant(address)); - self.unlock_write_protection(); - - // Clear stale errors - self.flc.intr().modify(|_, w| w.af().clear_bit()); - - while !self.flc.ctrl().read().pend().bit_is_clear() {} - - self.flc.addr().modify(|_, w| w.addr().variant(address)); - - self.flc.ctrl().modify(|_, w| w.erase_code().erase_page()); - self.flc.ctrl().modify(|_, w| w.pge().set_bit()); - - while !self.flc.ctrl().read().pend().bit_is_clear() {} - - self.lock_write_protection(); - - self.flush_icc()?; + self.flc.ctrl().modify(|_, w| w.erase_code().erase_page()); + self.flc.ctrl().modify(|_, w| w.pge().set_bit()); + })?; Ok(()) } From e38bf9bf273b8ae6098184e3e2c5762fa7038ce6 Mon Sep 17 00:00:00 2001 From: pdobbins23 <146784496+pdobbins23@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:05:05 -0800 Subject: [PATCH 02/32] Fix lint warnings & formatting --- hal/src/peripherals/flash_controller.rs | 26 +++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 3e5dc93..5b27bc3 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -112,21 +112,21 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { } /// Busy loop until FLC is ready. - /// + /// /// This MUST be called BEFORE any FLC operation EXCEPT clearing interrupts. fn wait_until_ready(&self) { while !self.flc.ctrl().read().pend().bit_is_clear() {} } /// Clear any stale errors in the FLC Interrupt Register - /// + /// /// This can be called without waiting for the FLC to be ready. fn clear_interrupts(&self) { self.flc.intr().modify(|_, w| w.af().clear_bit()); } /// Prepares the FLC for a write operation. - /// + /// /// Procedure: /// - Wait until FLC ready /// - Disable icc0 @@ -138,7 +138,11 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// - Lock write protection /// - Flush ICC /// - Enable icc0 - fn write_guard ()>(&self, sys_clk: &SystemClock, operation: F) -> Result<(), FlashErr> { + fn write_guard( + &self, + sys_clk: &SystemClock, + operation: F, + ) -> Result<(), FlashErr> { // Pre-write self.wait_until_ready(); self.disable_icc0(); @@ -301,7 +305,12 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// Writes less than 128 bits (16 bytes) of data to flash. Data needs to fit /// within one flash word (16 bytes). - unsafe fn write_lt_128_unaligned(&self, address: u32, data: &[u8], sys_clk: &SystemClock) -> Result<(), FlashErr> { + unsafe fn write_lt_128_unaligned( + &self, + address: u32, + data: &[u8], + sys_clk: &SystemClock, + ) -> Result<(), FlashErr> { // Get byte idx within 128-bit word let byte_idx = (address & 0xF) as usize; @@ -327,7 +336,12 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { } /// Writes 128 bits (16 bytes) of data to flash. - unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk: &SystemClock) -> Result<(), FlashErr> { + unsafe fn write128( + &self, + address: u32, + data: &[u32; 4], + sys_clk: &SystemClock, + ) -> Result<(), FlashErr> { // Check if adddress is 128-bit aligned if address & 0xF > 0 { return Err(FlashErr::AddressNotAligned128); From 85c8d1e128773ec9704e91c9e9a06b550e2a2d19 Mon Sep 17 00:00:00 2001 From: pdobbins23 <146784496+pdobbins23@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:25:16 -0800 Subject: [PATCH 03/32] Update FLC tests to use both UART and semihosting --- tests/src/main.rs | 20 ++++++++++++++++++++ tests/src/tests/flc_tests.rs | 5 ++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/src/main.rs b/tests/src/main.rs index 2e6b4b1..fadb25b 100644 --- a/tests/src/main.rs +++ b/tests/src/main.rs @@ -58,6 +58,26 @@ fn main() -> ! { .configure_timer_2(Oscillator::ISO, Prescaler::_4096) .build(); + // run FLC tests with semi-hosting + flc_tests::run_flc_tests( + &mut stdout, + manager.flash_controller().unwrap(), + manager.system_clock().unwrap(), + ); + + { + let mut uart = manager.build_uart().unwrap().build(115200); + + // run FLC tests with UART + flc_tests::run_flc_tests( + &mut uart, + manager.flash_controller().unwrap(), + manager.system_clock().unwrap(), + ); + + // UART instance is tossed here + } + flc_tests::run_flc_tests( &mut stdout, manager.flash_controller().unwrap(), diff --git a/tests/src/tests/flc_tests.rs b/tests/src/tests/flc_tests.rs index f839717..0534520 100644 --- a/tests/src/tests/flc_tests.rs +++ b/tests/src/tests/flc_tests.rs @@ -1,7 +1,6 @@ //! Flash controller tests use core::fmt::Write; -use cortex_m_semihosting::hio; use max78000_hal::peripherals::flash_controller::{FlashController, FlashErr}; use max78000_hal::peripherals::oscillator::{ Ibro, IbroDivider, IbroFrequency, Iso, IsoDivider, IsoFrequency, Oscillator, SystemClock, @@ -14,8 +13,8 @@ use max78000_hal::peripherals::PeripheralHandle; /// [`flash_write_full_outbounds`], /// [`flash_write_partially_outbound_beginning`], /// [`flash_write_full_partially_outbound_end`]. -pub fn run_flc_tests( - stdout: &mut hio::HostStream, +pub fn run_flc_tests( + stdout: &mut T, flash_controller: PeripheralHandle<'_, FlashController<'_, '_>>, mut sys_clk: PeripheralHandle<'_, SystemClock<'_, '_>>, ) { From d7cee28ab14707b24c7cb7796ae739baffc7fbbe Mon Sep 17 00:00:00 2001 From: pdobbins23 <146784496+pdobbins23@users.noreply.github.com> Date: Sun, 23 Feb 2025 01:43:34 -0800 Subject: [PATCH 04/32] Fix formatting again? --- hal/src/peripherals/flash_controller.rs | 6 +----- tests/build.rs | 2 ++ tests/memory.x | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 5b27bc3..3f40e8d 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -138,11 +138,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// - Lock write protection /// - Flush ICC /// - Enable icc0 - fn write_guard( - &self, - sys_clk: &SystemClock, - operation: F, - ) -> Result<(), FlashErr> { + fn write_guard(&self, sys_clk: &SystemClock, operation: F) -> Result<(), FlashErr> { // Pre-write self.wait_until_ready(); self.disable_icc0(); diff --git a/tests/build.rs b/tests/build.rs index 42107c6..90c6c1f 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -13,6 +13,8 @@ fn main() { .write_all(include_bytes!("memory.x")) .unwrap(); + println!("cargo:rustc-link-arg=--nmagic"); + // Only re-run the build script when this file, memory.x, or link.x is changed. println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=memory.x"); diff --git a/tests/memory.x b/tests/memory.x index aabdf58..2994e14 100644 --- a/tests/memory.x +++ b/tests/memory.x @@ -1,6 +1,7 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K + FLASH (rx) : ORIGIN = 0x1000E000, LENGTH = 222K + SECFLASH (rx) : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = 2K STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K RAM (rw) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 128K - LENGTH(STACK) } @@ -9,5 +10,19 @@ MEMORY Add a block of memory for the stack before the RAM block, so that a stack overflow leaks into reserved space and flash memory, instead of .data and .bss. */ +ASSERT((LENGTH(SECFLASH) == 2K), "Error: SECFLASH is not 2K. To change the size, update this assert, the size in the MEMORY section, and the assert in the flash layout crate.") _stack_start = ORIGIN(STACK) + LENGTH(STACK); +_stack_end = ORIGIN(STACK); + +/* Bootloader hard jumps to 0x1000e200 */ +_stext = ORIGIN(FLASH) + 0x200; + +SECTIONS { + /* Add a section for the secure flash space. */ + .secflash ORIGIN(SECFLASH) : + { + KEEP(*(.secflash .secflash.*)); + . = ALIGN(4); + } > SECFLASH +} From 2f144adca798323eb0b04535e06c4522e9227608 Mon Sep 17 00:00:00 2001 From: pdobbins23 <146784496+pdobbins23@users.noreply.github.com> Date: Sun, 23 Feb 2025 10:41:37 -0800 Subject: [PATCH 05/32] Add safety comments & fix memory.x --- hal/src/peripherals/flash_controller.rs | 27 +++++++++++++++++++++++-- tests/memory.x | 21 +------------------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 3f40e8d..cadf2d3 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -299,8 +299,19 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { Ok(()) } - /// Writes less than 128 bits (16 bytes) of data to flash. Data needs to fit - /// within one flash word (16 bytes). + /// Writes less than 128 bits (16 bytes) of data to flash. + /// Data needs to fit within one flash word (16 bytes). + /// + /// SAFETY: + /// + /// Writes must not corrupt potentially executable instructions of the program. + /// Callers must ensure that the following condition is met: + /// * If `address` points to a portion of the program's instructions, `data` must + /// contain valid instructions that does not introduce undefined behavior. + /// + /// It is very difficult to define what would cause undefined behavior when + /// modifying program instructions. This would almost certainly result + /// in unwanted and likely undefined behavior. Do so at your own risk. unsafe fn write_lt_128_unaligned( &self, address: u32, @@ -332,6 +343,18 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { } /// Writes 128 bits (16 bytes) of data to flash. + /// Address must be 128-bit aligned. + /// + /// SAFETY: + /// + /// Writes must not corrupt potentially executable instructions of the program. + /// Callers must ensure that the following condition is met: + /// * If `address` points to a portion of the program's instructions, `data` must + /// contain valid instructions that does not introduce undefined behavior. + /// + /// It is very difficult to define what would cause undefined behavior when + /// modifying program instructions. This would almost certainly result + /// in unwanted and likely undefined behavior. Do so at your own risk. unsafe fn write128( &self, address: u32, diff --git a/tests/memory.x b/tests/memory.x index 2994e14..50aa495 100644 --- a/tests/memory.x +++ b/tests/memory.x @@ -1,28 +1,9 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x1000E000, LENGTH = 222K - SECFLASH (rx) : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = 2K + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K RAM (rw) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 128K - LENGTH(STACK) } -/* -Add a block of memory for the stack before the RAM block, so that a stack overflow leaks into -reserved space and flash memory, instead of .data and .bss. -*/ -ASSERT((LENGTH(SECFLASH) == 2K), "Error: SECFLASH is not 2K. To change the size, update this assert, the size in the MEMORY section, and the assert in the flash layout crate.") - _stack_start = ORIGIN(STACK) + LENGTH(STACK); _stack_end = ORIGIN(STACK); - -/* Bootloader hard jumps to 0x1000e200 */ -_stext = ORIGIN(FLASH) + 0x200; - -SECTIONS { - /* Add a section for the secure flash space. */ - .secflash ORIGIN(SECFLASH) : - { - KEEP(*(.secflash .secflash.*)); - . = ALIGN(4); - } > SECFLASH -} From 055329c11e0502bd34e5e01cdb864d6592d6c09e Mon Sep 17 00:00:00 2001 From: pdobbins23 <146784496+pdobbins23@users.noreply.github.com> Date: Sun, 23 Feb 2025 10:45:26 -0800 Subject: [PATCH 06/32] Fix formatting? --- hal/src/peripherals/flash_controller.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index cadf2d3..6407967 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -242,8 +242,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { Ok(()) } - /// - /// # Safety + /// SAFETY: /// /// Writes must not corrupt potentially executable instructions of the program. /// Callers must ensure that the following condition is met: @@ -303,7 +302,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// Data needs to fit within one flash word (16 bytes). /// /// SAFETY: - /// + /// /// Writes must not corrupt potentially executable instructions of the program. /// Callers must ensure that the following condition is met: /// * If `address` points to a portion of the program's instructions, `data` must @@ -346,7 +345,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// Address must be 128-bit aligned. /// /// SAFETY: - /// + /// /// Writes must not corrupt potentially executable instructions of the program. /// Callers must ensure that the following condition is met: /// * If `address` points to a portion of the program's instructions, `data` must From 88fa9b3f1e5a8efca3f79256a109ed645270d706 Mon Sep 17 00:00:00 2001 From: pdobbins23 <146784496+pdobbins23@users.noreply.github.com> Date: Sun, 23 Feb 2025 10:47:16 -0800 Subject: [PATCH 07/32] Fix safety comment format --- hal/src/peripherals/flash_controller.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 6407967..324628d 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -242,7 +242,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { Ok(()) } - /// SAFETY: + /// # Safety /// /// Writes must not corrupt potentially executable instructions of the program. /// Callers must ensure that the following condition is met: @@ -301,7 +301,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// Writes less than 128 bits (16 bytes) of data to flash. /// Data needs to fit within one flash word (16 bytes). /// - /// SAFETY: + /// # Safety /// /// Writes must not corrupt potentially executable instructions of the program. /// Callers must ensure that the following condition is met: @@ -344,7 +344,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// Writes 128 bits (16 bytes) of data to flash. /// Address must be 128-bit aligned. /// - /// SAFETY: + /// # Safety /// /// Writes must not corrupt potentially executable instructions of the program. /// Callers must ensure that the following condition is met: From aac1d4ee920aae13ca441178cf32acf1a0b6bb25 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 2 Mar 2025 17:24:06 -0800 Subject: [PATCH 08/32] flc ram linking --- .cargo/config.toml | 2 +- hal/Cargo.toml | 2 + hal/src/peripherals.rs | 4 + hal/src/peripherals/flash_controller.rs | 300 ++++++------- hal/src/peripherals/oscillator.rs | 2 + tests/Cargo.toml | 10 +- tests/build.rs | 15 + tests/flc_asm.s | 562 ++++++++++++++++++++++++ tests/link.x | 293 ++++++++++++ tests/memory.x | 3 +- tests/run.sh | 2 +- tests/src/main.rs | 19 +- tests/src/tests/flc_tests.rs | 24 +- 13 files changed, 1039 insertions(+), 199 deletions(-) create mode 100644 tests/flc_asm.s create mode 100644 tests/link.x diff --git a/.cargo/config.toml b/.cargo/config.toml index e0e5b9f..a03c2a8 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,7 +5,7 @@ target = "thumbv7em-none-eabihf" git-fetch-with-cli = true [target.thumbv7em-none-eabihf] -runner = 'arm-none-eabi-gdb' +runner = 'gdb' rustflags = [ "-C", "link-arg=-Tlink.x", ] diff --git a/hal/Cargo.toml b/hal/Cargo.toml index f105468..6126c39 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -24,7 +24,9 @@ zeroize = { version = "1.7.0", default-features = false } bitvec = { version = "1.0.1", default-features = false } cortex-m-semihosting = "0.5.0" cortex-m = { version = "0.7.7" } +critical-section = "1.2.0" [features] rt = ["max78000/rt", "cortex-m-rt"] low_frequency = [] +flc-ram = [] diff --git a/hal/src/peripherals.rs b/hal/src/peripherals.rs index 9737db7..d0c65f5 100644 --- a/hal/src/peripherals.rs +++ b/hal/src/peripherals.rs @@ -43,6 +43,7 @@ use core::cell::{BorrowMutError, RefCell, RefMut}; use core::ops::{Deref, DerefMut}; use embedded_hal::i2c::SevenBitAddress; +#[cfg(feature = "flc-ram")] use crate::peripherals::flash_controller::FlashController; use crate::peripherals::i2c::{BusSpeed, I2CMaster, I2CSlave}; use crate::peripherals::oscillator::SystemClock; @@ -446,6 +447,7 @@ impl<'a, T: Oscillator + private::Oscillator, F: FnMut(&mut [u8])> PeripheralManager { power_ctrl, + #[cfg(feature = "flc-ram")] flash_controller: RefCell::new(FlashController::new( self.consumed_periphs.flc, &self.borrowed_periphs.icc0, @@ -508,6 +510,7 @@ macro_rules! enable_rst_periph_fn { /// The methods inside here can be used to interact with the board peripherals. pub struct PeripheralManager<'a> { power_ctrl: PowerControl<'a, 'a>, + #[cfg(feature = "flc-ram")] flash_controller: RefCell>, system_clock: RefCell>, gpio0: Gpio0, @@ -524,6 +527,7 @@ pub struct PeripheralManager<'a> { } impl<'a> PeripheralManager<'a> { + #[cfg(feature = "flc-ram")] no_enable_rst_periph_fn!(flash_controller, FlashController<'a, 'a>, flash_controller); no_enable_rst_periph_fn!(system_clock, SystemClock<'a, 'a>, system_clock); diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 324628d..2a207c8 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -1,36 +1,35 @@ +#![cfg(feature = "flc-ram")] //! Flash controller peripheral API. -use core::borrow::BorrowMut; - -/// # Examples -/// ``` -/// let flash_controller = FlashController::new(flc, icc0, gcr); -/// -/// let test_addr: u32 = 0x10070FF0; -/// let test_val: u32 = 0xCAFEBABE; -/// let mut data_read: [u8; 4] = [0; 4]; -/// -/// // # Safety -/// // Non-read flash operations must not corrupt potentially instructions of the -/// // program. -/// // Callers must ensure that the following condition is met: -/// // * If `address` points to a portion of the program's instructions, `data` must -/// // contain valid instructions that does not introduce undefined behavior. -/// // -/// // It is very difficult to define what would cause undefined behavior when -/// // modifying program instructions. This would almost certainly result -/// // in unwanted and likely undefined behavior. Do so at your own risk. -/// unsafe { -/// flash_controller.page_erase(test_addr, &sys_clk).unwrap(); -/// flash_controller -/// .write(test_addr, &u32::to_le_bytes(test_val), &sys_clk) -/// .unwrap(); -/// } -/// flash_controller -/// .read_bytes(test_addr, &mut data_read) -/// .unwrap(); -/// -/// assert!(u32::from_le_bytes(data_read) == test_val); -/// ``` +//! # Examples +//! ``` +//! let flash_controller = FlashController::new(flc, icc0, gcr); +//! +//! let test_addr: u32 = 0x10070FF0; +//! let test_val: u32 = 0xCAFEBABE; +//! let mut data_read: [u8; 4] = [0; 4]; +//! +//! // # Safety +//! // Non-read flash operations must not corrupt potentially instructions of the +//! // program. +//! // Callers must ensure that the following condition is met: +//! // * If `address` points to a portion of the program's instructions, `data` must +//! // contain valid instructions that does not introduce undefined behavior. +//! // +//! // It is very difficult to define what would cause undefined behavior when +//! // modifying program instructions. This would almost certainly result +//! // in unwanted and likely undefined behavior. Do so at your own risk. +//! unsafe { +//! flash_controller.page_erase(test_addr, &sys_clk).unwrap(); +//! flash_controller +//! .write(test_addr, &u32::to_le_bytes(test_val), &sys_clk) +//! .unwrap(); +//! } +//! flash_controller +//! .read_bytes(test_addr, &mut data_read) +//! .unwrap(); +//! +//! assert!(u32::from_le_bytes(data_read) == test_val); +//! ``` use crate::peripherals::oscillator::SystemClock; use max78000::{FLC, GCR, ICC0}; @@ -61,149 +60,94 @@ pub struct FlashController<'gcr, 'icc> { gcr: &'gcr GCR, } -impl<'gcr, 'icc> FlashController<'gcr, 'icc> { - /// Creates a new flash controller peripheral. - pub(crate) fn new(flc: FLC, icc: &'icc ICC0, gcr: &'gcr GCR) -> Self { - Self { flc, icc, gcr } - } - - /// Checks the address to see if it is a valid flash memory address - fn check_address_bounds(&self, address_range: core::ops::Range) -> Result<(), FlashErr> { - if (FLASH_MEM_BASE..(FLASH_MEM_BASE + FLASH_MEM_SIZE)).contains(&address_range.start) - && (FLASH_MEM_BASE..(FLASH_MEM_BASE + FLASH_MEM_SIZE)).contains(&address_range.end) - { - Ok(()) - } else { - Err(FlashErr::PtrBoundsErr) - } - } - - /// Unlocks memory protection to allow flash operations +unsafe extern "C" { + /// Reads a little-endian `u32` from flash memory. /// - /// This MUST be called before any non-read flash controller operation. - fn unlock_write_protection(&self) { - self.flc.ctrl().modify(|_, w| w.unlock().unlocked()); - } - - /// Locks memory protection. - /// - /// This MUST be called after any non-read flash controller operation. - fn lock_write_protection(&self) { - self.flc.ctrl().modify(|_, w| w.unlock().locked()); - } + /// Panics if any of the following preconditions are not true: + /// - `address` must be 32-bit aligned. + /// - `address` must point to a valid location in flash memory (`0x1000_0000..=0x1007_ffff`). + pub unsafe fn flc_read32_primitive(address: *const u32) -> u32; - /// Checks if the flash controller's clock divisor is correct and if not, sets it. Correct - /// clock frequency is 1 MHz. + /// Erases the page at the given address in flash memory. /// - /// This MUST be called before any non-read flash controller operations. - fn set_clock_divisor(&self, sys_clk: &SystemClock) -> Result<(), FlashErr> { - let sys_clk_freq = sys_clk.get_freq() / sys_clk.get_div() as u32; - if sys_clk_freq % 1_000_000 != 0 { - return Err(FlashErr::FlcClkErr); - } - - let flc_clkdiv = sys_clk_freq / 1_000_000; - - self.flc - .clkdiv() - .modify(|_, w| w.clkdiv().variant(flc_clkdiv as u8)); - - Ok(()) - } - - /// Busy loop until FLC is ready. - /// - /// This MUST be called BEFORE any FLC operation EXCEPT clearing interrupts. - fn wait_until_ready(&self) { - while !self.flc.ctrl().read().pend().bit_is_clear() {} - } - - /// Clear any stale errors in the FLC Interrupt Register + /// Safety: + /// - The caller must hold a shared reference to the [`FLC`], [`ICC0`], and [`GCR`] registers. + /// - `address` must point to a valid page within flash memory (`0x1000_0000..=0x1007_ffff`). + /// - `sys_clk_freq` must be equal to `freq / div` where `freq` is the frequency of + /// the current system clock, and `div` is the divider of the system clock. + /// - `sys_clk_freq` must be divisible by one million (`1_000_000`). + /// - If `address` erases a page in the currently-running program's instruction space, + /// it must be rewritten with [`write128`] before the program reaches those instructions. /// - /// This can be called without waiting for the FLC to be ready. - fn clear_interrupts(&self) { - self.flc.intr().modify(|_, w| w.af().clear_bit()); - } + /// Panics if any of the following preconditions are not true: + /// - `address` must point to within a valid page in flash space (`0x1000_000..=0x1007_ffff`) + /// - `sys_clk_freq` must be divisible by one million (`1_000_000`). + pub unsafe fn flc_page_erase_primitive(address: *mut u8, sys_clk_freq: u32); - /// Prepares the FLC for a write operation. + /// Writes a little-endian 128-bit flash word into flash memory. /// - /// Procedure: - /// - Wait until FLC ready - /// - Disable icc0 - /// - Clear FLC interrupts - /// - Set clock divisor - /// - Unlock write protection - /// - EXECUTE OPERATION (CLOSURE) - /// - Wait until FLC ready - /// - Lock write protection - /// - Flush ICC - /// - Enable icc0 - fn write_guard(&self, sys_clk: &SystemClock, operation: F) -> Result<(), FlashErr> { - // Pre-write - self.wait_until_ready(); - self.disable_icc0(); - self.clear_interrupts(); - self.set_clock_divisor(sys_clk)?; - self.unlock_write_protection(); - - operation(); - - // Post-write - self.wait_until_ready(); - self.lock_write_protection(); - self.flush_icc()?; - self.enable_icc0(); - - Ok(()) - } - - /// Flushes the flash line buffer and arm instruction cache. + /// Safety: + /// - The caller must hold a shared reference to the [`FLC`], [`ICC0`], and [`GCR`] registers. + /// - The flash word at `address` must be in the *erased* state (with [`page_erase`]). + /// - `data` must point to an array of four `u32`s. + /// - `sys_clk_freq` must be equal to `freq / div` where `freq` is the frequency of + /// the current system clock, and `div` is the divider of the system clock. + /// - If `address` writes to an address in the currently-running program's instruction space, + /// it must be valid instructions. /// - /// This MUST be called after any write/erase flash controller operations. - fn flush_icc(&self) -> Result<(), FlashErr> { - self.gcr.sysctrl().modify(|_, w| w.icc0_flush().flush()); - while !self.gcr.sysctrl().read().icc0_flush().bit_is_clear() {} - - // Clear the line fill buffer by reading 2 pages from flash - let ptr = FLASH_MEM_BASE; - let mut empty_buffer = [0; 4]; - self.read_bytes(ptr, &mut empty_buffer)?; - self.read_bytes(ptr + FLASH_PAGE_SIZE, &mut empty_buffer)?; + /// Panics if any of the following preconditions are not true: + /// - `address` must be 128-bit aligned. + /// - The entire flash word at address (bytes `address..address + 16`) must be within + /// the flash memory (`0x1000_0000..=0x1007_ffff`). + /// - `sys_clk_freq` must be divisible by one million (`1_000_000`). + pub unsafe fn flc_write128_primitive( + address: *mut [u32; 4], + data: *const u32, + sys_clk_freq: u32, + ); +} +/// Checks whether the given address range (exclusive) is within flash space, returning an `Err` if not. +#[inline(always)] +const fn check_address_bounds(address_range: core::ops::Range) -> Result<(), FlashErr> { + if !(FLASH_MEM_BASE <= address_range.start + && address_range.start < FLASH_MEM_BASE + FLASH_MEM_SIZE + && FLASH_MEM_BASE < address_range.end + && address_range.end <= FLASH_MEM_BASE + FLASH_MEM_SIZE) + { + Err(FlashErr::PtrBoundsErr) + } else { Ok(()) } +} - /// Disables instruction cache. - /// - /// This MUST be called before any non-read flash controller operations. - fn disable_icc0(&self) { - self.icc.ctrl().modify(|_, w| w.en().dis()); +impl<'gcr, 'icc> FlashController<'gcr, 'icc> { + /// Creates a new flash controller peripheral. + pub(crate) fn new(flc: FLC, icc: &'icc ICC0, gcr: &'gcr GCR) -> Self { + Self { flc, icc, gcr } } - /// Enables instruction cache. - /// - /// This MUST be called after any non-read flash controller operations. - fn enable_icc0(&self) { - // ensure the cache is invalidated when enabled - self.disable_icc0(); - - self.icc.invalidate().modify(|_, w| w.invalid().variant(1)); - while !self.icc.ctrl().read().rdy().bit_is_set() {} + /// Calculates the correct `sys_clk_freq` from the passed [`SystemClock`] for FLC primitives. + /// Returns an `Err` if the calculated frequency is not a multiple of `1_000_000`. + fn get_clock_divisor(sys_clk: &SystemClock) -> Result { + let sys_clk_freq = sys_clk.get_freq() / sys_clk.get_div() as u32; + if sys_clk_freq % 1_000_000 != 0 { + return Err(FlashErr::FlcClkErr); + } - self.icc.ctrl().modify(|_, w| w.en().en()); - while !self.icc.ctrl().read().rdy().bit_is_set() {} + Ok(sys_clk_freq) } /// Reads data from flash. - pub fn read_bytes(&self, address: u32, data: &mut [u8]) -> Result<(), FlashErr> { + pub fn read_bytes(address: u32, data: &mut [u8]) -> Result<(), FlashErr> { // change to range check - self.check_address_bounds(address..(address + data.len() as u32))?; + check_address_bounds(address..(address + data.len() as u32))?; let mut next_read_address = address; // read from flash in word chunks let mut word_chunk = data.chunks_exact_mut(4); - for word in word_chunk.borrow_mut() { + for word in &mut word_chunk { // SAFETY: // * src is valid for reads. Because read range is checked at the // beginning of function. @@ -258,7 +202,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { data: &[u8], sys_clk: &SystemClock, ) -> Result<(), FlashErr> { - self.check_address_bounds(address..(address + data.len() as u32))?; + check_address_bounds(address..(address + data.len() as u32))?; // Check alignment let mut physical_addr = address; @@ -324,7 +268,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { let aligned_addr = address & !0xF; let mut current_bytes: [u8; 16] = [0; 16]; - self.read_bytes(aligned_addr, &mut current_bytes[..])?; + Self::read_bytes(aligned_addr, &mut current_bytes[..])?; // construct 128 bits of data to write back to flash current_bytes[byte_idx..(byte_idx + data.len())].copy_from_slice(data); @@ -346,6 +290,9 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// /// # Safety /// + /// The flash word at `address` must be in the *erased* state. Otherwise, the write will not + /// occur. + /// /// Writes must not corrupt potentially executable instructions of the program. /// Callers must ensure that the following condition is met: /// * If `address` points to a portion of the program's instructions, `data` must @@ -364,19 +311,20 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { if address & 0xF > 0 { return Err(FlashErr::AddressNotAligned128); } - - self.write_guard(sys_clk, || { - self.flc.addr().modify(|_, w| w.addr().variant(address)); - self.flc.data(0).modify(|_, w| w.data().variant(data[0])); - self.flc.data(1).modify(|_, w| w.data().variant(data[1])); - self.flc.data(2).modify(|_, w| w.data().variant(data[2])); - self.flc.data(3).modify(|_, w| w.data().variant(data[3])); - - self.flc.ctrl().modify(|_, w| w.wr().set_bit()); - - // Wait until write completes - while !self.flc.ctrl().read().wr().is_complete() {} - })?; + check_address_bounds(address..address + 16)?; + + let sys_clk_freq = Self::get_clock_divisor(sys_clk)?; + + // SAFETY: per the safety contract of [`flc_write128_primitive`]: + // - we hold a reference (in `self`) to the FLC, ICC0, and GCR registers + // - the caller guarantees that the flash word at `address` in the erased state. + // - `data.as_ptr()` points to an array of 4 u32s. + // - `sys_clk_freq` is calculated as `freq / div` of the current system clock above + // - the caller must guarantee that, if the word at `address` is in instruction memory, + // it contains safe and valid instructions. + critical_section::with(|_| unsafe { + flc_write128_primitive(address as *mut [u32; 4], data.as_ptr(), sys_clk_freq); + }); Ok(()) } @@ -390,14 +338,16 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// Behavior is undefined if any of the following conditions are violated: /// * `address` must be in a valid flash page pub unsafe fn page_erase(&self, address: u32, sys_clk: &SystemClock) -> Result<(), FlashErr> { - self.check_address_bounds(address..address)?; - - self.write_guard(sys_clk, || { - self.flc.addr().modify(|_, w| w.addr().variant(address)); - - self.flc.ctrl().modify(|_, w| w.erase_code().erase_page()); - self.flc.ctrl().modify(|_, w| w.pge().set_bit()); - })?; + check_address_bounds(address..address + 1)?; + let sys_clk_freq = Self::get_clock_divisor(sys_clk)?; + + // SAFETY: per the safety contract of [`flc_page_erase_primitive`]: + // - we hold a reference (in `self`) to the FLC, ICC0, and GCR registers. + // - `sys_clk_freq` is calculated as `freq / div` of the current system clock above. + // - the caller guarantees safety if the erased page is part of instruction memory. + critical_section::with(|_| unsafe { + flc_page_erase_primitive(address as *mut u8, sys_clk_freq); + }); Ok(()) } diff --git a/hal/src/peripherals/oscillator.rs b/hal/src/peripherals/oscillator.rs index 6b82997..8913254 100644 --- a/hal/src/peripherals/oscillator.rs +++ b/hal/src/peripherals/oscillator.rs @@ -305,11 +305,13 @@ impl<'a, 'b> SystemClock<'a, 'b> { } /// Returns the clock divider of the SYS_OSC + #[inline(always)] pub fn get_div(&self) -> u8 { self.clock_divider } /// Returns the frequency of the SYS_OSC in hertz + #[inline(always)] pub fn get_freq(&self) -> u32 { self.clock_frequency } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index c4c7673..9c62f08 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -12,9 +12,15 @@ cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = { version = "0.7.3", features = ["set-sp", "set-vtor"] } cortex-m-semihosting = "0.5.0" libm = "0.2.8" -max78000-hal = { version = "0.1.0", path = "../hal", features = ["rt"] } +max78000-hal = { version = "0.1.0", path = "../hal", features = [ + "rt", + "flc-ram", +] } panic-semihosting = "0.6.0" -embedded-hal = { version = "1.0"} +embedded-hal = { version = "1.0" } [features] low_frequency_test = ["max78000-hal/low_frequency"] + +[build-dependencies] +cc = "1.2.16" diff --git a/tests/build.rs b/tests/build.rs index 90c6c1f..dc8a4e4 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -13,9 +13,24 @@ fn main() { .write_all(include_bytes!("memory.x")) .unwrap(); + // Put the link.x linker script somewhere the linker can find it. + File::create(out.join("link.x")) + .unwrap() + .write_all(include_bytes!("link.x")) + .unwrap(); + + let flc_asm_path = out.join("flc_asm.s"); + File::create(&flc_asm_path) + .unwrap() + .write_all(include_bytes!("flc_asm.s")) + .unwrap(); + + cc::Build::new().file(&flc_asm_path).compile("flc_asm"); + println!("cargo:rustc-link-arg=--nmagic"); // Only re-run the build script when this file, memory.x, or link.x is changed. println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=memory.x"); + println!("cargo:rerun-if-changed=link.x"); } diff --git a/tests/flc_asm.s b/tests/flc_asm.s new file mode 100644 index 0000000..62a1368 --- /dev/null +++ b/tests/flc_asm.s @@ -0,0 +1,562 @@ + .text + .syntax unified + .eabi_attribute 67, "2.09" + .eabi_attribute 6, 13 + .eabi_attribute 7, 77 + .eabi_attribute 8, 0 + .eabi_attribute 9, 2 + .fpu fpv4-sp-d16 + .eabi_attribute 27, 1 + .eabi_attribute 36, 1 + .eabi_attribute 34, 1 + .eabi_attribute 17, 1 + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 28, 1 + .eabi_attribute 38, 1 + .eabi_attribute 14, 0 + .file "flc_asm.c1ff00fd3aa9b52e-cgu.0" + .section .analogsucks,"ax",%progbits + .globl flc_read32_primitive + .p2align 2 + .type flc_read32_primitive,%function + .code 16 + .thumb_func +flc_read32_primitive: +.Lfunc_begin0: + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .save {r7, lr} + push {r7, lr} + .cfi_def_cfa_offset 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .setfp r7, sp + mov r7, sp + .cfi_def_cfa_register r7 + lsls r1, r0, #30 + ittt eq + moveq r1, r0 + bfceq r1, #0, #19 + cmpeq.w r1, #268435456 + bne .LBB0_2 + ldr r1, .LCPI0_0 + add r1, r0 + cmp.w r1, #524288 + itt lo + ldrlo r0, [r0] + poplo {r7, pc} +.LBB0_2: + bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E + .p2align 2 +.LCPI0_0: + .long 4026531843 +.Lfunc_end0: + .size flc_read32_primitive, .Lfunc_end0-flc_read32_primitive + .cfi_endproc + .cantunwind + .fnend + + .globl flc_write128_primitive + .p2align 2 + .type flc_write128_primitive,%function + .code 16 + .thumb_func +flc_write128_primitive: +.Lfunc_begin1: + .fnstart + .cfi_startproc + .save {r4, r5, r6, r7, lr} + push {r4, r5, r6, r7, lr} + .cfi_def_cfa_offset 20 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .cfi_offset r6, -12 + .cfi_offset r5, -16 + .cfi_offset r4, -20 + .setfp r7, sp, #12 + add r7, sp, #12 + .cfi_def_cfa r7, 8 + .save {r11} + str r11, [sp, #-4]! + .cfi_offset r11, -24 + .pad #8 + sub sp, #8 + mov r3, r0 + bfc r3, #0, #19 + cmp.w r3, #268435456 + bne .LBB1_16 + ldr r3, .LCPI1_0 + add r3, r0 + cmp.w r3, #524288 + bhs .LBB1_16 + lsls r3, r0, #28 + bne .LBB1_16 + ldr r4, .LCPI1_1 +.LBB1_4: + ldr r3, [r4, #8] + lsls r3, r3, #7 + bmi .LBB1_4 + ldr r3, .LCPI1_2 + ldr r6, .LCPI1_4 + ldr r5, [r3] + bic r5, r5, #1 + str r5, [r3] + ldr r5, [r4, #36] + bic r5, r5, #2 + str r5, [r4, #36] + ldr r5, .LCPI1_3 + udiv r5, r2, r5 + muls r6, r5, r6 + cmn r6, r2 + bne .LBB1_16 + ldr r2, [r4, #4] + bfi r2, r5, #0, #8 + str r2, [r4, #4] + ldr r2, [r4, #8] + movs r5, #2 + bfi r2, r5, #28, #4 + str r2, [r4, #8] + ldr r2, [r4] + str r0, [r4] + ldr r0, [r4, #48] + ldr r0, [r1] + str r0, [r4, #48] + ldr r0, [r4, #52] + ldr r0, [r1, #4] + str r0, [r4, #52] + ldr r0, [r4, #56] + ldr r0, [r1, #8] + str r0, [r4, #56] + ldr r0, [r4, #60] + ldr r0, [r1, #12] + str r0, [r4, #60] + ldr r0, [r4, #8] + orr r0, r0, #1 + str r0, [r4, #8] +.LBB1_7: + ldr r0, [r4, #8] + lsls r0, r0, #31 + bne .LBB1_7 +.LBB1_8: + ldr r0, [r4, #8] + lsls r0, r0, #7 + bmi .LBB1_8 + ldr r0, [r4, #8] + movs r1, #3 + bfi r0, r1, #28, #4 + str r0, [r4, #8] + mov.w r0, #1073741824 + ldr r1, [r0] + orr r1, r1, #64 + str r1, [r0] +.LBB1_10: + ldr r1, [r0] + lsls r1, r1, #25 + bmi .LBB1_10 + mov.w r0, #268435456 + ldr r0, [r0] + str r0, [sp] + mov r0, sp + @APP + @NO_APP + ldr r0, .LCPI1_5 + ldr r0, [r0] + str r0, [sp, #4] + add r0, sp, #4 + @APP + @NO_APP + ldr r0, [r3] + bic r0, r0, #1 + str r0, [r3] + ldr.w r0, [r3, #1536] + movs r0, #1 + str.w r0, [r3, #1536] +.LBB1_12: + ldr r0, [r3] + lsls r0, r0, #15 + bpl .LBB1_12 + ldr r0, [r3] + orr r0, r0, #1 + str r0, [r3] +.LBB1_14: + ldr r0, [r3] + lsls r0, r0, #15 + bpl .LBB1_14 + add sp, #8 + ldr r11, [sp], #4 + pop {r4, r5, r6, r7, pc} +.LBB1_16: + bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E + .p2align 2 +.LCPI1_0: + .long 4026531855 +.LCPI1_1: + .long 1073909760 +.LCPI1_2: + .long 1073914112 +.LCPI1_3: + .long 1000000 +.LCPI1_4: + .long 4293967296 +.LCPI1_5: + .long 268443648 +.Lfunc_end1: + .size flc_write128_primitive, .Lfunc_end1-flc_write128_primitive + .cfi_endproc + .cantunwind + .fnend + + .globl flc_page_erase_primitive + .p2align 2 + .type flc_page_erase_primitive,%function + .code 16 + .thumb_func +flc_page_erase_primitive: +.Lfunc_begin2: + .fnstart + .cfi_startproc + .save {r4, r5, r7, lr} + .pad #8 + push {r2, r3, r4, r5, r7, lr} + .cfi_def_cfa_offset 24 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .cfi_offset r5, -12 + .cfi_offset r4, -16 + .setfp r7, sp, #16 + add r7, sp, #16 + .cfi_def_cfa r7, 8 + mov r2, r0 + bfc r2, #0, #19 + cmp.w r2, #268435456 + bne .LBB2_13 + ldr r3, .LCPI2_0 +.LBB2_2: + ldr r2, [r3, #8] + lsls r2, r2, #7 + bmi .LBB2_2 + ldr r2, .LCPI2_1 + ldr r5, .LCPI2_3 + ldr r4, [r2] + bic r4, r4, #1 + str r4, [r2] + ldr r4, [r3, #36] + bic r4, r4, #2 + str r4, [r3, #36] + ldr r4, .LCPI2_2 + udiv r4, r1, r4 + muls r5, r4, r5 + cmn r5, r1 + bne .LBB2_13 + ldr r1, [r3, #4] + bfi r1, r4, #0, #8 + str r1, [r3, #4] + ldr r1, [r3, #8] + movs r4, #2 + bfi r1, r4, #28, #4 + str r1, [r3, #8] + ldr r1, [r3] + str r0, [r3] + movs r1, #85 + ldr r0, [r3, #8] + bfi r0, r1, #8, #8 + str r0, [r3, #8] + ldr r0, [r3, #8] + orr r0, r0, #4 + str r0, [r3, #8] +.LBB2_5: + ldr r0, [r3, #8] + lsls r0, r0, #7 + bmi .LBB2_5 + ldr r0, [r3, #8] + movs r1, #3 + bfi r0, r1, #28, #4 + str r0, [r3, #8] + mov.w r0, #1073741824 + ldr r1, [r0] + orr r1, r1, #64 + str r1, [r0] +.LBB2_7: + ldr r1, [r0] + lsls r1, r1, #25 + bmi .LBB2_7 + mov.w r0, #268435456 + ldr r0, [r0] + str r0, [sp] + mov r0, sp + @APP + @NO_APP + ldr r0, .LCPI2_4 + ldr r0, [r0] + str r0, [sp, #4] + add r0, sp, #4 + @APP + @NO_APP + ldr r0, [r2] + bic r0, r0, #1 + str r0, [r2] + ldr.w r0, [r2, #1536] + movs r0, #1 + str.w r0, [r2, #1536] +.LBB2_9: + ldr r0, [r2] + lsls r0, r0, #15 + bpl .LBB2_9 + ldr r0, [r2] + orr r0, r0, #1 + str r0, [r2] +.LBB2_11: + ldr r0, [r2] + lsls r0, r0, #15 + bpl .LBB2_11 + pop {r2, r3, r4, r5, r7, pc} +.LBB2_13: + bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E + .p2align 2 +.LCPI2_0: + .long 1073909760 +.LCPI2_1: + .long 1073914112 +.LCPI2_2: + .long 1000000 +.LCPI2_3: + .long 4293967296 +.LCPI2_4: + .long 268443648 +.Lfunc_end2: + .size flc_page_erase_primitive, .Lfunc_end2-flc_page_erase_primitive + .cfi_endproc + .cantunwind + .fnend + + .section .text.unlikely._ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E,"ax",%progbits + .p2align 1 + .type _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E,%function + .code 16 + .thumb_func +_ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E: +.Lfunc_begin3: + .fnstart + .cfi_startproc + .save {r7, lr} + push {r7, lr} + .cfi_def_cfa_offset 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .setfp r7, sp + mov r7, sp + .cfi_def_cfa_register r7 + bl _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE +.Lfunc_end3: + .size _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E, .Lfunc_end3-_ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E + .cfi_endproc + .cantunwind + .fnend + + .section .text.unlikely._ZN4core9panicking9panic_fmt17haebed1323d60a452E,"ax",%progbits + .p2align 1 + .type _ZN4core9panicking9panic_fmt17haebed1323d60a452E,%function + .code 16 + .thumb_func +_ZN4core9panicking9panic_fmt17haebed1323d60a452E: +.Lfunc_begin4: + .file 1 "/rustc/bef3c3b01f690de16738b1c9f36470fbfc6ac623" "library/core/src/panicking.rs" + .loc 1 55 0 + .fnstart + .cfi_startproc + .save {r7, lr} + push {r7, lr} + .cfi_def_cfa_offset 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .setfp r7, sp + mov r7, sp + .cfi_def_cfa_register r7 +.Ltmp0: + .loc 1 75 14 prologue_end + @APP +.Ltmp1: + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + @NO_APP + .inst.n 0xdefe +.Ltmp2: +.Lfunc_end4: + .size _ZN4core9panicking9panic_fmt17haebed1323d60a452E, .Lfunc_end4-_ZN4core9panicking9panic_fmt17haebed1323d60a452E + .cfi_endproc + .cantunwind + .fnend + + .section .text.unlikely._ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE,"ax",%progbits + .p2align 1 + .type _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE,%function + .code 16 + .thumb_func +_ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE: +.Lfunc_begin5: + .loc 1 233 0 + .fnstart + .cfi_startproc + .save {r7, lr} + push {r7, lr} + .cfi_def_cfa_offset 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .setfp r7, sp + mov r7, sp + .cfi_def_cfa_register r7 +.Ltmp3: + .loc 1 261 5 prologue_end + bl _ZN4core9panicking9panic_fmt17haebed1323d60a452E +.Ltmp4: +.Lfunc_end5: + .size _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE, .Lfunc_end5-_ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE + .cfi_endproc + .cantunwind + .fnend + + .section .debug_info,"",%progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 +.Ldebug_info_start0: + .short 4 + .long .debug_abbrev + .byte 4 + .byte 1 + .long .Linfo_string0 + .short 28 + .long .Linfo_string1 + .long .Lline_table_start0 + .long .Linfo_string2 + .long 0 + .long .Ldebug_ranges0 + .byte 2 + .long .Linfo_string3 + .byte 2 + .long .Linfo_string4 + .byte 3 + .long .Lfunc_begin4 + .long .Lfunc_end4-.Lfunc_begin4 + .byte 1 + .byte 87 + .long .Linfo_string7 + .long .Linfo_string8 + .byte 1 + .byte 55 + + + .byte 4 + .long .Linfo_string5 + .long .Linfo_string6 + .byte 1 + .short 260 + + .byte 1 + .byte 5 + .long .Lfunc_begin5 + .long .Lfunc_end5-.Lfunc_begin5 + .byte 1 + .byte 87 + .long .Linfo_string9 + .long .Linfo_string10 + .byte 1 + .byte 233 + + + .byte 6 + .long 69 + .long .Ltmp3 + .long .Ltmp4-.Ltmp3 + .byte 1 + .byte 234 + .byte 5 + .byte 0 + .byte 0 + .byte 0 + .byte 0 +.Ldebug_info_end0: + .section .text.unlikely._ZN4core9panicking9panic_fmt17haebed1323d60a452E,"ax",%progbits +.Lsec_end0: + .section .text.unlikely._ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE,"ax",%progbits +.Lsec_end1: + .section .debug_aranges,"",%progbits + .long 36 + .short 2 + .long .Lcu_begin0 + .byte 4 + .byte 0 + .zero 4,255 + .long .Lfunc_begin4 + .long .Lsec_end0-.Lfunc_begin4 + .long .Lfunc_begin5 + .long .Lsec_end1-.Lfunc_begin5 + .long 0 + .long 0 + .section .debug_ranges,"",%progbits +.Ldebug_ranges0: + .long .Lfunc_begin4 + .long .Lfunc_end4 + .long .Lfunc_begin5 + .long .Lfunc_end5 + .long 0 + .long 0 + .section .debug_str,"MS",%progbits,1 +.Linfo_string0: + .asciz "clang LLVM (rustc version 1.86.0-nightly (bef3c3b01 2025-02-04))" +.Linfo_string1: + .asciz "library/core/src/lib.rs/@/core.42399d673965ec88-cgu.0" +.Linfo_string2: + .asciz "/rustc/bef3c3b01f690de16738b1c9f36470fbfc6ac623" +.Linfo_string3: + .asciz "core" +.Linfo_string4: + .asciz "panicking" +.Linfo_string5: + .asciz "_ZN4core9panicking13panic_display17hb27badd535428c70E" +.Linfo_string6: + .asciz "panic_display<&str>" +.Linfo_string7: + .asciz "_ZN4core9panicking9panic_fmt17haebed1323d60a452E" +.Linfo_string8: + .asciz "panic_fmt" +.Linfo_string9: + .asciz "_ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE" +.Linfo_string10: + .asciz "panic_explicit" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .section ".note.GNU-stack","",%progbits + .section .debug_line,"",%progbits +.Lline_table_start0: diff --git a/tests/link.x b/tests/link.x new file mode 100644 index 0000000..3c06479 --- /dev/null +++ b/tests/link.x @@ -0,0 +1,293 @@ + +/* # Developer notes + +- Symbols that start with a double underscore (__) are considered "private" + +- Symbols that start with a single underscore (_) are considered "semi-public"; they can be + overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { + static mut __sbss }`). + +- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a + symbol is not dropped if it appears in or near the front of the linker arguments and "it's not + needed" by any of the preceding objects (linker arguments) + +- `PROVIDE` is used to provide default values that can be overridden by a user linker script + +- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* + the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization + routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see + "Address (..) is out of bounds" in the disassembly produced by `objdump`. +*/ + +/* Provides information about the memory layout of the device */ +/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ +INCLUDE memory.x +INCLUDE device.x + +/* # Entry point = reset vector */ +EXTERN(__RESET_VECTOR); +EXTERN(Reset); +ENTRY(Reset); + +/* # Exception vectors */ +/* This is effectively weak aliasing at the linker level */ +/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. + the `exception!` macro) */ +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ + +EXTERN(DefaultHandler); + +PROVIDE(NonMaskableInt = DefaultHandler); +EXTERN(HardFaultTrampoline); +PROVIDE(MemoryManagement = DefaultHandler); +PROVIDE(BusFault = DefaultHandler); +PROVIDE(UsageFault = DefaultHandler); +PROVIDE(SecureFault = DefaultHandler); +PROVIDE(SVCall = DefaultHandler); +PROVIDE(DebugMonitor = DefaultHandler); +PROVIDE(PendSV = DefaultHandler); +PROVIDE(SysTick = DefaultHandler); + +PROVIDE(DefaultHandler = DefaultHandler_); +PROVIDE(HardFault = HardFault_); + +/* # Interrupt vectors */ +EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ + +/* # Pre-initialization function */ +/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, + then the function this points to will be called before the RAM is initialized. */ +PROVIDE(__pre_init = DefaultPreInit); + +/* # Sections */ +SECTIONS +{ + PROVIDE(_ram_start = ORIGIN(RAM)); + PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM)); + PROVIDE(_stack_start = _ram_end); + + /* ## Sections in FLASH */ + /* ### Vector table */ + .vector_table ORIGIN(FLASH) : + { + __vector_table = .; + + /* Initial Stack Pointer (SP) value. + * We mask the bottom three bits to force 8-byte alignment. + * Despite having an assert for this later, it's possible that a separate + * linker script could override _stack_start after the assert is checked. + */ + LONG(_stack_start & 0xFFFFFFF8); + + /* Reset vector */ + KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ + + /* Exceptions */ + __exceptions = .; /* start of exceptions */ + KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ + __eexceptions = .; /* end of exceptions */ + + /* Device specific interrupts */ + KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ + } > FLASH + + PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); + + /* ### .text */ + .text _stext : + { + __stext = .; + *(.Reset); + + *(.text .text.*); + + /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, + so must be placed close to it. */ + *(.HardFaultTrampoline); + *(.HardFault.*); + + . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ + __etext = .; + } > FLASH + + /* ### .rodata */ + .rodata : ALIGN(4) + { + . = ALIGN(4); + __srodata = .; + *(.rodata .rodata.*); + + /* 4-byte align the end (VMA) of this section. + This is required by LLD to ensure the LMA of the following .data + section will have the correct alignment. */ + . = ALIGN(4); + __erodata = .; + } > FLASH + + /* Add a section for the FLC function operations */ + .analogsucks : ALIGN(4) + { + . = ALIGN(4); + __sanalogsucks = .; + *(.analogsucks .analogsucks.*); + . = ALIGN(4); + __eanalogsucks = .; + } > ANALOGSUCKS AT>FLASH + + /* ## Sections in RAM */ + /* ### .data */ + .data : ALIGN(4) + { + . = ALIGN(4); + __sdata = .; + *(.data .data.*); + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + } > RAM AT>FLASH + /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to + * use the .data loading mechanism by pushing __edata. Note: do not change + * output region or load region in those user sections! */ + . = ALIGN(4); + __edata = .; + + /* LMA of .data */ + __sidata = LOADADDR(.data); + + __sianalogsucks = LOADADDR(.analogsucks); + + /* ### .gnu.sgstubs + This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ + /* Security Attribution Unit blocks must be 32 bytes aligned. */ + /* Note that this pads the FLASH usage to 32 byte alignment. */ + .gnu.sgstubs : ALIGN(32) + { + . = ALIGN(32); + __veneer_base = .; + *(.gnu.sgstubs*) + . = ALIGN(32); + } > FLASH + /* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are + * always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol. + */ + . = ALIGN(32); + __veneer_limit = .; + + /* ### .bss */ + .bss (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + __sbss = .; + *(.bss .bss.*); + *(COMMON); /* Uninitialized C statics */ + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + } > RAM + /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to + * use the .bss zeroing mechanism by pushing __ebss. Note: do not change + * output region or load region in those user sections! */ + . = ALIGN(4); + __ebss = .; + + /* ### .uninit */ + .uninit (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + __suninit = .; + *(.uninit .uninit.*); + . = ALIGN(4); + __euninit = .; + } > RAM + + /* Place the heap right after `.uninit` in RAM */ + PROVIDE(__sheap = __euninit); + + /* Place stack end at the end of allocated RAM */ + PROVIDE(_stack_end = __euninit); + + /* ## .got */ + /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in + the input files and raise an error if relocatable code is found */ + .got (NOLOAD) : + { + KEEP(*(.got .got.*)); + } + + /* ## Discarded sections */ + /DISCARD/ : + { + /* Unused exception related info that only wastes space */ + *(.ARM.exidx); + *(.ARM.exidx.*); + *(.ARM.extab.*); + } +} + +/* Do not exceed this mark in the error messages below | */ +/* # Alignment checks */ +ASSERT(ORIGIN(FLASH) % 4 == 0, " +ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); + +ASSERT(ORIGIN(RAM) % 4 == 0, " +ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); + +ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " +BUG(cortex-m-rt): .data is not 4-byte aligned"); + +ASSERT(__sidata % 4 == 0, " +BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); + +ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " +BUG(cortex-m-rt): .bss is not 4-byte aligned"); + +ASSERT(__sheap % 4 == 0, " +BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); + +ASSERT(_stack_start % 8 == 0, " +ERROR(cortex-m-rt): stack start address is not 8-byte aligned. +If you have set _stack_start, check it's set to an address which is a multiple of 8 bytes. +If you haven't, stack starts at the end of RAM by default. Check that both RAM +origin and length are set to multiples of 8 in the `memory.x` file."); + +ASSERT(_stack_end % 4 == 0, " +ERROR(cortex-m-rt): end of stack is not 4-byte aligned"); + +ASSERT(_stack_start >= _stack_end, " +ERROR(cortex-m-rt): stack end address is not below stack start."); + +/* # Position checks */ + +/* ## .vector_table + * + * If the *start* of exception vectors is not 8 bytes past the start of the + * vector table, then we somehow did not place the reset vector, which should + * live 4 bytes past the start of the vector table. + */ +ASSERT(__exceptions == ADDR(.vector_table) + 0x8, " +BUG(cortex-m-rt): the reset vector is missing"); + +ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " +BUG(cortex-m-rt): the exception vectors are missing"); + +ASSERT(SIZEOF(.vector_table) > 0x40, " +ERROR(cortex-m-rt): The interrupt vectors are missing. +Possible solutions, from most likely to less likely: +- Link to a svd2rust generated device crate +- Check that you actually use the device/hal/bsp crate in your code +- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency +may be enabling it) +- Supply the interrupt handlers yourself. Check the documentation for details."); + +/* ## .text */ +ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " +ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section +Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); + +ASSERT(_stext >= ORIGIN(FLASH) && _stext < ORIGIN(FLASH) + LENGTH(FLASH), " +ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. +Set _stext to an address within the FLASH region."); + +/* # Other checks */ +ASSERT(SIZEOF(.got) == 0, " +ERROR(cortex-m-rt): .got section detected in the input object files +Dynamic relocations are not supported. If you are linking to C code compiled using +the 'cc' crate then modify your build script to compile the C code _without_ +the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); +/* Do not exceed this mark in the error messages above | */ diff --git a/tests/memory.x b/tests/memory.x index 50aa495..c79c034 100644 --- a/tests/memory.x +++ b/tests/memory.x @@ -2,7 +2,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K - RAM (rw) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 128K - LENGTH(STACK) + ANALOGSUCKS (rx) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 10K + RAM (rw) : ORIGIN = ORIGIN(ANALOGSUCKS) + LENGTH(ANALOGSUCKS), LENGTH = 128K - LENGTH(STACK) - LENGTH(ANALOGSUCKS) } _stack_start = ORIGIN(STACK) + LENGTH(STACK); diff --git a/tests/run.sh b/tests/run.sh index a1eb710..e9dda83 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -12,7 +12,7 @@ if [ -z "$SERIAL" ]; then fi # Open GDB server with OpenOCD using the board's config. -/opt/MaximSDK/Tools/OpenOCD/openocd -s /opt/MaximSDK/Tools/OpenOCD/scripts \ +openocd \ -f interface/cmsis-dap.cfg \ -f target/max78000.cfg \ -c "adapter serial $SERIAL; init; reset init" & # ben's board diff --git a/tests/src/main.rs b/tests/src/main.rs index fadb25b..38eb98b 100644 --- a/tests/src/main.rs +++ b/tests/src/main.rs @@ -6,7 +6,7 @@ use core::fmt::Write; -use cortex_m_rt::entry; +use cortex_m_rt::{entry, pre_init}; use cortex_m_semihosting::hio; use max78000_hal::{ max78000::Peripherals, @@ -30,6 +30,23 @@ pub const TIMER_0_OSC: Oscillator = Oscillator::ERTCO; /// Prescaler to use for TMR0 during tests pub const TIMER_0_PRESCALER: Prescaler = Prescaler::_1; +#[pre_init] +unsafe fn pre_init() { + // load the .analogsucks section into memory + core::arch::asm! { + "ldr r0, =__sanalogsucks + ldr r1, =__eanalogsucks + ldr r2, =__sianalogsucks + 0: + cmp r1, r0 + beq 1f + ldm r2!, {{r3}} + stm r0!, {{r3}} + b 0b + 1:" + } +} + /// Entry point for tests. #[entry] fn main() -> ! { diff --git a/tests/src/tests/flc_tests.rs b/tests/src/tests/flc_tests.rs index 0534520..2ddd040 100644 --- a/tests/src/tests/flc_tests.rs +++ b/tests/src/tests/flc_tests.rs @@ -90,9 +90,7 @@ fn flash_write(flash_controller: &FlashController, sys_clk: &SystemClock) { flash_controller .write(test_addr, &u32::to_le_bytes(test_val), sys_clk) .unwrap(); - flash_controller - .read_bytes(test_addr, &mut data_read) - .unwrap(); + FlashController::read_bytes(test_addr, &mut data_read).unwrap(); } assert!(u32::from_le_bytes(data_read) == test_val); @@ -108,9 +106,7 @@ fn flash_write_large(flash_controller: &FlashController, sys_clk: &SystemClock) flash_controller .write(test_addr, &test_data, sys_clk) .unwrap(); - flash_controller - .read_bytes(test_addr, &mut read_data) - .unwrap(); + FlashController::read_bytes(test_addr, &mut read_data).unwrap(); } assert!(test_data == read_data); @@ -126,9 +122,7 @@ fn flash_write_extra_large(flash_controller: &FlashController, sys_clk: &SystemC flash_controller .write(test_addr, &test_data, sys_clk) .unwrap(); - flash_controller - .read_bytes(test_addr, &mut read_data) - .unwrap(); + FlashController::read_bytes(test_addr, &mut read_data).unwrap(); } assert!(test_data == read_data); @@ -144,9 +138,7 @@ fn flash_write_unaligned(flash_controller: &FlashController, sys_clk: &SystemClo flash_controller .write(test_addr, &test_data, sys_clk) .unwrap(); - flash_controller - .read_bytes(test_addr, &mut read_data) - .unwrap(); + FlashController::read_bytes(test_addr, &mut read_data).unwrap(); } assert!(test_data == read_data); @@ -177,9 +169,7 @@ fn flash_write_after_sys_osc_switch(flash_controller: &FlashController, sys_clk: flash_controller .write(test_addr, test_data, sys_clk) .unwrap(); - flash_controller - .read_bytes(test_addr, &mut read_data) - .unwrap(); + FlashController::read_bytes(test_addr, &mut read_data).unwrap(); } assert!(test_data == read_data); @@ -199,9 +189,7 @@ fn flash_write_after_sys_clk_div_changes( flash_controller .write(test_addr, test_data, sys_clk) .unwrap(); - flash_controller - .read_bytes(test_addr, &mut read_data) - .unwrap(); + FlashController::read_bytes(test_addr, &mut read_data).unwrap(); } assert!(test_data == read_data); From 78426753669182e49eba95ea9203faee030a7aec Mon Sep 17 00:00:00 2001 From: m Date: Sun, 2 Mar 2025 17:53:41 -0800 Subject: [PATCH 09/32] move flc logic into hal --- hal/Cargo.toml | 5 +- hal/build.rs | 16 ++ {tests => hal}/flc_asm.s | 0 hal/src/lib.rs | 53 ++++- hal/src/peripherals/flash_controller.rs | 12 + link.x.example | 293 ++++++++++++++++++++++++ memory.x.example | 10 + tests/build.rs | 14 -- tests/src/main.rs | 19 +- 9 files changed, 388 insertions(+), 34 deletions(-) create mode 100644 hal/build.rs rename {tests => hal}/flc_asm.s (100%) create mode 100644 link.x.example create mode 100644 memory.x.example diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 6126c39..7d3ee21 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -29,4 +29,7 @@ critical-section = "1.2.0" [features] rt = ["max78000/rt", "cortex-m-rt"] low_frequency = [] -flc-ram = [] +flc-ram = ["rt"] + +[build-dependencies] +cc = "1.2.16" diff --git a/hal/build.rs b/hal/build.rs new file mode 100644 index 0000000..11ee9aa --- /dev/null +++ b/hal/build.rs @@ -0,0 +1,16 @@ +use std::{env, fs::File, io::Write, path::PathBuf}; + +fn main() { + let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + let flc_asm_path = out.join("flc_asm.s"); + File::create(&flc_asm_path) + .unwrap() + .write_all(include_bytes!("flc_asm.s")) + .unwrap(); + + cc::Build::new().file(&flc_asm_path).compile("flc_asm"); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=flc_asm.s"); +} diff --git a/tests/flc_asm.s b/hal/flc_asm.s similarity index 100% rename from tests/flc_asm.s rename to hal/flc_asm.s diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 9c6e9b7..b42475d 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,4 +1,36 @@ //! A HAL for the Analog Devices MAX78000. +//! +//! # Runtime +//! +//! If the `rt` feature is enabled, this crate uses the runtime of the [`cortex_m_rt`] +//! crate. Note that the HAL uses the [`pre_init`] hook internally, and it is not possible +//! for users of the hal to specify their own `pre_init` routine. +//! +//! # Flash Controller +//! +//! If the `flc-ram` feature is enabled, this crate will expose the [`FlashController`] +//! peripheral. Certain routines for flash operations need to be located in RAM (instead +//! of flash memory), so users of this feature will need to add the following section to +//! their linker script `link.x`: +//! +//! ```ld +//! .analogsucks : ALIGN(4) +//! { +//! . = ALIGN(4); +//! __sanalogsucks = .; +//! *(.analogsucks .analogsucks.*); +//! } > ANALOGSUCKS +//! . = ALIGN(4); +//! __eanalogsucks = .; +//! } > ANALOGSUCKS AT>FLASH +//! +//! __sianalogsucks = LOADADDR(.analogsucks); +//! ``` +//! +//! where the `ANALOGSUCKS` is a memory section in RAM defined in `memory.x`. +//! +//! [`pre_init`]: cortex_m_rt::pre_init +//! [`FlashController`]: peripherals::FlashController #![warn(missing_docs)] #![no_std] @@ -9,7 +41,26 @@ pub use max78000; pub use self::max78000::Interrupt as interrupt; #[cfg(feature = "rt")] -pub use cortex_m_rt::interrupt; +pub use cortex_m_rt::{interrupt, pre_init}; pub mod communication; pub mod peripherals; + +#[cfg(feature = "rt")] +#[pre_init] +unsafe fn pre_init() { + // load the .analogsucks section into memory + #[cfg(feature = "flc-ram")] + core::arch::asm! { + "ldr r0, =__sanalogsucks + ldr r1, =__eanalogsucks + ldr r2, =__sianalogsucks + 0: + cmp r1, r0 + beq 1f + ldm r2!, {{r3}} + stm r0!, {{r3}} + b 0b + 1:" + } +} diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 2a207c8..ea290bf 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -55,8 +55,20 @@ pub enum FlashErr { /// Flash Controller peripheral. pub struct FlashController<'gcr, 'icc> { + #[expect( + unused, + reason = "the unsafe functions we call require us to hold references to these registers" + )] flc: FLC, + #[expect( + unused, + reason = "the unsafe functions we call require us to hold references to these registers" + )] icc: &'icc ICC0, + #[expect( + unused, + reason = "the unsafe functions we call require us to hold references to these registers" + )] gcr: &'gcr GCR, } diff --git a/link.x.example b/link.x.example new file mode 100644 index 0000000..3c06479 --- /dev/null +++ b/link.x.example @@ -0,0 +1,293 @@ + +/* # Developer notes + +- Symbols that start with a double underscore (__) are considered "private" + +- Symbols that start with a single underscore (_) are considered "semi-public"; they can be + overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { + static mut __sbss }`). + +- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a + symbol is not dropped if it appears in or near the front of the linker arguments and "it's not + needed" by any of the preceding objects (linker arguments) + +- `PROVIDE` is used to provide default values that can be overridden by a user linker script + +- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* + the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization + routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see + "Address (..) is out of bounds" in the disassembly produced by `objdump`. +*/ + +/* Provides information about the memory layout of the device */ +/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ +INCLUDE memory.x +INCLUDE device.x + +/* # Entry point = reset vector */ +EXTERN(__RESET_VECTOR); +EXTERN(Reset); +ENTRY(Reset); + +/* # Exception vectors */ +/* This is effectively weak aliasing at the linker level */ +/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. + the `exception!` macro) */ +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ + +EXTERN(DefaultHandler); + +PROVIDE(NonMaskableInt = DefaultHandler); +EXTERN(HardFaultTrampoline); +PROVIDE(MemoryManagement = DefaultHandler); +PROVIDE(BusFault = DefaultHandler); +PROVIDE(UsageFault = DefaultHandler); +PROVIDE(SecureFault = DefaultHandler); +PROVIDE(SVCall = DefaultHandler); +PROVIDE(DebugMonitor = DefaultHandler); +PROVIDE(PendSV = DefaultHandler); +PROVIDE(SysTick = DefaultHandler); + +PROVIDE(DefaultHandler = DefaultHandler_); +PROVIDE(HardFault = HardFault_); + +/* # Interrupt vectors */ +EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ + +/* # Pre-initialization function */ +/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, + then the function this points to will be called before the RAM is initialized. */ +PROVIDE(__pre_init = DefaultPreInit); + +/* # Sections */ +SECTIONS +{ + PROVIDE(_ram_start = ORIGIN(RAM)); + PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM)); + PROVIDE(_stack_start = _ram_end); + + /* ## Sections in FLASH */ + /* ### Vector table */ + .vector_table ORIGIN(FLASH) : + { + __vector_table = .; + + /* Initial Stack Pointer (SP) value. + * We mask the bottom three bits to force 8-byte alignment. + * Despite having an assert for this later, it's possible that a separate + * linker script could override _stack_start after the assert is checked. + */ + LONG(_stack_start & 0xFFFFFFF8); + + /* Reset vector */ + KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ + + /* Exceptions */ + __exceptions = .; /* start of exceptions */ + KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ + __eexceptions = .; /* end of exceptions */ + + /* Device specific interrupts */ + KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ + } > FLASH + + PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); + + /* ### .text */ + .text _stext : + { + __stext = .; + *(.Reset); + + *(.text .text.*); + + /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, + so must be placed close to it. */ + *(.HardFaultTrampoline); + *(.HardFault.*); + + . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ + __etext = .; + } > FLASH + + /* ### .rodata */ + .rodata : ALIGN(4) + { + . = ALIGN(4); + __srodata = .; + *(.rodata .rodata.*); + + /* 4-byte align the end (VMA) of this section. + This is required by LLD to ensure the LMA of the following .data + section will have the correct alignment. */ + . = ALIGN(4); + __erodata = .; + } > FLASH + + /* Add a section for the FLC function operations */ + .analogsucks : ALIGN(4) + { + . = ALIGN(4); + __sanalogsucks = .; + *(.analogsucks .analogsucks.*); + . = ALIGN(4); + __eanalogsucks = .; + } > ANALOGSUCKS AT>FLASH + + /* ## Sections in RAM */ + /* ### .data */ + .data : ALIGN(4) + { + . = ALIGN(4); + __sdata = .; + *(.data .data.*); + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + } > RAM AT>FLASH + /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to + * use the .data loading mechanism by pushing __edata. Note: do not change + * output region or load region in those user sections! */ + . = ALIGN(4); + __edata = .; + + /* LMA of .data */ + __sidata = LOADADDR(.data); + + __sianalogsucks = LOADADDR(.analogsucks); + + /* ### .gnu.sgstubs + This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ + /* Security Attribution Unit blocks must be 32 bytes aligned. */ + /* Note that this pads the FLASH usage to 32 byte alignment. */ + .gnu.sgstubs : ALIGN(32) + { + . = ALIGN(32); + __veneer_base = .; + *(.gnu.sgstubs*) + . = ALIGN(32); + } > FLASH + /* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are + * always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol. + */ + . = ALIGN(32); + __veneer_limit = .; + + /* ### .bss */ + .bss (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + __sbss = .; + *(.bss .bss.*); + *(COMMON); /* Uninitialized C statics */ + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + } > RAM + /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to + * use the .bss zeroing mechanism by pushing __ebss. Note: do not change + * output region or load region in those user sections! */ + . = ALIGN(4); + __ebss = .; + + /* ### .uninit */ + .uninit (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + __suninit = .; + *(.uninit .uninit.*); + . = ALIGN(4); + __euninit = .; + } > RAM + + /* Place the heap right after `.uninit` in RAM */ + PROVIDE(__sheap = __euninit); + + /* Place stack end at the end of allocated RAM */ + PROVIDE(_stack_end = __euninit); + + /* ## .got */ + /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in + the input files and raise an error if relocatable code is found */ + .got (NOLOAD) : + { + KEEP(*(.got .got.*)); + } + + /* ## Discarded sections */ + /DISCARD/ : + { + /* Unused exception related info that only wastes space */ + *(.ARM.exidx); + *(.ARM.exidx.*); + *(.ARM.extab.*); + } +} + +/* Do not exceed this mark in the error messages below | */ +/* # Alignment checks */ +ASSERT(ORIGIN(FLASH) % 4 == 0, " +ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); + +ASSERT(ORIGIN(RAM) % 4 == 0, " +ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); + +ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " +BUG(cortex-m-rt): .data is not 4-byte aligned"); + +ASSERT(__sidata % 4 == 0, " +BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); + +ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " +BUG(cortex-m-rt): .bss is not 4-byte aligned"); + +ASSERT(__sheap % 4 == 0, " +BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); + +ASSERT(_stack_start % 8 == 0, " +ERROR(cortex-m-rt): stack start address is not 8-byte aligned. +If you have set _stack_start, check it's set to an address which is a multiple of 8 bytes. +If you haven't, stack starts at the end of RAM by default. Check that both RAM +origin and length are set to multiples of 8 in the `memory.x` file."); + +ASSERT(_stack_end % 4 == 0, " +ERROR(cortex-m-rt): end of stack is not 4-byte aligned"); + +ASSERT(_stack_start >= _stack_end, " +ERROR(cortex-m-rt): stack end address is not below stack start."); + +/* # Position checks */ + +/* ## .vector_table + * + * If the *start* of exception vectors is not 8 bytes past the start of the + * vector table, then we somehow did not place the reset vector, which should + * live 4 bytes past the start of the vector table. + */ +ASSERT(__exceptions == ADDR(.vector_table) + 0x8, " +BUG(cortex-m-rt): the reset vector is missing"); + +ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " +BUG(cortex-m-rt): the exception vectors are missing"); + +ASSERT(SIZEOF(.vector_table) > 0x40, " +ERROR(cortex-m-rt): The interrupt vectors are missing. +Possible solutions, from most likely to less likely: +- Link to a svd2rust generated device crate +- Check that you actually use the device/hal/bsp crate in your code +- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency +may be enabling it) +- Supply the interrupt handlers yourself. Check the documentation for details."); + +/* ## .text */ +ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " +ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section +Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); + +ASSERT(_stext >= ORIGIN(FLASH) && _stext < ORIGIN(FLASH) + LENGTH(FLASH), " +ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. +Set _stext to an address within the FLASH region."); + +/* # Other checks */ +ASSERT(SIZEOF(.got) == 0, " +ERROR(cortex-m-rt): .got section detected in the input object files +Dynamic relocations are not supported. If you are linking to C code compiled using +the 'cc' crate then modify your build script to compile the C code _without_ +the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); +/* Do not exceed this mark in the error messages above | */ diff --git a/memory.x.example b/memory.x.example new file mode 100644 index 0000000..c79c034 --- /dev/null +++ b/memory.x.example @@ -0,0 +1,10 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K + STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K + ANALOGSUCKS (rx) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 10K + RAM (rw) : ORIGIN = ORIGIN(ANALOGSUCKS) + LENGTH(ANALOGSUCKS), LENGTH = 128K - LENGTH(STACK) - LENGTH(ANALOGSUCKS) +} + +_stack_start = ORIGIN(STACK) + LENGTH(STACK); +_stack_end = ORIGIN(STACK); diff --git a/tests/build.rs b/tests/build.rs index dc8a4e4..dd7a966 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -13,20 +13,6 @@ fn main() { .write_all(include_bytes!("memory.x")) .unwrap(); - // Put the link.x linker script somewhere the linker can find it. - File::create(out.join("link.x")) - .unwrap() - .write_all(include_bytes!("link.x")) - .unwrap(); - - let flc_asm_path = out.join("flc_asm.s"); - File::create(&flc_asm_path) - .unwrap() - .write_all(include_bytes!("flc_asm.s")) - .unwrap(); - - cc::Build::new().file(&flc_asm_path).compile("flc_asm"); - println!("cargo:rustc-link-arg=--nmagic"); // Only re-run the build script when this file, memory.x, or link.x is changed. diff --git a/tests/src/main.rs b/tests/src/main.rs index 38eb98b..fadb25b 100644 --- a/tests/src/main.rs +++ b/tests/src/main.rs @@ -6,7 +6,7 @@ use core::fmt::Write; -use cortex_m_rt::{entry, pre_init}; +use cortex_m_rt::entry; use cortex_m_semihosting::hio; use max78000_hal::{ max78000::Peripherals, @@ -30,23 +30,6 @@ pub const TIMER_0_OSC: Oscillator = Oscillator::ERTCO; /// Prescaler to use for TMR0 during tests pub const TIMER_0_PRESCALER: Prescaler = Prescaler::_1; -#[pre_init] -unsafe fn pre_init() { - // load the .analogsucks section into memory - core::arch::asm! { - "ldr r0, =__sanalogsucks - ldr r1, =__eanalogsucks - ldr r2, =__sianalogsucks - 0: - cmp r1, r0 - beq 1f - ldm r2!, {{r3}} - stm r0!, {{r3}} - b 0b - 1:" - } -} - /// Entry point for tests. #[entry] fn main() -> ! { From d846877509f3f00fdae9a8d0ccef0ae1f00601e2 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 2 Mar 2025 18:14:55 -0800 Subject: [PATCH 10/32] move flc-asm to hal --- Cargo.toml | 3 +- flc-asm/.cargo/config.toml | 2 + flc-asm/Cargo.toml | 10 + flc-asm/src/lib.rs | 416 +++++++++++++++++++++++++++++++++++++ hal/flc_asm.s | 1 + 5 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 flc-asm/.cargo/config.toml create mode 100644 flc-asm/Cargo.toml create mode 100644 flc-asm/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index f0a7887..62f7d8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [workspace] members = [ "hal", - "tests" + "flc-asm", + "tests", ] resolver = "2" diff --git a/flc-asm/.cargo/config.toml b/flc-asm/.cargo/config.toml new file mode 100644 index 0000000..5d10902 --- /dev/null +++ b/flc-asm/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "thumbv7em-none-eabihf" diff --git a/flc-asm/Cargo.toml b/flc-asm/Cargo.toml new file mode 100644 index 0000000..cecacb9 --- /dev/null +++ b/flc-asm/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "flc-asm" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +max78000 = { git = "https://github.com/slugsecurity/max78000" } diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs new file mode 100644 index 0000000..691e940 --- /dev/null +++ b/flc-asm/src/lib.rs @@ -0,0 +1,416 @@ +//! Flash controller peripheral API, but in asm +//! +//! This generates the `flc_asm.s` assembly file in the flash controller, +//! to ensure that all function calls in the HAL primitives are located in RAM. +//! +//! Compile with `cargo rustc --release -- --emit=asm`, then find the assembly file +//! `target/thumbv7em-none-eabihf/release/deps/flc-asm-.s` file. +//! +//! You need to remove the `CORE_PERIPHERALS` and `DEVICE_PERIPHERALS` symbols to +//! avoid linker conflicts. +#![no_std] +#![deny( + clippy::missing_safety_doc, + unsafe_op_in_unsafe_fn, + clippy::undocumented_unsafe_blocks +)] + +use core::{arch::asm, panic::PanicInfo, ptr::read_volatile}; + +use max78000::{FLC, GCR, ICC0}; + +/// A macro for ensuring that code never exits, even in cases of fault-injection attacks. +macro_rules! never_exit { + () => { + // SAFETY: All branches are to a local label. + unsafe { + asm!( + "2:", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + "b 2b", + options(noreturn), + ) + } + }; +} + +/// A panic handler that never exits, even in cases of fault-injection attacks. +// In debug mode, don't inline in order to allow setting breakpoints. +#[cfg_attr(debug_assertions, inline(never))] +#[panic_handler] +#[link_section = ".analogsucks"] +fn panic_handler(_info: &PanicInfo) -> ! { + never_exit!() +} + +/// Flash memory base address. +const FLASH_MEM_BASE: u32 = 0x1000_0000; + +/// Flash memory size. +const FLASH_MEM_SIZE: u32 = 0x0008_0000; + +/// Flash page size. +const FLASH_PAGE_SIZE: u32 = 0x2000; + +struct FlashController<'gcr, 'icc> { + flc: FLC, + gcr: &'gcr GCR, + icc: &'icc ICC0, +} + +/// Checks whether the given address range (exclusive) is within flash space. +/// +/// # Panics +/// - Panics if the given address range is not contained within flash range. +#[inline(always)] +const fn check_address_bounds(address_range: core::ops::Range) { + if !(FLASH_MEM_BASE <= address_range.start + && address_range.start < FLASH_MEM_BASE + FLASH_MEM_SIZE + && FLASH_MEM_BASE < address_range.end + && address_range.end <= FLASH_MEM_BASE + FLASH_MEM_SIZE) + { + panic!(); + } +} + +impl<'gcr, 'icc> FlashController<'gcr, 'icc> { + /// Unlocks memory protection to allow flash operations. + /// + /// This MUST be called before any non-read flash controller operation. + /// + /// # Safety + /// - The FLC must be in its ready state after [`Self::wait_until_ready`] + #[inline(always)] + unsafe fn unlock_write_protection(&self) { + self.flc.ctrl().modify(|_, w| w.unlock().unlocked()); + } + + /// Locks memory protection. + /// + /// This MUST be called after any non-read flash controller operation. + /// + /// # Safety + /// - The FLC must be in its ready state after [`Self::wait_until_ready`] + #[inline(always)] + unsafe fn lock_write_protection(&self) { + self.flc.ctrl().modify(|_, w| w.unlock().locked()); + } + + /// Sets the `FLC_CLKDIV` register to the system clock's frequency `sys_clk_freq`, + /// calculated with `freq / div` of the current system clock. It must be a multiple + /// of 1 MHz. + /// + /// This MUST be called before any non-read flash controller operations after + /// the FLC is ready. + /// + /// # Panics + /// - If the clock is not a multiple of 1 MHz, this function panics. + /// + /// # Safety + /// - The passed argument `sys_clk_freq` must be the current system clock's + /// frequency divided by its divider. + /// - The FLC must be in its ready state after [`Self::wait_until_ready`] + #[inline(always)] + unsafe fn set_clock_divisor(&self, sys_clk_freq: u32) { + if sys_clk_freq % 1_000_000 != 0 { + panic!() + } + + let flc_clkdiv = sys_clk_freq / 1_000_000; + + self.flc + .clkdiv() + .modify(|_, w| w.clkdiv().variant(flc_clkdiv as u8)); + } + + /// Wait, by busy-looping, until the FLC is ready. + /// + /// This MUST be called BEFORE any FLC operation EXCEPT clearing interrupts. + #[inline(always)] + fn wait_until_ready(&self) { + while !self.flc.ctrl().read().pend().bit_is_clear() {} + } + + /// Clear any stale errors in the FLC interrupt register. + /// + /// This can be called without waiting for the FLC to be ready. + #[inline(always)] + fn clear_interrupts(&self) { + self.flc.intr().modify(|_, w| w.af().clear_bit()); + } + + /// Prepares the FLC for a write operation, performs the operation, and + /// cleans up after the operation. + /// + /// # Safety + /// - The argument `sys_clk_freq` must be equal to the current system clock's + /// frequency divided by its divider. + /// + /// # Panics + /// - If `sys_clk_freq` is not a multiple of 1 MHz, this function panics. + #[inline(always)] + unsafe fn write_guard(&self, sys_clk_freq: u32, operation: F) { + // Pre-write + self.wait_until_ready(); + self.disable_icc0(); + self.clear_interrupts(); + + // SAFETY: we wait until the FLC is ready above, and the caller must + // guarantee that `sys_clk_freq` is valid per `[Self::set_clock_divisor]`. + unsafe { + self.set_clock_divisor(sys_clk_freq); + } + + // SAFETY: we wait until the FLC is ready above + unsafe { + self.unlock_write_protection(); + } + + operation(); + + // Post-write + self.wait_until_ready(); + + // SAFETY: we wait until the FLC is ready above + unsafe { + self.lock_write_protection(); + } + self.flush_icc(); + self.enable_icc0(); + } + + /// Flushes the flash line buffer and arm instruction cache. + /// + /// This MUST be called after any write/erase flash controller operations. + #[inline(always)] + fn flush_icc(&self) { + self.gcr.sysctrl().modify(|_, w| w.icc0_flush().flush()); + while !self.gcr.sysctrl().read().icc0_flush().bit_is_clear() {} + + // Clear the line fill buffer by reading 2 pages from flash + const PAGE1: u32 = FLASH_MEM_BASE; + const PAGE2: u32 = FLASH_MEM_BASE + FLASH_PAGE_SIZE; + // SAFETY: `FLASH_MEM_BASE` points to a valid, aligned word within flash space. + const { + check_address_bounds(PAGE1..PAGE1 + 4); + assert!(PAGE1 % 4 == 0); + check_address_bounds(PAGE2..PAGE2 + 4); + assert!(PAGE2 % 4 == 0); + } + unsafe { core::hint::black_box(read32(PAGE1 as *const u32)) }; + // SAFETY: `FLASH_MEM_BASE + FLASH_PAGE_SIZE` points to a valid, aligned word within flash space. + unsafe { core::hint::black_box(read32(PAGE2 as *const u32)) }; + } + + /// Disables instruction cache. + /// + /// This MUST be called before any non-read flash controller operations. + #[inline(always)] + fn disable_icc0(&self) { + self.icc.ctrl().modify(|_, w| w.en().dis()); + } + + /// Enables instruction cache. + /// + /// This MUST be called after any non-read flash controller operations. + #[inline(always)] + fn enable_icc0(&self) { + // ensure the cache is invalidated when enabled + self.disable_icc0(); + + self.icc.invalidate().modify(|_, w| w.invalid().variant(1)); + while !self.icc.ctrl().read().rdy().bit_is_set() {} + + self.icc.ctrl().modify(|_, w| w.en().en()); + while !self.icc.ctrl().read().rdy().bit_is_set() {} + } + + /// Writes 128 bits (16 bytes) of data to flash. + /// Address must be 128-bit aligned. + /// + /// # Safety + /// + /// - The argument `sys_clk_freq` must be equal to the current system clock's + /// frequency divided by its divider. + /// - Writes must not corrupt potentially executable instructions of the program. + /// Callers must ensure that the following condition is met: + /// * If `address` points to a portion of the program's instructions, `data` must + /// contain valid instructions that does not introduce undefined behavior. + /// + /// It is very difficult to define what would cause undefined behavior when + /// modifying program instructions. This would almost certainly result + /// in unwanted and likely undefined behavior. Do so at your own risk. + /// + /// + /// # Panics + /// + /// If any of the following conditions are not met, this function panics: + /// + /// - `sys_clk_freq` must be a multiple of 1 MHz + /// - `address` must point to a word contained in flash space + /// - `address` must be aligned to 128 bits + #[inline(always)] + unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk_freq: u32) { + check_address_bounds(address..address + 16); + if address % size_of::<[u32; 4]>() as u32 != 0 { + panic!(); + } + + // SAFETY: the caller must guarantee that `sys_clk_freq` is valid per this function's + // safety comment. + unsafe { + self.write_guard(sys_clk_freq, || { + self.flc.addr().modify(|_, w| w.addr().variant(address)); + self.flc.data(0).modify(|_, w| w.data().variant(data[0])); + self.flc.data(1).modify(|_, w| w.data().variant(data[1])); + self.flc.data(2).modify(|_, w| w.data().variant(data[2])); + self.flc.data(3).modify(|_, w| w.data().variant(data[3])); + + self.flc.ctrl().modify(|_, w| w.wr().set_bit()); + + // Wait until write completes + while !self.flc.ctrl().read().wr().is_complete() {} + }); + } + } + + /// Erases a page of flash. `address[12:0]` is ignored to ensure the address + /// is page-aligned. + /// + /// # Safety + /// + /// - The argument `sys_clk_freq` must be equal to the current system clock's + /// frequency divided by its divider. + /// - Erases must not corrupt potentially executable instructions of the program. + /// - `address` must be in a valid flash page + /// + /// # Panics + /// - If `sys_clk_freq` is not a multiple of 1 MHz, this function panics. + /// - This function also panics when the `address` does not point inside of a page + /// contained in flash space. + unsafe fn page_erase(&self, address: u32, sys_clk_freq: u32) { + check_address_bounds(address..address + 1); + // SAFETY: the caller must guarantee that `sys_clk_freq` is valid per this function's + // safety comment. + unsafe { + self.write_guard(sys_clk_freq, || { + self.flc.addr().modify(|_, w| w.addr().variant(address)); + + self.flc.ctrl().modify(|_, w| w.erase_code().erase_page()); + self.flc.ctrl().modify(|_, w| w.pge().set_bit()); + }); + } + } +} + +/// Reads a little-endian `u32` from flash memory. +/// +/// Panics if any of the following preconditions are not true: +/// - `address` must be 32-bit aligned. +/// - `address` must point to a valid location in flash memory (`0x1000_0000..=0x1007_ffff`). +#[export_name = "flc_read32_primitive"] +#[link_section = ".analogsucks"] +pub unsafe extern "C" fn read32(address: *const u32) -> u32 { + if !address.is_aligned() { + panic!(); + } + check_address_bounds(address as u32..(address as u32 + 4)); + // SAFETY: the caller must guarantee that `address` is aligned and is within + // flash memory. + unsafe { read_volatile(address) } +} + +/// Writes a little-endian 128-bit flash word into flash memory. +/// +/// Safety: +/// - The caller must hold a shared reference to the [`FLC`], [`ICC0`], and [`GCR`] registers. +/// - The flash word at `address` must be in the *erased* state (with [`page_erase`]). +/// - `data` must point to an array of four `u32`s. +/// - `sys_clk_freq` must be equal to `freq / div` where `freq` is the frequency of +/// the current system clock, and `div` is the divider of the system clock. +/// - If `address` writes to an address in the currently-running program's instruction space, +/// it must be valid instructions. +/// +/// Panics if any of the following preconditions are not true: +/// - `address` must be 128-bit aligned. +/// - The entire flash word at address (bytes `address..address + 16`) must be within +/// the flash memory (`0x1000_0000..=0x1007_ffff`). +/// - `sys_clk_freq` must be divisible by one million (`1_000_000`). +#[export_name = "flc_write128_primitive"] +#[link_section = ".analogsucks"] +pub unsafe extern "C" fn write128(address: *mut [u32; 4], data: *const u32, sys_clk_freq: u32) { + // SAFETY: the caller must hold a valid reference to these registers during this call. + let flc = unsafe { + FlashController { + flc: FLC::steal(), + icc: &ICC0::steal(), + gcr: &GCR::steal(), + } + }; + + // SAFETY: the caller must ensure that `data` points to a valid array of four `u32`s. + let data = unsafe { &*(data as *const [u32; 4]) }; + + // SAFETY: + // - the caller must guarantee that the address is aligned and the word is within flash space + // - the caller must guarantee that the word is in the erased state + // - the caller must ensure that `sys_clk_freq` is correctly calculated per this function's + // safety comment + // - the caller must ensure that, if it is overwriting instructions, the new instructions are valid + unsafe { + flc.write128(address as u32, data, sys_clk_freq); + } +} + +/// Erases the page at the given address in flash memory. +/// +/// Safety: +/// - The caller must hold a shared reference to the [`FLC`], [`ICC0`], and [`GCR`] registers. +/// - `address` must point to a valid page within flash memory (`0x1000_0000..=0x1007_ffff`). +/// - `sys_clk_freq` must be equal to `freq / div` where `freq` is the frequency of +/// the current system clock, and `div` is the divider of the system clock. +/// - `sys_clk_freq` must be divisible by one million (`1_000_000`). +/// - If `address` erases a page in the currently-running program's instruction space, +/// it must be rewritten with [`write128`] before the program reaches those instructions. +/// +/// Panics if any of the following preconditions are not true: +/// - `address` must point to within a valid page in flash space (`0x1000_000..=0x1007_ffff`) +/// - `sys_clk_freq` must be divisible by one million (`1_000_000`). +#[export_name = "flc_page_erase_primitive"] +#[link_section = ".analogsucks"] +pub unsafe extern "C" fn page_erase(address: *mut u8, sys_clk_freq: u32) { + // SAFETY: the caller must hold a valid reference to these registers during this call. + let flc = unsafe { + FlashController { + flc: FLC::steal(), + icc: &ICC0::steal(), + gcr: &GCR::steal(), + } + }; + + // SAFETY: + // - the caller must provide a valid address. + // - the caller must ensure that sys_clk_freq is calculated correctly per this function's + // safety comment. + // - the caller must guarantee that the program won't execute erased instructions in this page. + unsafe { + flc.page_erase(address as u32, sys_clk_freq); + } +} diff --git a/hal/flc_asm.s b/hal/flc_asm.s index 62a1368..042970e 100644 --- a/hal/flc_asm.s +++ b/hal/flc_asm.s @@ -1,3 +1,4 @@ +@ Please see the `flc-asm` crate at the git root for information on how this file is generated. .text .syntax unified .eabi_attribute 67, "2.09" From 98e2eb09700e008e4d77a6421db294e59fb892b5 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 2 Mar 2025 18:37:31 -0800 Subject: [PATCH 11/32] fix panicking --- flc-asm/src/lib.rs | 43 ++++--- hal/flc_asm.s | 309 +++++++++++++++++++++++++++++++++++++++------ tests/build.rs | 5 + 3 files changed, 301 insertions(+), 56 deletions(-) diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 691e940..2debbff 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -51,12 +51,14 @@ macro_rules! never_exit { }; } -/// A panic handler that never exits, even in cases of fault-injection attacks. -// In debug mode, don't inline in order to allow setting breakpoints. -#[cfg_attr(debug_assertions, inline(never))] #[panic_handler] +fn panic_handler(_: &PanicInfo) -> ! { + never_exit!() +} + +/// A "panic" function that is guaranteed to be in RAM #[link_section = ".analogsucks"] -fn panic_handler(_info: &PanicInfo) -> ! { +fn panic() -> ! { never_exit!() } @@ -75,19 +77,19 @@ struct FlashController<'gcr, 'icc> { icc: &'icc ICC0, } -/// Checks whether the given address range (exclusive) is within flash space. -/// -/// # Panics -/// - Panics if the given address range is not contained within flash range. +/// Checks whether the given address range (exclusive) is within flash space, returning `false` if there +/// is an error. #[inline(always)] -const fn check_address_bounds(address_range: core::ops::Range) { +#[must_use] +const fn check_address_bounds(address_range: core::ops::Range) -> bool { if !(FLASH_MEM_BASE <= address_range.start && address_range.start < FLASH_MEM_BASE + FLASH_MEM_SIZE && FLASH_MEM_BASE < address_range.end && address_range.end <= FLASH_MEM_BASE + FLASH_MEM_SIZE) { - panic!(); + return false; } + return true; } impl<'gcr, 'icc> FlashController<'gcr, 'icc> { @@ -209,9 +211,9 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { const PAGE2: u32 = FLASH_MEM_BASE + FLASH_PAGE_SIZE; // SAFETY: `FLASH_MEM_BASE` points to a valid, aligned word within flash space. const { - check_address_bounds(PAGE1..PAGE1 + 4); + assert!(check_address_bounds(PAGE1..PAGE1 + 4)); assert!(PAGE1 % 4 == 0); - check_address_bounds(PAGE2..PAGE2 + 4); + assert!(check_address_bounds(PAGE2..PAGE2 + 4)); assert!(PAGE2 % 4 == 0); } unsafe { core::hint::black_box(read32(PAGE1 as *const u32)) }; @@ -268,9 +270,11 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// - `address` must be aligned to 128 bits #[inline(always)] unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk_freq: u32) { - check_address_bounds(address..address + 16); + if !check_address_bounds(address..address + 16) { + panic() + } if address % size_of::<[u32; 4]>() as u32 != 0 { - panic!(); + panic(); } // SAFETY: the caller must guarantee that `sys_clk_freq` is valid per this function's @@ -305,8 +309,11 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// - If `sys_clk_freq` is not a multiple of 1 MHz, this function panics. /// - This function also panics when the `address` does not point inside of a page /// contained in flash space. + #[inline(always)] unsafe fn page_erase(&self, address: u32, sys_clk_freq: u32) { - check_address_bounds(address..address + 1); + if !check_address_bounds(address..address + 1) { + panic() + } // SAFETY: the caller must guarantee that `sys_clk_freq` is valid per this function's // safety comment. unsafe { @@ -329,9 +336,11 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { #[link_section = ".analogsucks"] pub unsafe extern "C" fn read32(address: *const u32) -> u32 { if !address.is_aligned() { - panic!(); + panic(); + } + if !check_address_bounds(address as u32..(address as u32 + 4)) { + panic(); } - check_address_bounds(address as u32..(address as u32 + 4)); // SAFETY: the caller must guarantee that `address` is aligned and is within // flash memory. unsafe { read_volatile(address) } diff --git a/hal/flc_asm.s b/hal/flc_asm.s index 042970e..7e7f6de 100644 --- a/hal/flc_asm.s +++ b/hal/flc_asm.s @@ -1,4 +1,3 @@ -@ Please see the `flc-asm` crate at the git root for information on how this file is generated. .text .syntax unified .eabi_attribute 67, "2.09" @@ -40,19 +39,65 @@ flc_read32_primitive: mov r7, sp .cfi_def_cfa_register r7 lsls r1, r0, #30 - ittt eq - moveq r1, r0 - bfceq r1, #0, #19 - cmpeq.w r1, #268435456 - bne .LBB0_2 + bne .LBB0_4 + mov r1, r0 + bfc r1, #0, #19 + cmp.w r1, #268435456 + bne .LBB0_3 ldr r1, .LCPI0_0 add r1, r0 cmp.w r1, #524288 itt lo ldrlo r0, [r0] poplo {r7, pc} -.LBB0_2: - bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E +.LBB0_3: + @APP +.Ltmp0: + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + b .Ltmp0 + @NO_APP + .inst.n 0xdefe +.LBB0_4: + @APP +.Ltmp1: + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + @NO_APP + .inst.n 0xdefe .p2align 2 .LCPI0_0: .long 4026531843 @@ -90,13 +135,13 @@ flc_write128_primitive: mov r3, r0 bfc r3, #0, #19 cmp.w r3, #268435456 - bne .LBB1_16 + bne .LBB1_17 ldr r3, .LCPI1_0 add r3, r0 cmp.w r3, #524288 - bhs .LBB1_16 + bhs .LBB1_17 lsls r3, r0, #28 - bne .LBB1_16 + bne.w .LBB1_18 ldr r4, .LCPI1_1 .LBB1_4: ldr r3, [r4, #8] @@ -193,6 +238,54 @@ flc_write128_primitive: pop {r4, r5, r6, r7, pc} .LBB1_16: bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E +.LBB1_17: + @APP +.Ltmp2: + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + b .Ltmp2 + @NO_APP + .inst.n 0xdefe +.LBB1_18: + @APP +.Ltmp3: + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + b .Ltmp3 + @NO_APP + .inst.n 0xdefe .p2align 2 .LCPI1_0: .long 4026531855 @@ -235,7 +328,7 @@ flc_page_erase_primitive: mov r2, r0 bfc r2, #0, #19 cmp.w r2, #268435456 - bne .LBB2_13 + bne .LBB2_14 ldr r3, .LCPI2_0 .LBB2_2: ldr r2, [r3, #8] @@ -318,6 +411,30 @@ flc_page_erase_primitive: pop {r2, r3, r4, r5, r7, pc} .LBB2_13: bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E +.LBB2_14: + @APP +.Ltmp4: + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + @NO_APP + .inst.n 0xdefe .p2align 2 .LCPI2_0: .long 1073909760 @@ -378,32 +495,32 @@ _ZN4core9panicking9panic_fmt17haebed1323d60a452E: .setfp r7, sp mov r7, sp .cfi_def_cfa_register r7 -.Ltmp0: +.Ltmp5: .loc 1 75 14 prologue_end @APP -.Ltmp1: - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 +.Ltmp6: + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 + b .Ltmp6 @NO_APP .inst.n 0xdefe -.Ltmp2: +.Ltmp7: .Lfunc_end4: .size _ZN4core9panicking9panic_fmt17haebed1323d60a452E, .Lfunc_end4-_ZN4core9panicking9panic_fmt17haebed1323d60a452E .cfi_endproc @@ -428,16 +545,128 @@ _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE: .setfp r7, sp mov r7, sp .cfi_def_cfa_register r7 -.Ltmp3: +.Ltmp8: .loc 1 261 5 prologue_end bl _ZN4core9panicking9panic_fmt17haebed1323d60a452E -.Ltmp4: +.Ltmp9: .Lfunc_end5: .size _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE, .Lfunc_end5-_ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE .cfi_endproc .cantunwind .fnend + .section .debug_abbrev,"",%progbits + .byte 1 + .byte 17 + .byte 1 + .byte 37 + .byte 14 + .byte 19 + .byte 5 + .byte 3 + .byte 14 + .byte 16 + .byte 23 + .byte 27 + .byte 14 + .byte 17 + .byte 1 + .byte 85 + .byte 23 + .byte 0 + .byte 0 + .byte 2 + .byte 57 + .byte 1 + .byte 3 + .byte 14 + .byte 0 + .byte 0 + .byte 3 + .byte 46 + .byte 0 + .byte 17 + .byte 1 + .byte 18 + .byte 6 + .byte 64 + .byte 24 + .byte 110 + .byte 14 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 54 + .byte 11 + .byte 63 + .byte 25 + .ascii "\207\001" + .byte 25 + .byte 0 + .byte 0 + .byte 4 + .byte 46 + .byte 0 + .byte 110 + .byte 14 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 5 + .ascii "\207\001" + .byte 25 + .byte 32 + .byte 11 + .byte 0 + .byte 0 + .byte 5 + .byte 46 + .byte 1 + .byte 17 + .byte 1 + .byte 18 + .byte 6 + .byte 64 + .byte 24 + .byte 110 + .byte 14 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 54 + .byte 11 + .byte 63 + .byte 25 + .ascii "\207\001" + .byte 25 + .byte 0 + .byte 0 + .byte 6 + .byte 29 + .byte 0 + .byte 49 + .byte 19 + .byte 17 + .byte 1 + .byte 18 + .byte 6 + .byte 88 + .byte 11 + .byte 89 + .byte 11 + .byte 87 + .byte 11 + .byte 0 + .byte 0 + .byte 0 .section .debug_info,"",%progbits .Lcu_begin0: .long .Ldebug_info_end0-.Ldebug_info_start0 @@ -466,6 +695,7 @@ _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE: .long .Linfo_string8 .byte 1 .byte 55 + .byte 3 .byte 4 @@ -484,12 +714,13 @@ _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE: .long .Linfo_string10 .byte 1 .byte 233 + .byte 3 .byte 6 - .long 69 - .long .Ltmp3 - .long .Ltmp4-.Ltmp3 + .long 70 + .long .Ltmp8 + .long .Ltmp9-.Ltmp8 .byte 1 .byte 234 .byte 5 diff --git a/tests/build.rs b/tests/build.rs index dd7a966..7170390 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -13,6 +13,11 @@ fn main() { .write_all(include_bytes!("memory.x")) .unwrap(); + File::create(out.join("link.x")) + .unwrap() + .write_all(include_bytes!("link.x")) + .unwrap(); + println!("cargo:rustc-link-arg=--nmagic"); // Only re-run the build script when this file, memory.x, or link.x is changed. From 967e288b1a2bf2009dd68f2b7278b7e08588e603 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 2 Mar 2025 18:46:17 -0800 Subject: [PATCH 12/32] the real flc-asm.s --- flc-asm/src/lib.rs | 4 +- hal/flc_asm.s | 414 ++++++++------------------------------------- 2 files changed, 68 insertions(+), 350 deletions(-) diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 2debbff..5548575 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -132,7 +132,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { #[inline(always)] unsafe fn set_clock_divisor(&self, sys_clk_freq: u32) { if sys_clk_freq % 1_000_000 != 0 { - panic!() + panic() } let flc_clkdiv = sys_clk_freq / 1_000_000; @@ -271,7 +271,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { #[inline(always)] unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk_freq: u32) { if !check_address_bounds(address..address + 16) { - panic() + panic(); } if address % size_of::<[u32; 4]>() as u32 != 0 { panic(); diff --git a/hal/flc_asm.s b/hal/flc_asm.s index 7e7f6de..c2a0eb9 100644 --- a/hal/flc_asm.s +++ b/hal/flc_asm.s @@ -135,13 +135,13 @@ flc_write128_primitive: mov r3, r0 bfc r3, #0, #19 cmp.w r3, #268435456 - bne .LBB1_17 + bne .LBB1_16 ldr r3, .LCPI1_0 add r3, r0 cmp.w r3, #524288 - bhs .LBB1_17 + bhs .LBB1_16 lsls r3, r0, #28 - bne.w .LBB1_18 + bne.w .LBB1_17 ldr r4, .LCPI1_1 .LBB1_4: ldr r3, [r4, #8] @@ -159,7 +159,7 @@ flc_write128_primitive: udiv r5, r2, r5 muls r6, r5, r6 cmn r6, r2 - bne .LBB1_16 + bne.w .LBB1_18 ldr r2, [r4, #4] bfi r2, r5, #0, #8 str r2, [r4, #4] @@ -237,8 +237,6 @@ flc_write128_primitive: ldr r11, [sp], #4 pop {r4, r5, r6, r7, pc} .LBB1_16: - bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E -.LBB1_17: @APP .Ltmp2: b .Ltmp2 @@ -262,7 +260,7 @@ flc_write128_primitive: b .Ltmp2 @NO_APP .inst.n 0xdefe -.LBB1_18: +.LBB1_17: @APP .Ltmp3: b .Ltmp3 @@ -286,6 +284,30 @@ flc_write128_primitive: b .Ltmp3 @NO_APP .inst.n 0xdefe +.LBB1_18: + @APP +.Ltmp4: + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + b .Ltmp4 + @NO_APP + .inst.n 0xdefe .p2align 2 .LCPI1_0: .long 4026531855 @@ -328,7 +350,7 @@ flc_page_erase_primitive: mov r2, r0 bfc r2, #0, #19 cmp.w r2, #268435456 - bne .LBB2_14 + bne .LBB2_13 ldr r3, .LCPI2_0 .LBB2_2: ldr r2, [r3, #8] @@ -346,7 +368,7 @@ flc_page_erase_primitive: udiv r4, r1, r4 muls r5, r4, r5 cmn r5, r1 - bne .LBB2_13 + bne .LBB2_14 ldr r1, [r3, #4] bfi r1, r4, #0, #8 str r1, [r3, #4] @@ -410,93 +432,30 @@ flc_page_erase_primitive: bpl .LBB2_11 pop {r2, r3, r4, r5, r7, pc} .LBB2_13: - bl _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E -.LBB2_14: @APP -.Ltmp4: - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 - b .Ltmp4 +.Ltmp5: + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 + b .Ltmp5 @NO_APP .inst.n 0xdefe - .p2align 2 -.LCPI2_0: - .long 1073909760 -.LCPI2_1: - .long 1073914112 -.LCPI2_2: - .long 1000000 -.LCPI2_3: - .long 4293967296 -.LCPI2_4: - .long 268443648 -.Lfunc_end2: - .size flc_page_erase_primitive, .Lfunc_end2-flc_page_erase_primitive - .cfi_endproc - .cantunwind - .fnend - - .section .text.unlikely._ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E,"ax",%progbits - .p2align 1 - .type _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E,%function - .code 16 - .thumb_func -_ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E: -.Lfunc_begin3: - .fnstart - .cfi_startproc - .save {r7, lr} - push {r7, lr} - .cfi_def_cfa_offset 8 - .cfi_offset lr, -4 - .cfi_offset r7, -8 - .setfp r7, sp - mov r7, sp - .cfi_def_cfa_register r7 - bl _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE -.Lfunc_end3: - .size _ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E, .Lfunc_end3-_ZN7flc_asm15FlashController17set_clock_divisor19panic_cold_explicit17hf124d6e3d1e3a7c6E - .cfi_endproc - .cantunwind - .fnend - - .section .text.unlikely._ZN4core9panicking9panic_fmt17haebed1323d60a452E,"ax",%progbits - .p2align 1 - .type _ZN4core9panicking9panic_fmt17haebed1323d60a452E,%function - .code 16 - .thumb_func -_ZN4core9panicking9panic_fmt17haebed1323d60a452E: -.Lfunc_begin4: - .file 1 "/rustc/bef3c3b01f690de16738b1c9f36470fbfc6ac623" "library/core/src/panicking.rs" - .loc 1 55 0 - .fnstart - .cfi_startproc - .save {r7, lr} - push {r7, lr} - .cfi_def_cfa_offset 8 - .cfi_offset lr, -4 - .cfi_offset r7, -8 - .setfp r7, sp - mov r7, sp - .cfi_def_cfa_register r7 -.Ltmp5: - .loc 1 75 14 prologue_end +.LBB2_14: @APP .Ltmp6: b .Ltmp6 @@ -520,263 +479,23 @@ _ZN4core9panicking9panic_fmt17haebed1323d60a452E: b .Ltmp6 @NO_APP .inst.n 0xdefe -.Ltmp7: -.Lfunc_end4: - .size _ZN4core9panicking9panic_fmt17haebed1323d60a452E, .Lfunc_end4-_ZN4core9panicking9panic_fmt17haebed1323d60a452E - .cfi_endproc - .cantunwind - .fnend - - .section .text.unlikely._ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE,"ax",%progbits - .p2align 1 - .type _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE,%function - .code 16 - .thumb_func -_ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE: -.Lfunc_begin5: - .loc 1 233 0 - .fnstart - .cfi_startproc - .save {r7, lr} - push {r7, lr} - .cfi_def_cfa_offset 8 - .cfi_offset lr, -4 - .cfi_offset r7, -8 - .setfp r7, sp - mov r7, sp - .cfi_def_cfa_register r7 -.Ltmp8: - .loc 1 261 5 prologue_end - bl _ZN4core9panicking9panic_fmt17haebed1323d60a452E -.Ltmp9: -.Lfunc_end5: - .size _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE, .Lfunc_end5-_ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE + .p2align 2 +.LCPI2_0: + .long 1073909760 +.LCPI2_1: + .long 1073914112 +.LCPI2_2: + .long 1000000 +.LCPI2_3: + .long 4293967296 +.LCPI2_4: + .long 268443648 +.Lfunc_end2: + .size flc_page_erase_primitive, .Lfunc_end2-flc_page_erase_primitive .cfi_endproc .cantunwind .fnend - .section .debug_abbrev,"",%progbits - .byte 1 - .byte 17 - .byte 1 - .byte 37 - .byte 14 - .byte 19 - .byte 5 - .byte 3 - .byte 14 - .byte 16 - .byte 23 - .byte 27 - .byte 14 - .byte 17 - .byte 1 - .byte 85 - .byte 23 - .byte 0 - .byte 0 - .byte 2 - .byte 57 - .byte 1 - .byte 3 - .byte 14 - .byte 0 - .byte 0 - .byte 3 - .byte 46 - .byte 0 - .byte 17 - .byte 1 - .byte 18 - .byte 6 - .byte 64 - .byte 24 - .byte 110 - .byte 14 - .byte 3 - .byte 14 - .byte 58 - .byte 11 - .byte 59 - .byte 11 - .byte 54 - .byte 11 - .byte 63 - .byte 25 - .ascii "\207\001" - .byte 25 - .byte 0 - .byte 0 - .byte 4 - .byte 46 - .byte 0 - .byte 110 - .byte 14 - .byte 3 - .byte 14 - .byte 58 - .byte 11 - .byte 59 - .byte 5 - .ascii "\207\001" - .byte 25 - .byte 32 - .byte 11 - .byte 0 - .byte 0 - .byte 5 - .byte 46 - .byte 1 - .byte 17 - .byte 1 - .byte 18 - .byte 6 - .byte 64 - .byte 24 - .byte 110 - .byte 14 - .byte 3 - .byte 14 - .byte 58 - .byte 11 - .byte 59 - .byte 11 - .byte 54 - .byte 11 - .byte 63 - .byte 25 - .ascii "\207\001" - .byte 25 - .byte 0 - .byte 0 - .byte 6 - .byte 29 - .byte 0 - .byte 49 - .byte 19 - .byte 17 - .byte 1 - .byte 18 - .byte 6 - .byte 88 - .byte 11 - .byte 89 - .byte 11 - .byte 87 - .byte 11 - .byte 0 - .byte 0 - .byte 0 - .section .debug_info,"",%progbits -.Lcu_begin0: - .long .Ldebug_info_end0-.Ldebug_info_start0 -.Ldebug_info_start0: - .short 4 - .long .debug_abbrev - .byte 4 - .byte 1 - .long .Linfo_string0 - .short 28 - .long .Linfo_string1 - .long .Lline_table_start0 - .long .Linfo_string2 - .long 0 - .long .Ldebug_ranges0 - .byte 2 - .long .Linfo_string3 - .byte 2 - .long .Linfo_string4 - .byte 3 - .long .Lfunc_begin4 - .long .Lfunc_end4-.Lfunc_begin4 - .byte 1 - .byte 87 - .long .Linfo_string7 - .long .Linfo_string8 - .byte 1 - .byte 55 - .byte 3 - - - .byte 4 - .long .Linfo_string5 - .long .Linfo_string6 - .byte 1 - .short 260 - - .byte 1 - .byte 5 - .long .Lfunc_begin5 - .long .Lfunc_end5-.Lfunc_begin5 - .byte 1 - .byte 87 - .long .Linfo_string9 - .long .Linfo_string10 - .byte 1 - .byte 233 - .byte 3 - - - .byte 6 - .long 70 - .long .Ltmp8 - .long .Ltmp9-.Ltmp8 - .byte 1 - .byte 234 - .byte 5 - .byte 0 - .byte 0 - .byte 0 - .byte 0 -.Ldebug_info_end0: - .section .text.unlikely._ZN4core9panicking9panic_fmt17haebed1323d60a452E,"ax",%progbits -.Lsec_end0: - .section .text.unlikely._ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE,"ax",%progbits -.Lsec_end1: - .section .debug_aranges,"",%progbits - .long 36 - .short 2 - .long .Lcu_begin0 - .byte 4 - .byte 0 - .zero 4,255 - .long .Lfunc_begin4 - .long .Lsec_end0-.Lfunc_begin4 - .long .Lfunc_begin5 - .long .Lsec_end1-.Lfunc_begin5 - .long 0 - .long 0 - .section .debug_ranges,"",%progbits -.Ldebug_ranges0: - .long .Lfunc_begin4 - .long .Lfunc_end4 - .long .Lfunc_begin5 - .long .Lfunc_end5 - .long 0 - .long 0 - .section .debug_str,"MS",%progbits,1 -.Linfo_string0: - .asciz "clang LLVM (rustc version 1.86.0-nightly (bef3c3b01 2025-02-04))" -.Linfo_string1: - .asciz "library/core/src/lib.rs/@/core.42399d673965ec88-cgu.0" -.Linfo_string2: - .asciz "/rustc/bef3c3b01f690de16738b1c9f36470fbfc6ac623" -.Linfo_string3: - .asciz "core" -.Linfo_string4: - .asciz "panicking" -.Linfo_string5: - .asciz "_ZN4core9panicking13panic_display17hb27badd535428c70E" -.Linfo_string6: - .asciz "panic_display<&str>" -.Linfo_string7: - .asciz "_ZN4core9panicking9panic_fmt17haebed1323d60a452E" -.Linfo_string8: - .asciz "panic_fmt" -.Linfo_string9: - .asciz "_ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE" -.Linfo_string10: - .asciz "panic_explicit" .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" @@ -790,5 +509,4 @@ _ZN4core9panicking14panic_explicit17hb6ee90eefcf59f2cE: .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" .section ".note.GNU-stack","",%progbits - .section .debug_line,"",%progbits -.Lline_table_start0: + .eabi_attribute 30, 4 From c326e6cf4ad702b74c71cdf96772f995fd5aeab3 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 2 Mar 2025 18:59:51 -0800 Subject: [PATCH 13/32] use stable_likely --- flc-asm/Cargo.toml | 1 + flc-asm/src/lib.rs | 13 ++++----- hal/flc_asm.s | 67 +++++++++++++++++++++++++--------------------- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/flc-asm/Cargo.toml b/flc-asm/Cargo.toml index cecacb9..5877f90 100644 --- a/flc-asm/Cargo.toml +++ b/flc-asm/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" crate-type = ["staticlib"] [dependencies] +likely_stable = "0.1.3" max78000 = { git = "https://github.com/slugsecurity/max78000" } diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 5548575..8002be6 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -17,6 +17,7 @@ use core::{arch::asm, panic::PanicInfo, ptr::read_volatile}; +use likely_stable::likely; use max78000::{FLC, GCR, ICC0}; /// A macro for ensuring that code never exits, even in cases of fault-injection attacks. @@ -131,7 +132,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// - The FLC must be in its ready state after [`Self::wait_until_ready`] #[inline(always)] unsafe fn set_clock_divisor(&self, sys_clk_freq: u32) { - if sys_clk_freq % 1_000_000 != 0 { + if likely(sys_clk_freq % 1_000_000 != 0) { panic() } @@ -270,10 +271,10 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// - `address` must be aligned to 128 bits #[inline(always)] unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk_freq: u32) { - if !check_address_bounds(address..address + 16) { + if likely(!check_address_bounds(address..address + 16)) { panic(); } - if address % size_of::<[u32; 4]>() as u32 != 0 { + if likely(address % size_of::<[u32; 4]>() as u32 != 0) { panic(); } @@ -311,7 +312,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// contained in flash space. #[inline(always)] unsafe fn page_erase(&self, address: u32, sys_clk_freq: u32) { - if !check_address_bounds(address..address + 1) { + if likely(!check_address_bounds(address..address + 1)) { panic() } // SAFETY: the caller must guarantee that `sys_clk_freq` is valid per this function's @@ -335,10 +336,10 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { #[export_name = "flc_read32_primitive"] #[link_section = ".analogsucks"] pub unsafe extern "C" fn read32(address: *const u32) -> u32 { - if !address.is_aligned() { + if likely(!address.is_aligned()) { panic(); } - if !check_address_bounds(address as u32..(address as u32 + 4)) { + if likely(!check_address_bounds(address as u32..(address as u32 + 4))) { panic(); } // SAFETY: the caller must guarantee that `address` is aligned and is within diff --git a/hal/flc_asm.s b/hal/flc_asm.s index c2a0eb9..8581db1 100644 --- a/hal/flc_asm.s +++ b/hal/flc_asm.s @@ -18,7 +18,7 @@ .eabi_attribute 28, 1 .eabi_attribute 38, 1 .eabi_attribute 14, 0 - .file "flc_asm.c1ff00fd3aa9b52e-cgu.0" + .file "flc_asm.167cc79d25ff71c0-cgu.0" .section .analogsucks,"ax",%progbits .globl flc_read32_primitive .p2align 2 @@ -45,11 +45,12 @@ flc_read32_primitive: cmp.w r1, #268435456 bne .LBB0_3 ldr r1, .LCPI0_0 + ldr r2, .LCPI0_1 add r1, r0 - cmp.w r1, #524288 - itt lo - ldrlo r0, [r0] - poplo {r7, pc} + cmp r1, r2 + itt hs + ldrhs r0, [r0] + pophs {r7, pc} .LBB0_3: @APP .Ltmp0: @@ -100,7 +101,9 @@ flc_read32_primitive: .inst.n 0xdefe .p2align 2 .LCPI0_0: - .long 4026531843 + .long 4026007555 +.LCPI0_1: + .long 4294443008 .Lfunc_end0: .size flc_read32_primitive, .Lfunc_end0-flc_read32_primitive .cfi_endproc @@ -137,25 +140,26 @@ flc_write128_primitive: cmp.w r3, #268435456 bne .LBB1_16 ldr r3, .LCPI1_0 + ldr r4, .LCPI1_1 add r3, r0 - cmp.w r3, #524288 - bhs .LBB1_16 + cmp r3, r4 + blo .LBB1_16 lsls r3, r0, #28 bne.w .LBB1_17 - ldr r4, .LCPI1_1 + ldr r4, .LCPI1_2 .LBB1_4: ldr r3, [r4, #8] lsls r3, r3, #7 bmi .LBB1_4 - ldr r3, .LCPI1_2 - ldr r6, .LCPI1_4 + ldr r3, .LCPI1_3 + ldr r6, .LCPI1_5 ldr r5, [r3] bic r5, r5, #1 str r5, [r3] ldr r5, [r4, #36] bic r5, r5, #2 str r5, [r4, #36] - ldr r5, .LCPI1_3 + ldr r5, .LCPI1_4 udiv r5, r2, r5 muls r6, r5, r6 cmn r6, r2 @@ -210,7 +214,7 @@ flc_write128_primitive: mov r0, sp @APP @NO_APP - ldr r0, .LCPI1_5 + ldr r0, .LCPI1_6 ldr r0, [r0] str r0, [sp, #4] add r0, sp, #4 @@ -310,16 +314,18 @@ flc_write128_primitive: .inst.n 0xdefe .p2align 2 .LCPI1_0: - .long 4026531855 + .long 4026007567 .LCPI1_1: - .long 1073909760 + .long 4294443008 .LCPI1_2: - .long 1073914112 + .long 1073909760 .LCPI1_3: - .long 1000000 + .long 1073914112 .LCPI1_4: - .long 4293967296 + .long 1000000 .LCPI1_5: + .long 4293967296 +.LCPI1_6: .long 268443648 .Lfunc_end1: .size flc_write128_primitive, .Lfunc_end1-flc_write128_primitive @@ -496,17 +502,18 @@ flc_page_erase_primitive: .cantunwind .fnend - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" - .ident "rustc version 1.86.0-nightly (bef3c3b01 2025-02-04)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" .section ".note.GNU-stack","",%progbits .eabi_attribute 30, 4 From 4125eb8c005c57852cd16e3d8a2e5c459dc945ae Mon Sep 17 00:00:00 2001 From: m Date: Mon, 3 Mar 2025 16:23:55 -0800 Subject: [PATCH 14/32] try pinning cc=1.1 --- hal/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 7d3ee21..e10d5a0 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -32,4 +32,4 @@ low_frequency = [] flc-ram = ["rt"] [build-dependencies] -cc = "1.2.16" +cc = "1.1" From bcf198841172943e15af29ff9db7c284659ebf7b Mon Sep 17 00:00:00 2001 From: m Date: Mon, 3 Mar 2025 16:27:46 -0800 Subject: [PATCH 15/32] try to appease ci i.e. install multiarch gcc --- .github/workflows/clippy-format-rustdocs.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/clippy-format-rustdocs.yaml b/.github/workflows/clippy-format-rustdocs.yaml index 518c4ba..a979ec4 100644 --- a/.github/workflows/clippy-format-rustdocs.yaml +++ b/.github/workflows/clippy-format-rustdocs.yaml @@ -14,6 +14,7 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" + apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo clippy -- -D warnings @@ -25,6 +26,7 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" + apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo clippy -- -W clippy::pedantic @@ -36,6 +38,7 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" + apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo fmt --check @@ -48,6 +51,7 @@ jobs: eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" rustup target add thumbv7em-none-eabihf + apt install -y gcc-arm-none-eabi RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items - name: upload artifacts uses: actions/upload-artifact@v4 From fcae09afe69495a8745a9f1f18bb68f6396dec66 Mon Sep 17 00:00:00 2001 From: m Date: Mon, 3 Mar 2025 16:29:02 -0800 Subject: [PATCH 16/32] sudo !! --- .github/workflows/clippy-format-rustdocs.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clippy-format-rustdocs.yaml b/.github/workflows/clippy-format-rustdocs.yaml index a979ec4..2634477 100644 --- a/.github/workflows/clippy-format-rustdocs.yaml +++ b/.github/workflows/clippy-format-rustdocs.yaml @@ -14,7 +14,7 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" - apt install -y gcc-arm-none-eabi + sudo apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo clippy -- -D warnings @@ -26,7 +26,7 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" - apt install -y gcc-arm-none-eabi + sudo apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo clippy -- -W clippy::pedantic @@ -38,7 +38,7 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" - apt install -y gcc-arm-none-eabi + sudo apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo fmt --check @@ -51,7 +51,7 @@ jobs: eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" rustup target add thumbv7em-none-eabihf - apt install -y gcc-arm-none-eabi + sudo apt install -y gcc-arm-none-eabi RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items - name: upload artifacts uses: actions/upload-artifact@v4 From c15a9234074efb1d348258e18140e8ea35c9d50c Mon Sep 17 00:00:00 2001 From: m Date: Tue, 4 Mar 2025 00:29:33 -0800 Subject: [PATCH 17/32] appease clippy --- flc-asm/src/lib.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 8002be6..7884b8f 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -83,17 +83,13 @@ struct FlashController<'gcr, 'icc> { #[inline(always)] #[must_use] const fn check_address_bounds(address_range: core::ops::Range) -> bool { - if !(FLASH_MEM_BASE <= address_range.start + FLASH_MEM_BASE <= address_range.start && address_range.start < FLASH_MEM_BASE + FLASH_MEM_SIZE && FLASH_MEM_BASE < address_range.end - && address_range.end <= FLASH_MEM_BASE + FLASH_MEM_SIZE) - { - return false; - } - return true; + && address_range.end <= FLASH_MEM_BASE + FLASH_MEM_SIZE } -impl<'gcr, 'icc> FlashController<'gcr, 'icc> { +impl FlashController<'_, '_> { /// Unlocks memory protection to allow flash operations. /// /// This MUST be called before any non-read flash controller operation. @@ -217,6 +213,8 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { assert!(check_address_bounds(PAGE2..PAGE2 + 4)); assert!(PAGE2 % 4 == 0); } + + // SAFETY: `FLASH_MEM_BASE` points to a valid, aligned word within flash space as asserted above. unsafe { core::hint::black_box(read32(PAGE1 as *const u32)) }; // SAFETY: `FLASH_MEM_BASE + FLASH_PAGE_SIZE` points to a valid, aligned word within flash space. unsafe { core::hint::black_box(read32(PAGE2 as *const u32)) }; @@ -253,9 +251,9 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// - The argument `sys_clk_freq` must be equal to the current system clock's /// frequency divided by its divider. /// - Writes must not corrupt potentially executable instructions of the program. - /// Callers must ensure that the following condition is met: - /// * If `address` points to a portion of the program's instructions, `data` must - /// contain valid instructions that does not introduce undefined behavior. + /// - Callers must ensure that the following condition is met: + /// * If `address` points to a portion of the program's instructions, `data` must + /// contain valid instructions that does not introduce undefined behavior. /// /// It is very difficult to define what would cause undefined behavior when /// modifying program instructions. This would almost certainly result @@ -333,6 +331,11 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { /// Panics if any of the following preconditions are not true: /// - `address` must be 32-bit aligned. /// - `address` must point to a valid location in flash memory (`0x1000_0000..=0x1007_ffff`). +/// +/// # Safety +/// +/// This is a pointer read to flash space, it is the caller's responsibility to ensure +/// that the pointer points to the correct value. #[export_name = "flc_read32_primitive"] #[link_section = ".analogsucks"] pub unsafe extern "C" fn read32(address: *const u32) -> u32 { @@ -349,7 +352,8 @@ pub unsafe extern "C" fn read32(address: *const u32) -> u32 { /// Writes a little-endian 128-bit flash word into flash memory. /// -/// Safety: +/// # Safety +/// /// - The caller must hold a shared reference to the [`FLC`], [`ICC0`], and [`GCR`] registers. /// - The flash word at `address` must be in the *erased* state (with [`page_erase`]). /// - `data` must point to an array of four `u32`s. @@ -358,6 +362,8 @@ pub unsafe extern "C" fn read32(address: *const u32) -> u32 { /// - If `address` writes to an address in the currently-running program's instruction space, /// it must be valid instructions. /// +/// # Panics +/// /// Panics if any of the following preconditions are not true: /// - `address` must be 128-bit aligned. /// - The entire flash word at address (bytes `address..address + 16`) must be within @@ -391,7 +397,8 @@ pub unsafe extern "C" fn write128(address: *mut [u32; 4], data: *const u32, sys_ /// Erases the page at the given address in flash memory. /// -/// Safety: +/// # Safety +/// /// - The caller must hold a shared reference to the [`FLC`], [`ICC0`], and [`GCR`] registers. /// - `address` must point to a valid page within flash memory (`0x1000_0000..=0x1007_ffff`). /// - `sys_clk_freq` must be equal to `freq / div` where `freq` is the frequency of @@ -400,6 +407,8 @@ pub unsafe extern "C" fn write128(address: *mut [u32; 4], data: *const u32, sys_ /// - If `address` erases a page in the currently-running program's instruction space, /// it must be rewritten with [`write128`] before the program reaches those instructions. /// +/// # Panics +/// /// Panics if any of the following preconditions are not true: /// - `address` must point to within a valid page in flash space (`0x1000_000..=0x1007_ffff`) /// - `sys_clk_freq` must be divisible by one million (`1_000_000`). From 1a238a2d8ea415834d945bded77160b1e0031243 Mon Sep 17 00:00:00 2001 From: m Date: Tue, 4 Mar 2025 00:36:02 -0800 Subject: [PATCH 18/32] clippy pedantic --- flc-asm/src/lib.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 7884b8f..56712c4 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -14,6 +14,10 @@ unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks )] +#![allow( + clippy::inline_always, + reason = "we need the functions to be inlined in this specific case" +)] use core::{arch::asm, panic::PanicInfo, ptr::read_volatile}; @@ -200,12 +204,14 @@ impl FlashController<'_, '_> { /// This MUST be called after any write/erase flash controller operations. #[inline(always)] fn flush_icc(&self) { + const PAGE1: u32 = FLASH_MEM_BASE; + const PAGE2: u32 = FLASH_MEM_BASE + FLASH_PAGE_SIZE; + self.gcr.sysctrl().modify(|_, w| w.icc0_flush().flush()); while !self.gcr.sysctrl().read().icc0_flush().bit_is_clear() {} // Clear the line fill buffer by reading 2 pages from flash - const PAGE1: u32 = FLASH_MEM_BASE; - const PAGE2: u32 = FLASH_MEM_BASE + FLASH_PAGE_SIZE; + // SAFETY: `FLASH_MEM_BASE` points to a valid, aligned word within flash space. const { assert!(check_address_bounds(PAGE1..PAGE1 + 4)); @@ -272,6 +278,10 @@ impl FlashController<'_, '_> { if likely(!check_address_bounds(address..address + 16)) { panic(); } + #[allow( + clippy::cast_possible_truncation, + reason = "the target pointer width is 32, so this will not truncate" + )] if likely(address % size_of::<[u32; 4]>() as u32 != 0) { panic(); } @@ -310,6 +320,10 @@ impl FlashController<'_, '_> { /// contained in flash space. #[inline(always)] unsafe fn page_erase(&self, address: u32, sys_clk_freq: u32) { + #[allow( + clippy::range_plus_one, + reason = "the caller takes a Range struct, not an `impl RangeBounds`" + )] if likely(!check_address_bounds(address..address + 1)) { panic() } @@ -382,7 +396,7 @@ pub unsafe extern "C" fn write128(address: *mut [u32; 4], data: *const u32, sys_ }; // SAFETY: the caller must ensure that `data` points to a valid array of four `u32`s. - let data = unsafe { &*(data as *const [u32; 4]) }; + let data = unsafe { &*data.cast() }; // SAFETY: // - the caller must guarantee that the address is aligned and the word is within flash space From 750012a7e42301008b530650eedc84c02fea3832 Mon Sep 17 00:00:00 2001 From: m Date: Tue, 4 Mar 2025 19:27:33 -0800 Subject: [PATCH 19/32] rustdoc nitfixes --- hal/src/peripherals/flash_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index ea290bf..460befe 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -89,7 +89,7 @@ unsafe extern "C" { /// the current system clock, and `div` is the divider of the system clock. /// - `sys_clk_freq` must be divisible by one million (`1_000_000`). /// - If `address` erases a page in the currently-running program's instruction space, - /// it must be rewritten with [`write128`] before the program reaches those instructions. + /// it must be rewritten with `write128` before the program reaches those instructions. /// /// Panics if any of the following preconditions are not true: /// - `address` must point to within a valid page in flash space (`0x1000_000..=0x1007_ffff`) @@ -100,7 +100,7 @@ unsafe extern "C" { /// /// Safety: /// - The caller must hold a shared reference to the [`FLC`], [`ICC0`], and [`GCR`] registers. - /// - The flash word at `address` must be in the *erased* state (with [`page_erase`]). + /// - The flash word at `address` must be in the *erased* state (with `page_erase`). /// - `data` must point to an array of four `u32`s. /// - `sys_clk_freq` must be equal to `freq / div` where `freq` is the frequency of /// the current system clock, and `div` is the divider of the system clock. From 253a49ddf7a8a185ccffb6ed42444ee66a15ba88 Mon Sep 17 00:00:00 2001 From: m Date: Tue, 4 Mar 2025 19:28:42 -0800 Subject: [PATCH 20/32] revert runner change --- .cargo/config.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index a03c2a8..0156fd5 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,7 +5,5 @@ target = "thumbv7em-none-eabihf" git-fetch-with-cli = true [target.thumbv7em-none-eabihf] -runner = 'gdb' -rustflags = [ - "-C", "link-arg=-Tlink.x", -] +runner = 'arm-none-eabi-gdb' +rustflags = ["-C", "link-arg=-Tlink.x"] From 518bddd68ec0795a538e6a936fdcb30d6ebe9e36 Mon Sep 17 00:00:00 2001 From: m Date: Tue, 4 Mar 2025 19:36:23 -0800 Subject: [PATCH 21/32] its a *ci thing * --- .github/workflows/clippy-format-rustdocs.yaml | 8 ++++++++ hal/src/lib.rs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clippy-format-rustdocs.yaml b/.github/workflows/clippy-format-rustdocs.yaml index 2634477..cac0656 100644 --- a/.github/workflows/clippy-format-rustdocs.yaml +++ b/.github/workflows/clippy-format-rustdocs.yaml @@ -14,6 +14,8 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" + echo 'set man-db/auto-update false' | sudo debconf-communicate >/dev/null + sudo dpkg-reconfigure man-db sudo apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo clippy -- -D warnings @@ -26,6 +28,8 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" + echo 'set man-db/auto-update false' | sudo debconf-communicate >/dev/null + sudo dpkg-reconfigure man-db sudo apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo clippy -- -W clippy::pedantic @@ -38,6 +42,8 @@ jobs: run: | eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" + echo 'set man-db/auto-update false' | sudo debconf-communicate >/dev/null + sudo dpkg-reconfigure man-db sudo apt install -y gcc-arm-none-eabi rustup target add thumbv7em-none-eabihf cargo fmt --check @@ -51,6 +57,8 @@ jobs: eval $(ssh-agent -s) ssh-add - <<< "${{ secrets.PRIVATE_SSH_KEY }}" rustup target add thumbv7em-none-eabihf + echo 'set man-db/auto-update false' | sudo debconf-communicate >/dev/null + sudo dpkg-reconfigure man-db sudo apt install -y gcc-arm-none-eabi RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items - name: upload artifacts diff --git a/hal/src/lib.rs b/hal/src/lib.rs index b42475d..c7b6ee6 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -30,7 +30,7 @@ //! where the `ANALOGSUCKS` is a memory section in RAM defined in `memory.x`. //! //! [`pre_init`]: cortex_m_rt::pre_init -//! [`FlashController`]: peripherals::FlashController +//! [`FlashController`]: peripherals::flash_controller::FlashController #![warn(missing_docs)] #![no_std] From 66dba6a246bcdbbf31be3f56f99d0b4f419470c1 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 11:33:05 -0800 Subject: [PATCH 22/32] remove likely and fix build script --- flc-asm/Cargo.toml | 1 - flc-asm/src/lib.rs | 13 ++++++------- hal/build.rs | 14 ++++++++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/flc-asm/Cargo.toml b/flc-asm/Cargo.toml index 5877f90..cecacb9 100644 --- a/flc-asm/Cargo.toml +++ b/flc-asm/Cargo.toml @@ -7,5 +7,4 @@ edition = "2021" crate-type = ["staticlib"] [dependencies] -likely_stable = "0.1.3" max78000 = { git = "https://github.com/slugsecurity/max78000" } diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 56712c4..f66f84b 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -21,7 +21,6 @@ use core::{arch::asm, panic::PanicInfo, ptr::read_volatile}; -use likely_stable::likely; use max78000::{FLC, GCR, ICC0}; /// A macro for ensuring that code never exits, even in cases of fault-injection attacks. @@ -132,7 +131,7 @@ impl FlashController<'_, '_> { /// - The FLC must be in its ready state after [`Self::wait_until_ready`] #[inline(always)] unsafe fn set_clock_divisor(&self, sys_clk_freq: u32) { - if likely(sys_clk_freq % 1_000_000 != 0) { + if sys_clk_freq % 1_000_000 != 0 { panic() } @@ -275,14 +274,14 @@ impl FlashController<'_, '_> { /// - `address` must be aligned to 128 bits #[inline(always)] unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk_freq: u32) { - if likely(!check_address_bounds(address..address + 16)) { + if !check_address_bounds(address..address + 16) { panic(); } #[allow( clippy::cast_possible_truncation, reason = "the target pointer width is 32, so this will not truncate" )] - if likely(address % size_of::<[u32; 4]>() as u32 != 0) { + if address % size_of::<[u32; 4]>() as u32 != 0 { panic(); } @@ -324,7 +323,7 @@ impl FlashController<'_, '_> { clippy::range_plus_one, reason = "the caller takes a Range struct, not an `impl RangeBounds`" )] - if likely(!check_address_bounds(address..address + 1)) { + if !check_address_bounds(address..address + 1) { panic() } // SAFETY: the caller must guarantee that `sys_clk_freq` is valid per this function's @@ -353,10 +352,10 @@ impl FlashController<'_, '_> { #[export_name = "flc_read32_primitive"] #[link_section = ".analogsucks"] pub unsafe extern "C" fn read32(address: *const u32) -> u32 { - if likely(!address.is_aligned()) { + if !address.is_aligned() { panic(); } - if likely(!check_address_bounds(address as u32..(address as u32 + 4))) { + if !check_address_bounds(address as u32..(address as u32 + 4)) { panic(); } // SAFETY: the caller must guarantee that `address` is aligned and is within diff --git a/hal/build.rs b/hal/build.rs index 11ee9aa..bf25bb2 100644 --- a/hal/build.rs +++ b/hal/build.rs @@ -1,8 +1,8 @@ -use std::{env, fs::File, io::Write, path::PathBuf}; +#[cfg(feature = "flc-ram")] +fn compile_flc_asm() { + use std::{env, fs::File, io::Write, path::PathBuf}; -fn main() { let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let flc_asm_path = out.join("flc_asm.s"); File::create(&flc_asm_path) .unwrap() @@ -11,6 +11,12 @@ fn main() { cc::Build::new().file(&flc_asm_path).compile("flc_asm"); - println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=flc_asm.s"); } + +fn main() { + #[cfg(feature = "flc-ram")] + compile_flc_asm(); + + println!("cargo:rerun-if-changed=build.rs"); +} From 7fa60540b797ff0166111f0b0cd3185b52c7a43d Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 11:36:47 -0800 Subject: [PATCH 23/32] update flc_asm.s --- hal/flc_asm.s | 68 +++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/hal/flc_asm.s b/hal/flc_asm.s index 8581db1..d8f81db 100644 --- a/hal/flc_asm.s +++ b/hal/flc_asm.s @@ -18,7 +18,7 @@ .eabi_attribute 28, 1 .eabi_attribute 38, 1 .eabi_attribute 14, 0 - .file "flc_asm.167cc79d25ff71c0-cgu.0" + .file "flc_asm.b33526c4dbe694e0-cgu.0" .section .analogsucks,"ax",%progbits .globl flc_read32_primitive .p2align 2 @@ -45,12 +45,11 @@ flc_read32_primitive: cmp.w r1, #268435456 bne .LBB0_3 ldr r1, .LCPI0_0 - ldr r2, .LCPI0_1 add r1, r0 - cmp r1, r2 - itt hs - ldrhs r0, [r0] - pophs {r7, pc} + cmp.w r1, #524288 + itt lo + ldrlo r0, [r0] + poplo {r7, pc} .LBB0_3: @APP .Ltmp0: @@ -101,9 +100,7 @@ flc_read32_primitive: .inst.n 0xdefe .p2align 2 .LCPI0_0: - .long 4026007555 -.LCPI0_1: - .long 4294443008 + .long 4026531843 .Lfunc_end0: .size flc_read32_primitive, .Lfunc_end0-flc_read32_primitive .cfi_endproc @@ -140,26 +137,25 @@ flc_write128_primitive: cmp.w r3, #268435456 bne .LBB1_16 ldr r3, .LCPI1_0 - ldr r4, .LCPI1_1 add r3, r0 - cmp r3, r4 - blo .LBB1_16 + cmp.w r3, #524288 + bhs .LBB1_16 lsls r3, r0, #28 bne.w .LBB1_17 - ldr r4, .LCPI1_2 + ldr r4, .LCPI1_1 .LBB1_4: ldr r3, [r4, #8] lsls r3, r3, #7 bmi .LBB1_4 - ldr r3, .LCPI1_3 - ldr r6, .LCPI1_5 + ldr r3, .LCPI1_2 + ldr r6, .LCPI1_4 ldr r5, [r3] bic r5, r5, #1 str r5, [r3] ldr r5, [r4, #36] bic r5, r5, #2 str r5, [r4, #36] - ldr r5, .LCPI1_4 + ldr r5, .LCPI1_3 udiv r5, r2, r5 muls r6, r5, r6 cmn r6, r2 @@ -214,7 +210,7 @@ flc_write128_primitive: mov r0, sp @APP @NO_APP - ldr r0, .LCPI1_6 + ldr r0, .LCPI1_5 ldr r0, [r0] str r0, [sp, #4] add r0, sp, #4 @@ -314,18 +310,16 @@ flc_write128_primitive: .inst.n 0xdefe .p2align 2 .LCPI1_0: - .long 4026007567 + .long 4026531855 .LCPI1_1: - .long 4294443008 -.LCPI1_2: .long 1073909760 -.LCPI1_3: +.LCPI1_2: .long 1073914112 -.LCPI1_4: +.LCPI1_3: .long 1000000 -.LCPI1_5: +.LCPI1_4: .long 4293967296 -.LCPI1_6: +.LCPI1_5: .long 268443648 .Lfunc_end1: .size flc_write128_primitive, .Lfunc_end1-flc_write128_primitive @@ -502,18 +496,18 @@ flc_page_erase_primitive: .cantunwind .fnend - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" - .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" .section ".note.GNU-stack","",%progbits .eabi_attribute 30, 4 From 603c4e75a8a197df8b3d507286d0e0afdc38636e Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 22:38:10 -0800 Subject: [PATCH 24/32] remove old inlines --- hal/src/peripherals/oscillator.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/hal/src/peripherals/oscillator.rs b/hal/src/peripherals/oscillator.rs index 8913254..6b82997 100644 --- a/hal/src/peripherals/oscillator.rs +++ b/hal/src/peripherals/oscillator.rs @@ -305,13 +305,11 @@ impl<'a, 'b> SystemClock<'a, 'b> { } /// Returns the clock divider of the SYS_OSC - #[inline(always)] pub fn get_div(&self) -> u8 { self.clock_divider } /// Returns the frequency of the SYS_OSC in hertz - #[inline(always)] pub fn get_freq(&self) -> u32 { self.clock_frequency } From 9da8c8d280c9c97e09ca8920a48cdc9d7dd54e10 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 22:40:13 -0800 Subject: [PATCH 25/32] build with no warnings with no flc-asm feature --- hal/src/peripherals.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/src/peripherals.rs b/hal/src/peripherals.rs index d0c65f5..f795fc4 100644 --- a/hal/src/peripherals.rs +++ b/hal/src/peripherals.rs @@ -173,6 +173,7 @@ pub struct PeripheralsToBorrow { /// The peripherals that are completely consumed and moved by the [`PeripheralManager`]. pub struct PeripheralsToConsume { + #[cfg(feature = "flc-ram")] flc: FLC, gpio0: GPIO0, gpio1: GPIO1, @@ -210,6 +211,7 @@ impl SplittablePeripheral for Peripherals { RemainingPeripherals, ) { let to_consume = PeripheralsToConsume { + #[cfg(feature = "flc-ram")] flc: self.FLC, gpio0: self.GPIO0, gpio1: self.GPIO1, From 6531ac9192c5c6bc7fbcce4235d72eddadeada9e Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 22:43:41 -0800 Subject: [PATCH 26/32] add receiver back to read_bytes --- hal/src/peripherals/flash_controller.rs | 4 ++-- tests/src/tests/flc_tests.rs | 24 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/hal/src/peripherals/flash_controller.rs b/hal/src/peripherals/flash_controller.rs index 460befe..66233c0 100644 --- a/hal/src/peripherals/flash_controller.rs +++ b/hal/src/peripherals/flash_controller.rs @@ -151,7 +151,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { } /// Reads data from flash. - pub fn read_bytes(address: u32, data: &mut [u8]) -> Result<(), FlashErr> { + pub fn read_bytes(&self, address: u32, data: &mut [u8]) -> Result<(), FlashErr> { // change to range check check_address_bounds(address..(address + data.len() as u32))?; @@ -280,7 +280,7 @@ impl<'gcr, 'icc> FlashController<'gcr, 'icc> { let aligned_addr = address & !0xF; let mut current_bytes: [u8; 16] = [0; 16]; - Self::read_bytes(aligned_addr, &mut current_bytes[..])?; + self.read_bytes(aligned_addr, &mut current_bytes[..])?; // construct 128 bits of data to write back to flash current_bytes[byte_idx..(byte_idx + data.len())].copy_from_slice(data); diff --git a/tests/src/tests/flc_tests.rs b/tests/src/tests/flc_tests.rs index 2ddd040..0534520 100644 --- a/tests/src/tests/flc_tests.rs +++ b/tests/src/tests/flc_tests.rs @@ -90,7 +90,9 @@ fn flash_write(flash_controller: &FlashController, sys_clk: &SystemClock) { flash_controller .write(test_addr, &u32::to_le_bytes(test_val), sys_clk) .unwrap(); - FlashController::read_bytes(test_addr, &mut data_read).unwrap(); + flash_controller + .read_bytes(test_addr, &mut data_read) + .unwrap(); } assert!(u32::from_le_bytes(data_read) == test_val); @@ -106,7 +108,9 @@ fn flash_write_large(flash_controller: &FlashController, sys_clk: &SystemClock) flash_controller .write(test_addr, &test_data, sys_clk) .unwrap(); - FlashController::read_bytes(test_addr, &mut read_data).unwrap(); + flash_controller + .read_bytes(test_addr, &mut read_data) + .unwrap(); } assert!(test_data == read_data); @@ -122,7 +126,9 @@ fn flash_write_extra_large(flash_controller: &FlashController, sys_clk: &SystemC flash_controller .write(test_addr, &test_data, sys_clk) .unwrap(); - FlashController::read_bytes(test_addr, &mut read_data).unwrap(); + flash_controller + .read_bytes(test_addr, &mut read_data) + .unwrap(); } assert!(test_data == read_data); @@ -138,7 +144,9 @@ fn flash_write_unaligned(flash_controller: &FlashController, sys_clk: &SystemClo flash_controller .write(test_addr, &test_data, sys_clk) .unwrap(); - FlashController::read_bytes(test_addr, &mut read_data).unwrap(); + flash_controller + .read_bytes(test_addr, &mut read_data) + .unwrap(); } assert!(test_data == read_data); @@ -169,7 +177,9 @@ fn flash_write_after_sys_osc_switch(flash_controller: &FlashController, sys_clk: flash_controller .write(test_addr, test_data, sys_clk) .unwrap(); - FlashController::read_bytes(test_addr, &mut read_data).unwrap(); + flash_controller + .read_bytes(test_addr, &mut read_data) + .unwrap(); } assert!(test_data == read_data); @@ -189,7 +199,9 @@ fn flash_write_after_sys_clk_div_changes( flash_controller .write(test_addr, test_data, sys_clk) .unwrap(); - FlashController::read_bytes(test_addr, &mut read_data).unwrap(); + flash_controller + .read_bytes(test_addr, &mut read_data) + .unwrap(); } assert!(test_data == read_data); From ca476cc6cff6453f03f0718e2bd21e6aa9dcd220 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 22:46:24 -0800 Subject: [PATCH 27/32] doc pre_init --- hal/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index c7b6ee6..a7554c1 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -46,6 +46,15 @@ pub use cortex_m_rt::{interrupt, pre_init}; pub mod communication; pub mod peripherals; +/// `__pre_init` symbol, ran before initializing memory in [`cortex-m-rt`]. See +/// [`pre_init`] for more. +/// +/// # Safety +/// +/// - Only assembly is allowed, because RAM has not been initialized, so any Rust +/// code that touches memory or the stack is undefined behavior. +/// +/// [`pre_init`]: cortex_m_rt::pre_init #[cfg(feature = "rt")] #[pre_init] unsafe fn pre_init() { From 2773707eedf9a49564d162c9849b7f8e5db72677 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 22:55:40 -0800 Subject: [PATCH 28/32] whitespace in memory.exes --- memory.x.example | 8 ++++---- tests/memory.x | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/memory.x.example b/memory.x.example index c79c034..a489a66 100644 --- a/memory.x.example +++ b/memory.x.example @@ -1,9 +1,9 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K - STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K - ANALOGSUCKS (rx) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 10K - RAM (rw) : ORIGIN = ORIGIN(ANALOGSUCKS) + LENGTH(ANALOGSUCKS), LENGTH = 128K - LENGTH(STACK) - LENGTH(ANALOGSUCKS) + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K + STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K + ANALOGSUCKS (rx) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 10K + RAM (rw) : ORIGIN = ORIGIN(ANALOGSUCKS) + LENGTH(ANALOGSUCKS), LENGTH = 128K - LENGTH(STACK) - LENGTH(ANALOGSUCKS) } _stack_start = ORIGIN(STACK) + LENGTH(STACK); diff --git a/tests/memory.x b/tests/memory.x index c79c034..a489a66 100644 --- a/tests/memory.x +++ b/tests/memory.x @@ -1,9 +1,9 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K - STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K - ANALOGSUCKS (rx) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 10K - RAM (rw) : ORIGIN = ORIGIN(ANALOGSUCKS) + LENGTH(ANALOGSUCKS), LENGTH = 128K - LENGTH(STACK) - LENGTH(ANALOGSUCKS) + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K + STACK (rw) : ORIGIN = 0x20000000, LENGTH = 110K + ANALOGSUCKS (rx) : ORIGIN = ORIGIN(STACK) + LENGTH(STACK), LENGTH = 10K + RAM (rw) : ORIGIN = ORIGIN(ANALOGSUCKS) + LENGTH(ANALOGSUCKS), LENGTH = 128K - LENGTH(STACK) - LENGTH(ANALOGSUCKS) } _stack_start = ORIGIN(STACK) + LENGTH(STACK); From 03c24b4e486cc0eb3e44a3578e21011088b0e571 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 23:00:15 -0800 Subject: [PATCH 29/32] dont inline as much --- flc-asm/src/lib.rs | 25 +- hal/flc_asm.s | 604 +++++++++++++++++++++++---------------------- 2 files changed, 320 insertions(+), 309 deletions(-) diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index f66f84b..15f4e49 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -56,6 +56,7 @@ macro_rules! never_exit { } #[panic_handler] +#[link_section = ".analogsucks"] fn panic_handler(_: &PanicInfo) -> ! { never_exit!() } @@ -83,8 +84,8 @@ struct FlashController<'gcr, 'icc> { /// Checks whether the given address range (exclusive) is within flash space, returning `false` if there /// is an error. -#[inline(always)] #[must_use] +#[link_section = ".analogsucks"] const fn check_address_bounds(address_range: core::ops::Range) -> bool { FLASH_MEM_BASE <= address_range.start && address_range.start < FLASH_MEM_BASE + FLASH_MEM_SIZE @@ -99,7 +100,7 @@ impl FlashController<'_, '_> { /// /// # Safety /// - The FLC must be in its ready state after [`Self::wait_until_ready`] - #[inline(always)] + #[link_section = ".analogsucks"] unsafe fn unlock_write_protection(&self) { self.flc.ctrl().modify(|_, w| w.unlock().unlocked()); } @@ -110,7 +111,7 @@ impl FlashController<'_, '_> { /// /// # Safety /// - The FLC must be in its ready state after [`Self::wait_until_ready`] - #[inline(always)] + #[link_section = ".analogsucks"] unsafe fn lock_write_protection(&self) { self.flc.ctrl().modify(|_, w| w.unlock().locked()); } @@ -129,7 +130,7 @@ impl FlashController<'_, '_> { /// - The passed argument `sys_clk_freq` must be the current system clock's /// frequency divided by its divider. /// - The FLC must be in its ready state after [`Self::wait_until_ready`] - #[inline(always)] + #[link_section = ".analogsucks"] unsafe fn set_clock_divisor(&self, sys_clk_freq: u32) { if sys_clk_freq % 1_000_000 != 0 { panic() @@ -145,7 +146,7 @@ impl FlashController<'_, '_> { /// Wait, by busy-looping, until the FLC is ready. /// /// This MUST be called BEFORE any FLC operation EXCEPT clearing interrupts. - #[inline(always)] + #[link_section = ".analogsucks"] fn wait_until_ready(&self) { while !self.flc.ctrl().read().pend().bit_is_clear() {} } @@ -153,7 +154,7 @@ impl FlashController<'_, '_> { /// Clear any stale errors in the FLC interrupt register. /// /// This can be called without waiting for the FLC to be ready. - #[inline(always)] + #[link_section = ".analogsucks"] fn clear_interrupts(&self) { self.flc.intr().modify(|_, w| w.af().clear_bit()); } @@ -167,7 +168,7 @@ impl FlashController<'_, '_> { /// /// # Panics /// - If `sys_clk_freq` is not a multiple of 1 MHz, this function panics. - #[inline(always)] + #[link_section = ".analogsucks"] unsafe fn write_guard(&self, sys_clk_freq: u32, operation: F) { // Pre-write self.wait_until_ready(); @@ -201,7 +202,7 @@ impl FlashController<'_, '_> { /// Flushes the flash line buffer and arm instruction cache. /// /// This MUST be called after any write/erase flash controller operations. - #[inline(always)] + #[link_section = ".analogsucks"] fn flush_icc(&self) { const PAGE1: u32 = FLASH_MEM_BASE; const PAGE2: u32 = FLASH_MEM_BASE + FLASH_PAGE_SIZE; @@ -228,7 +229,7 @@ impl FlashController<'_, '_> { /// Disables instruction cache. /// /// This MUST be called before any non-read flash controller operations. - #[inline(always)] + #[link_section = ".analogsucks"] fn disable_icc0(&self) { self.icc.ctrl().modify(|_, w| w.en().dis()); } @@ -236,7 +237,7 @@ impl FlashController<'_, '_> { /// Enables instruction cache. /// /// This MUST be called after any non-read flash controller operations. - #[inline(always)] + #[link_section = ".analogsucks"] fn enable_icc0(&self) { // ensure the cache is invalidated when enabled self.disable_icc0(); @@ -272,7 +273,7 @@ impl FlashController<'_, '_> { /// - `sys_clk_freq` must be a multiple of 1 MHz /// - `address` must point to a word contained in flash space /// - `address` must be aligned to 128 bits - #[inline(always)] + #[link_section = ".analogsucks"] unsafe fn write128(&self, address: u32, data: &[u32; 4], sys_clk_freq: u32) { if !check_address_bounds(address..address + 16) { panic(); @@ -317,7 +318,7 @@ impl FlashController<'_, '_> { /// - If `sys_clk_freq` is not a multiple of 1 MHz, this function panics. /// - This function also panics when the `address` does not point inside of a page /// contained in flash space. - #[inline(always)] + #[link_section = ".analogsucks"] unsafe fn page_erase(&self, address: u32, sys_clk_freq: u32) { #[allow( clippy::range_plus_one, diff --git a/hal/flc_asm.s b/hal/flc_asm.s index d8f81db..af8c4be 100644 --- a/hal/flc_asm.s +++ b/hal/flc_asm.s @@ -18,14 +18,13 @@ .eabi_attribute 28, 1 .eabi_attribute 38, 1 .eabi_attribute 14, 0 - .file "flc_asm.b33526c4dbe694e0-cgu.0" + .file "flc_asm.d8eec276ff8a6799-cgu.0" .section .analogsucks,"ax",%progbits - .globl flc_read32_primitive .p2align 2 - .type flc_read32_primitive,%function + .type _ZN7flc_asm15FlashController17set_clock_divisor17hc5cf0d05434ae31dE,%function .code 16 .thumb_func -flc_read32_primitive: +_ZN7flc_asm15FlashController17set_clock_divisor17hc5cf0d05434ae31dE: .Lfunc_begin0: .fnstart .cfi_sections .debug_frame @@ -38,19 +37,19 @@ flc_read32_primitive: .setfp r7, sp mov r7, sp .cfi_def_cfa_register r7 - lsls r1, r0, #30 - bne .LBB0_4 - mov r1, r0 - bfc r1, #0, #19 - cmp.w r1, #268435456 - bne .LBB0_3 ldr r1, .LCPI0_0 - add r1, r0 - cmp.w r1, #524288 - itt lo - ldrlo r0, [r0] - poplo {r7, pc} -.LBB0_3: + ldr r2, .LCPI0_1 + udiv r1, r0, r1 + muls r2, r1, r2 + cmn r2, r0 + itttt eq + ldreq r0, .LCPI0_2 + ldreq r2, [r0] + bfieq r2, r1, #0, #8 + streq r2, [r0] + it eq + popeq {r7, pc} +.LBB0_1: @APP .Ltmp0: b .Ltmp0 @@ -74,169 +73,174 @@ flc_read32_primitive: b .Ltmp0 @NO_APP .inst.n 0xdefe -.LBB0_4: - @APP -.Ltmp1: - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - b .Ltmp1 - @NO_APP - .inst.n 0xdefe .p2align 2 .LCPI0_0: - .long 4026531843 + .long 1000000 +.LCPI0_1: + .long 4293967296 +.LCPI0_2: + .long 1073909764 .Lfunc_end0: - .size flc_read32_primitive, .Lfunc_end0-flc_read32_primitive + .size _ZN7flc_asm15FlashController17set_clock_divisor17hc5cf0d05434ae31dE, .Lfunc_end0-_ZN7flc_asm15FlashController17set_clock_divisor17hc5cf0d05434ae31dE .cfi_endproc .cantunwind .fnend - .globl flc_write128_primitive .p2align 2 - .type flc_write128_primitive,%function + .type _ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E,%function .code 16 .thumb_func -flc_write128_primitive: +_ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E: .Lfunc_begin1: .fnstart .cfi_startproc - .save {r4, r5, r6, r7, lr} - push {r4, r5, r6, r7, lr} - .cfi_def_cfa_offset 20 - .cfi_offset lr, -4 - .cfi_offset r7, -8 - .cfi_offset r6, -12 - .cfi_offset r5, -16 - .cfi_offset r4, -20 - .setfp r7, sp, #12 - add r7, sp, #12 - .cfi_def_cfa r7, 8 - .save {r11} - str r11, [sp, #-4]! - .cfi_offset r11, -24 + ldr r0, .LCPI1_0 +.LBB1_1: + ldr r1, [r0] + lsls r1, r1, #7 + bmi .LBB1_1 + bx lr + .p2align 2 +.LCPI1_0: + .long 1073909768 +.Lfunc_end1: + .size _ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E, .Lfunc_end1-_ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E + .cfi_endproc + .cantunwind + .fnend + + .p2align 2 + .type _ZN7flc_asm15FlashController9flush_icc17hdfc1ef73516cdd37E,%function + .code 16 + .thumb_func +_ZN7flc_asm15FlashController9flush_icc17hdfc1ef73516cdd37E: +.Lfunc_begin2: + .fnstart + .cfi_startproc .pad #8 sub sp, #8 - mov r3, r0 - bfc r3, #0, #19 - cmp.w r3, #268435456 - bne .LBB1_16 - ldr r3, .LCPI1_0 - add r3, r0 - cmp.w r3, #524288 - bhs .LBB1_16 - lsls r3, r0, #28 - bne.w .LBB1_17 - ldr r4, .LCPI1_1 -.LBB1_4: - ldr r3, [r4, #8] - lsls r3, r3, #7 - bmi .LBB1_4 - ldr r3, .LCPI1_2 - ldr r6, .LCPI1_4 - ldr r5, [r3] - bic r5, r5, #1 - str r5, [r3] - ldr r5, [r4, #36] - bic r5, r5, #2 - str r5, [r4, #36] - ldr r5, .LCPI1_3 - udiv r5, r2, r5 - muls r6, r5, r6 - cmn r6, r2 - bne.w .LBB1_18 - ldr r2, [r4, #4] - bfi r2, r5, #0, #8 - str r2, [r4, #4] - ldr r2, [r4, #8] - movs r5, #2 - bfi r2, r5, #28, #4 - str r2, [r4, #8] - ldr r2, [r4] - str r0, [r4] - ldr r0, [r4, #48] - ldr r0, [r1] - str r0, [r4, #48] - ldr r0, [r4, #52] - ldr r0, [r1, #4] - str r0, [r4, #52] - ldr r0, [r4, #56] - ldr r0, [r1, #8] - str r0, [r4, #56] - ldr r0, [r4, #60] - ldr r0, [r1, #12] - str r0, [r4, #60] - ldr r0, [r4, #8] - orr r0, r0, #1 - str r0, [r4, #8] -.LBB1_7: - ldr r0, [r4, #8] - lsls r0, r0, #31 - bne .LBB1_7 -.LBB1_8: - ldr r0, [r4, #8] - lsls r0, r0, #7 - bmi .LBB1_8 - ldr r0, [r4, #8] - movs r1, #3 - bfi r0, r1, #28, #4 - str r0, [r4, #8] + .cfi_def_cfa_offset 8 mov.w r0, #1073741824 ldr r1, [r0] orr r1, r1, #64 str r1, [r0] -.LBB1_10: +.LBB2_1: ldr r1, [r0] lsls r1, r1, #25 - bmi .LBB1_10 + bmi .LBB2_1 mov.w r0, #268435456 ldr r0, [r0] str r0, [sp] mov r0, sp @APP @NO_APP - ldr r0, .LCPI1_5 + ldr r0, .LCPI2_0 ldr r0, [r0] str r0, [sp, #4] add r0, sp, #4 @APP @NO_APP - ldr r0, [r3] - bic r0, r0, #1 - str r0, [r3] - ldr.w r0, [r3, #1536] - movs r0, #1 - str.w r0, [r3, #1536] -.LBB1_12: - ldr r0, [r3] - lsls r0, r0, #15 - bpl .LBB1_12 - ldr r0, [r3] - orr r0, r0, #1 - str r0, [r3] -.LBB1_14: - ldr r0, [r3] - lsls r0, r0, #15 - bpl .LBB1_14 add sp, #8 - ldr r11, [sp], #4 - pop {r4, r5, r6, r7, pc} -.LBB1_16: + bx lr + .p2align 2 +.LCPI2_0: + .long 268443648 +.Lfunc_end2: + .size _ZN7flc_asm15FlashController9flush_icc17hdfc1ef73516cdd37E, .Lfunc_end2-_ZN7flc_asm15FlashController9flush_icc17hdfc1ef73516cdd37E + .cfi_endproc + .cantunwind + .fnend + + .p2align 2 + .type _ZN7flc_asm15FlashController11enable_icc017h626bac51309a41f0E,%function + .code 16 + .thumb_func +_ZN7flc_asm15FlashController11enable_icc017h626bac51309a41f0E: +.Lfunc_begin3: + .fnstart + .cfi_startproc + ldr r0, .LCPI3_0 + ldr r1, [r0] + bic r1, r1, #1 + str r1, [r0] + ldr.w r1, [r0, #1536] + movs r1, #1 + str.w r1, [r0, #1536] +.LBB3_1: + ldr r1, [r0] + lsls r1, r1, #15 + bpl .LBB3_1 + ldr r1, [r0] + orr r1, r1, #1 + str r1, [r0] +.LBB3_3: + ldr r1, [r0] + lsls r1, r1, #15 + bpl .LBB3_3 + bx lr + .p2align 2 +.LCPI3_0: + .long 1073914112 +.Lfunc_end3: + .size _ZN7flc_asm15FlashController11enable_icc017h626bac51309a41f0E, .Lfunc_end3-_ZN7flc_asm15FlashController11enable_icc017h626bac51309a41f0E + .cfi_endproc + .cantunwind + .fnend + + .globl flc_read32_primitive + .p2align 2 + .type flc_read32_primitive,%function + .code 16 + .thumb_func +flc_read32_primitive: +.Lfunc_begin4: + .fnstart + .cfi_startproc + .save {r7, lr} + push {r7, lr} + .cfi_def_cfa_offset 8 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .setfp r7, sp + mov r7, sp + .cfi_def_cfa_register r7 + lsls r1, r0, #30 + bne .LBB4_4 + mov r1, r0 + bfc r1, #0, #19 + cmp.w r1, #268435456 + bne .LBB4_3 + ldr r1, .LCPI4_0 + add r1, r0 + cmp.w r1, #524288 + itt lo + ldrlo r0, [r0] + poplo {r7, pc} +.LBB4_3: + @APP +.Ltmp1: + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + b .Ltmp1 + @NO_APP + .inst.n 0xdefe +.LBB4_4: @APP .Ltmp2: b .Ltmp2 @@ -260,7 +264,93 @@ flc_write128_primitive: b .Ltmp2 @NO_APP .inst.n 0xdefe -.LBB1_17: + .p2align 2 +.LCPI4_0: + .long 4026531843 +.Lfunc_end4: + .size flc_read32_primitive, .Lfunc_end4-flc_read32_primitive + .cfi_endproc + .cantunwind + .fnend + + .globl flc_write128_primitive + .p2align 2 + .type flc_write128_primitive,%function + .code 16 + .thumb_func +flc_write128_primitive: +.Lfunc_begin5: + .fnstart + .cfi_startproc + .save {r4, r5, r6, r7, lr} + push {r4, r5, r6, r7, lr} + .cfi_def_cfa_offset 20 + .cfi_offset lr, -4 + .cfi_offset r7, -8 + .cfi_offset r6, -12 + .cfi_offset r5, -16 + .cfi_offset r4, -20 + .setfp r7, sp, #12 + add r7, sp, #12 + .cfi_def_cfa r7, 8 + .save {r8} + str r8, [sp, #-4]! + .cfi_offset r8, -24 + mov r5, r0 + bfc r0, #0, #19 + cmp.w r0, #268435456 + bne .LBB5_6 + ldr r0, .LCPI5_0 + add r0, r5 + cmp.w r0, #524288 + bhs .LBB5_6 + lsls r0, r5, #28 + bne .LBB5_7 + mov r8, r2 + mov r4, r1 + bl _ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E + ldr r0, .LCPI5_1 + ldr r6, .LCPI5_2 + ldr r1, [r0] + bic r1, r1, #1 + str r1, [r0] + ldr r0, [r6, #28] + bic r0, r0, #2 + str r0, [r6, #28] + mov r0, r8 + bl _ZN7flc_asm15FlashController17set_clock_divisor17hc5cf0d05434ae31dE + ldr r0, [r6] + movs r1, #2 + bfi r0, r1, #28, #4 + str r0, [r6] + ldr r0, [r6, #-8] + str r5, [r6, #-8] + ldr r0, [r6, #40] + ldm r4!, {r0, r1, r2, r3} + str r0, [r6, #40] + ldr r0, [r6, #44] + str r1, [r6, #44] + ldr r0, [r6, #48] + str r2, [r6, #48] + ldr r0, [r6, #52] + str r3, [r6, #52] + ldr r0, [r6] + orr r0, r0, #1 + str r0, [r6] +.LBB5_4: + ldr r0, [r6] + lsls r0, r0, #31 + bne .LBB5_4 + bl _ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E + ldr r0, [r6] + movs r1, #3 + bfi r0, r1, #28, #4 + str r0, [r6] + bl _ZN7flc_asm15FlashController9flush_icc17hdfc1ef73516cdd37E + ldr r8, [sp], #4 + pop.w {r4, r5, r6, r7, lr} + b _ZN7flc_asm15FlashController11enable_icc017h626bac51309a41f0E +.LBB5_6: @APP .Ltmp3: b .Ltmp3 @@ -284,7 +374,7 @@ flc_write128_primitive: b .Ltmp3 @NO_APP .inst.n 0xdefe -.LBB1_18: +.LBB5_7: @APP .Ltmp4: b .Ltmp4 @@ -309,20 +399,14 @@ flc_write128_primitive: @NO_APP .inst.n 0xdefe .p2align 2 -.LCPI1_0: +.LCPI5_0: .long 4026531855 -.LCPI1_1: - .long 1073909760 -.LCPI1_2: +.LCPI5_1: .long 1073914112 -.LCPI1_3: - .long 1000000 -.LCPI1_4: - .long 4293967296 -.LCPI1_5: - .long 268443648 -.Lfunc_end1: - .size flc_write128_primitive, .Lfunc_end1-flc_write128_primitive +.LCPI5_2: + .long 1073909768 +.Lfunc_end5: + .size flc_write128_primitive, .Lfunc_end5-flc_write128_primitive .cfi_endproc .cantunwind .fnend @@ -333,105 +417,62 @@ flc_write128_primitive: .code 16 .thumb_func flc_page_erase_primitive: -.Lfunc_begin2: +.Lfunc_begin6: .fnstart .cfi_startproc - .save {r4, r5, r7, lr} - .pad #8 - push {r2, r3, r4, r5, r7, lr} - .cfi_def_cfa_offset 24 + .save {r4, r5, r6, r7, lr} + push {r4, r5, r6, r7, lr} + .cfi_def_cfa_offset 20 .cfi_offset lr, -4 .cfi_offset r7, -8 - .cfi_offset r5, -12 - .cfi_offset r4, -16 - .setfp r7, sp, #16 - add r7, sp, #16 + .cfi_offset r6, -12 + .cfi_offset r5, -16 + .cfi_offset r4, -20 + .setfp r7, sp, #12 + add r7, sp, #12 .cfi_def_cfa r7, 8 - mov r2, r0 - bfc r2, #0, #19 - cmp.w r2, #268435456 - bne .LBB2_13 - ldr r3, .LCPI2_0 -.LBB2_2: - ldr r2, [r3, #8] - lsls r2, r2, #7 - bmi .LBB2_2 - ldr r2, .LCPI2_1 - ldr r5, .LCPI2_3 - ldr r4, [r2] - bic r4, r4, #1 - str r4, [r2] - ldr r4, [r3, #36] - bic r4, r4, #2 - str r4, [r3, #36] - ldr r4, .LCPI2_2 - udiv r4, r1, r4 - muls r5, r4, r5 - cmn r5, r1 - bne .LBB2_14 - ldr r1, [r3, #4] - bfi r1, r4, #0, #8 - str r1, [r3, #4] - ldr r1, [r3, #8] - movs r4, #2 - bfi r1, r4, #28, #4 - str r1, [r3, #8] - ldr r1, [r3] - str r0, [r3] + .save {r11} + str r11, [sp, #-4]! + .cfi_offset r11, -24 + mov r4, r0 + bfc r0, #0, #19 + cmp.w r0, #268435456 + bne .LBB6_2 + mov r5, r1 + bl _ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E + ldr r0, .LCPI6_0 + ldr r6, .LCPI6_1 + ldr r1, [r0] + bic r1, r1, #1 + str r1, [r0] + ldr r0, [r6, #28] + bic r0, r0, #2 + str r0, [r6, #28] + mov r0, r5 + bl _ZN7flc_asm15FlashController17set_clock_divisor17hc5cf0d05434ae31dE + ldr r0, [r6] + movs r1, #2 + bfi r0, r1, #28, #4 + str r0, [r6] + ldr r0, [r6, #-8] movs r1, #85 - ldr r0, [r3, #8] + str r4, [r6, #-8] + ldr r0, [r6] bfi r0, r1, #8, #8 - str r0, [r3, #8] - ldr r0, [r3, #8] + str r0, [r6] + ldr r0, [r6] orr r0, r0, #4 - str r0, [r3, #8] -.LBB2_5: - ldr r0, [r3, #8] - lsls r0, r0, #7 - bmi .LBB2_5 - ldr r0, [r3, #8] + str r0, [r6] + bl _ZN7flc_asm15FlashController16wait_until_ready17h3156387ccf27a694E + ldr r0, [r6] movs r1, #3 bfi r0, r1, #28, #4 - str r0, [r3, #8] - mov.w r0, #1073741824 - ldr r1, [r0] - orr r1, r1, #64 - str r1, [r0] -.LBB2_7: - ldr r1, [r0] - lsls r1, r1, #25 - bmi .LBB2_7 - mov.w r0, #268435456 - ldr r0, [r0] - str r0, [sp] - mov r0, sp - @APP - @NO_APP - ldr r0, .LCPI2_4 - ldr r0, [r0] - str r0, [sp, #4] - add r0, sp, #4 - @APP - @NO_APP - ldr r0, [r2] - bic r0, r0, #1 - str r0, [r2] - ldr.w r0, [r2, #1536] - movs r0, #1 - str.w r0, [r2, #1536] -.LBB2_9: - ldr r0, [r2] - lsls r0, r0, #15 - bpl .LBB2_9 - ldr r0, [r2] - orr r0, r0, #1 - str r0, [r2] -.LBB2_11: - ldr r0, [r2] - lsls r0, r0, #15 - bpl .LBB2_11 - pop {r2, r3, r4, r5, r7, pc} -.LBB2_13: + str r0, [r6] + bl _ZN7flc_asm15FlashController9flush_icc17hdfc1ef73516cdd37E + ldr r11, [sp], #4 + pop.w {r4, r5, r6, r7, lr} + b _ZN7flc_asm15FlashController11enable_icc017h626bac51309a41f0E +.LBB6_2: @APP .Ltmp5: b .Ltmp5 @@ -455,59 +496,28 @@ flc_page_erase_primitive: b .Ltmp5 @NO_APP .inst.n 0xdefe -.LBB2_14: - @APP -.Ltmp6: - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - b .Ltmp6 - @NO_APP - .inst.n 0xdefe .p2align 2 -.LCPI2_0: - .long 1073909760 -.LCPI2_1: +.LCPI6_0: .long 1073914112 -.LCPI2_2: - .long 1000000 -.LCPI2_3: - .long 4293967296 -.LCPI2_4: - .long 268443648 -.Lfunc_end2: - .size flc_page_erase_primitive, .Lfunc_end2-flc_page_erase_primitive +.LCPI6_1: + .long 1073909768 +.Lfunc_end6: + .size flc_page_erase_primitive, .Lfunc_end6-flc_page_erase_primitive .cfi_endproc .cantunwind .fnend - - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" - .ident "rustc version 1.86.0-nightly (d8810e3e2 2025-02-14)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" + .ident "rustc version 1.84.1 (e71f9a9a9 2025-01-27)" .section ".note.GNU-stack","",%progbits .eabi_attribute 30, 4 From 013cc7fdca430937b7397c4e3b982ecc9b0d65d4 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 23:02:50 -0800 Subject: [PATCH 30/32] rm old safety comment --- flc-asm/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 15f4e49..1ac3e4b 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -211,8 +211,6 @@ impl FlashController<'_, '_> { while !self.gcr.sysctrl().read().icc0_flush().bit_is_clear() {} // Clear the line fill buffer by reading 2 pages from flash - - // SAFETY: `FLASH_MEM_BASE` points to a valid, aligned word within flash space. const { assert!(check_address_bounds(PAGE1..PAGE1 + 4)); assert!(PAGE1 % 4 == 0); From 39040924774ce4c498646058e096e23655b3e81b Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 23:16:23 -0800 Subject: [PATCH 31/32] revise preinit --- hal/src/lib.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index a7554c1..f654832 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -52,7 +52,7 @@ pub mod peripherals; /// # Safety /// /// - Only assembly is allowed, because RAM has not been initialized, so any Rust -/// code that touches memory or the stack is undefined behavior. +/// code that touches memory is undefined behavior. /// /// [`pre_init`]: cortex_m_rt::pre_init #[cfg(feature = "rt")] @@ -61,15 +61,19 @@ unsafe fn pre_init() { // load the .analogsucks section into memory #[cfg(feature = "flc-ram")] core::arch::asm! { - "ldr r0, =__sanalogsucks - ldr r1, =__eanalogsucks - ldr r2, =__sianalogsucks + "ldr {0}, =__sanalogsucks + ldr {1}, =__eanalogsucks + ldr {2}, =__sianalogsucks 0: - cmp r1, r0 + cmp {1}, {0} beq 1f - ldm r2!, {{r3}} - stm r0!, {{r3}} + ldm {2}!, {{{3}}} + stm {0}!, {{{3}}} b 0b - 1:" + 1:", + out(reg) _, + out(reg) _, + out(reg) _, + out(reg) _, } } From bd620c375ebc0325d8c9e0e293d7cae17102e473 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 5 Mar 2025 23:40:51 -0800 Subject: [PATCH 32/32] remove outdated allow --- flc-asm/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/flc-asm/src/lib.rs b/flc-asm/src/lib.rs index 1ac3e4b..f8b4dfa 100644 --- a/flc-asm/src/lib.rs +++ b/flc-asm/src/lib.rs @@ -14,10 +14,6 @@ unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks )] -#![allow( - clippy::inline_always, - reason = "we need the functions to be inlined in this specific case" -)] use core::{arch::asm, panic::PanicInfo, ptr::read_volatile};