From cf24629be86dfb660bada3ce97c82364908d7847 Mon Sep 17 00:00:00 2001 From: Xiling Sun Date: Thu, 9 Jan 2025 16:51:16 -0800 Subject: [PATCH] Add recovery flash in emulator and extend flash test cases to recovery flash --- .gitignore | 4 +- Cargo.lock | 2 + emulator/app/Cargo.toml | 9 +- emulator/app/src/main.rs | 63 +- emulator/periph/Cargo.toml | 3 + emulator/periph/src/flash_ctrl.rs | 574 ++++++++++++++---- emulator/periph/src/i3c.rs | 13 +- emulator/periph/src/root_bus.rs | 6 +- hw/flash_ctrl.rdl | 2 +- hw/mcu.rdl | 3 +- registers/generated-emulator/src/lib.rs | 3 +- .../src/{flash.rs => main_flash.rs} | 26 +- .../generated-emulator/src/recovery_flash.rs | 244 ++++++++ registers/generated-emulator/src/root_bus.rs | 44 +- registers/generated-firmware/src/lib.rs | 3 +- .../src/{flash_ctrl.rs => main_flash_ctrl.rs} | 14 +- .../src/recovery_flash_ctrl.rs | 60 ++ runtime/capsules/src/flash_partition.rs | 2 + runtime/flash/src/flash_ctrl.rs | 18 +- runtime/src/board.rs | 38 +- runtime/src/chip.rs | 30 +- runtime/src/tests/flash_ctrl_test.rs | 7 +- runtime/src/tests/flash_storage_test.rs | 4 +- 23 files changed, 976 insertions(+), 196 deletions(-) rename registers/generated-emulator/src/{flash.rs => main_flash.rs} (90%) create mode 100644 registers/generated-emulator/src/recovery_flash.rs rename registers/generated-firmware/src/{flash_ctrl.rs => main_flash_ctrl.rs} (85%) create mode 100644 registers/generated-firmware/src/recovery_flash_ctrl.rs diff --git a/.gitignore b/.gitignore index f78c56b..21958b2 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,5 @@ runtime/apps/layout.ld book # flash file -dummy_flash.bin -primary_flash +main_flash +recovery_flash \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d20314f..cc28d56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -972,6 +972,7 @@ dependencies = [ "rand", "strum", "strum_macros", + "tempfile", "tock-registers", "zerocopy 0.8.13", ] @@ -1043,6 +1044,7 @@ dependencies = [ "registers-generated", "serde", "serde_json", + "tempfile", "tock-registers", "zerocopy 0.8.13", ] diff --git a/emulator/app/Cargo.toml b/emulator/app/Cargo.toml index 78b4c82..9a3c19a 100644 --- a/emulator/app/Cargo.toml +++ b/emulator/app/Cargo.toml @@ -30,16 +30,17 @@ strum_macros.workspace = true strum.workspace = true tock-registers.workspace = true zerocopy.workspace = true +tempfile.workspace = true [features] default = [] test-i3c-simple = [] test-i3c-constant-writes = ["emulator-periph/test-i3c-constant-writes"] test-flash-ctrl-init = [] -test-flash-ctrl-read-write-page = [] -test-flash-ctrl-erase-page = [] -test-flash-storage-read-write = [] -test-flash-storage-erase = [] +test-flash-ctrl-read-write-page = ["emulator-periph/test-flash-ctrl-read-write-page"] +test-flash-ctrl-erase-page = ["emulator-periph/test-flash-ctrl-erase-page"] +test-flash-storage-read-write = ["emulator-periph/test-flash-storage-read-write"] +test-flash-storage-erase = ["emulator-periph/test-flash-storage-erase"] test-mctp-ctrl-cmds = ["emulator-periph/test-mctp-ctrl-cmds"] test-mctp-capsule-loopback = ["emulator-periph/test-mctp-capsule-loopback"] test-mctp-user-loopback = ["emulator-periph/test-mctp-user-loopback"] diff --git a/emulator/app/src/main.rs b/emulator/app/src/main.rs index 14ea07f..6f258c2 100644 --- a/emulator/app/src/main.rs +++ b/emulator/app/src/main.rs @@ -405,15 +405,45 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result> { ); } - let flash_ctrl_error_irq = pic.register_irq(CaliptraRootBus::FLASH_CTRL_ERROR_IRQ); - let flash_ctrl_event_irq = pic.register_irq(CaliptraRootBus::FLASH_CTRL_EVENT_IRQ); - let flash_controller = DummyFlashCtrl::new( - &clock.clone(), - Some(PathBuf::from("primary_flash")), // TODO: make this configurable - flash_ctrl_error_irq, - flash_ctrl_event_irq, - ) - .unwrap(); + let create_flash_controller = |default_path: &str, error_irq: u8, event_irq: u8| { + // Use a temporary file for flash storage if we're running a test + let flash_file = if cfg!(any( + feature = "test-flash-ctrl-read-write-page", + feature = "test-flash-ctrl-erase-page", + feature = "test-flash-storage-read-write", + feature = "test-flash-storage-erase" + )) { + println!("[xs debug] flash test feature enabled with temp file"); + Some( + tempfile::NamedTempFile::new() + .unwrap() + .into_temp_path() + .to_path_buf(), + ) + } else { + Some(PathBuf::from(default_path)) + }; + + DummyFlashCtrl::new( + &clock.clone(), + flash_file, + pic.register_irq(error_irq), + pic.register_irq(event_irq), + ) + .unwrap() + }; + + let main_flash_controller = create_flash_controller( + "main_flash", + CaliptraRootBus::MAIN_FLASH_CTRL_ERROR_IRQ, + CaliptraRootBus::MAIN_FLASH_CTRL_EVENT_IRQ, + ); + + let recovery_flash_controller = create_flash_controller( + "recovery_flash", + CaliptraRootBus::RECOVERY_FLASH_CTRL_ERROR_IRQ, + CaliptraRootBus::RECOVERY_FLASH_CTRL_EVENT_IRQ, + ); let mut delegates: Vec> = vec![Box::new(root_bus)]; let soc_periph = if let Some(soc_to_caliptra) = soc_to_caliptra { @@ -428,7 +458,8 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result> { let mut auto_root_bus = AutoRootBus::new( delegates, Some(Box::new(i3c)), - Some(Box::new(flash_controller)), + Some(Box::new(main_flash_controller)), + Some(Box::new(recovery_flash_controller)), None, Some(Box::new(otp)), None, @@ -437,9 +468,17 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result> { None, ); - // Set the DMA RAM for the Flash Controller + // Set the DMA RAM for Main Flash Controller + auto_root_bus + .main_flash_periph + .as_mut() + .unwrap() + .periph + .set_dma_ram(dma_ram.clone()); + + // Set the DMA RAM for Recovery Flash Controller auto_root_bus - .flash_periph + .recovery_flash_periph .as_mut() .unwrap() .periph diff --git a/emulator/periph/Cargo.toml b/emulator/periph/Cargo.toml index aa5c7d1..0de07b4 100644 --- a/emulator/periph/Cargo.toml +++ b/emulator/periph/Cargo.toml @@ -22,6 +22,9 @@ serde.workspace = true tock-registers.workspace = true zerocopy.workspace = true +[dev-dependencies] +tempfile.workspace = true + [features] default = [] test-i3c-constant-writes = [] diff --git a/emulator/periph/src/flash_ctrl.rs b/emulator/periph/src/flash_ctrl.rs index 7a61f36..6adc0d8 100644 --- a/emulator/periph/src/flash_ctrl.rs +++ b/emulator/periph/src/flash_ctrl.rs @@ -15,11 +15,13 @@ Abstract: use core::convert::TryInto; use emulator_bus::{ActionHandle, Bus, Clock, Ram, ReadOnlyRegister, ReadWriteRegister, Timer}; use emulator_cpu::Irq; -use emulator_registers_generated::flash::FlashPeripheral; +use emulator_registers_generated::main_flash::MainFlashPeripheral; +use emulator_registers_generated::recovery_flash::RecoveryFlashPeripheral; use emulator_types::{RvSize, RAM_OFFSET, RAM_SIZE}; -use registers_generated::flash_ctrl::bits::{ +use registers_generated::main_flash_ctrl::bits::{ CtrlRegwen, FlControl, FlInterruptEnable, FlInterruptState, OpStatus, }; +use registers_generated::recovery_flash_ctrl; use std::cell::RefCell; use std::fs::File; use std::io::{Read, Seek, Write}; @@ -61,7 +63,7 @@ pub enum FlashOpError { DmaRamAccessError = 4, } -// Define a dummy flash controller peripheral. +/// A dummy flash controller peripheral for emulation purposes. pub struct DummyFlashCtrl { interrupt_state: ReadWriteRegister, interrupt_enable: ReadWriteRegister, @@ -91,6 +93,17 @@ impl DummyFlashCtrl { /// I/O processing delay in ticks pub const IO_START_DELAY: u64 = 200; + fn initialize_flash_storage(file: &mut File, size: usize) -> std::io::Result<()> { + let chunk = vec![0xFF; 1048576]; // 1MB chunk + let mut remaining = size; + while remaining > 0 { + let write_size = std::cmp::min(remaining, chunk.len()); + file.write_all(&chunk[..write_size])?; + remaining -= write_size; + } + Ok(()) + } + pub fn new( clock: &Clock, file_name: Option, @@ -99,14 +112,25 @@ impl DummyFlashCtrl { ) -> Result { let timer = Timer::new(clock); let file = if let Some(path) = file_name { - Some( - std::fs::File::options() - .read(true) - .write(true) - .create(true) - .truncate(false) - .open(path)?, - ) + let mut file = std::fs::File::options() + .read(true) + .write(true) + .create(true) + .truncate(false) + .open(&path)?; + + let capacity = DummyFlashCtrl::PAGE_SIZE * DummyFlashCtrl::MAX_PAGES as usize; + // Check if the file is empty and fill it with 64MB of 0xFF in chunks of 1MB if it is + if file.metadata()?.len() < capacity as u64 { + DummyFlashCtrl::initialize_flash_storage(&mut file, capacity)?; + } + println!( + "[xs debug] Flash file path is {:?}, Flash file size is {}", + path, + file.metadata()?.len() + ); + + Some(file) } else { None }; @@ -333,7 +357,180 @@ impl DummyFlashCtrl { } } -impl FlashPeripheral for DummyFlashCtrl { +impl MainFlashPeripheral for DummyFlashCtrl { + fn set_dma_ram(&mut self, ram: std::rc::Rc>) { + self.dma_ram = Some(ram); + } + + fn poll(&mut self) { + if self.timer.fired(&mut self.operation_start) { + self.process_io(); + } + } + + fn read_fl_interrupt_state( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::FlInterruptState::Register, + > { + emulator_bus::ReadWriteRegister::new(self.interrupt_state.reg.get()) + } + + fn write_fl_interrupt_state( + &mut self, + _size: emulator_types::RvSize, + val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::FlInterruptState::Register, + >, + ) { + // Interrupt state register: SW write 1 to clear + if val + .reg + .is_set(registers_generated::main_flash_ctrl::bits::FlInterruptState::Error) + { + self.clear_interrupt(FlashCtrlIntType::Error); + } + if val + .reg + .is_set(registers_generated::main_flash_ctrl::bits::FlInterruptState::Event) + { + self.clear_interrupt(FlashCtrlIntType::Event); + } + } + + fn read_fl_interrupt_enable( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::FlInterruptEnable::Register, + > { + emulator_bus::ReadWriteRegister::new(self.interrupt_enable.reg.get()) + } + + fn write_fl_interrupt_enable( + &mut self, + _size: emulator_types::RvSize, + val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::FlInterruptEnable::Register, + >, + ) { + if self.interrupt_state.reg.is_set(FlInterruptState::Error) + && val + .reg + .is_set(registers_generated::main_flash_ctrl::bits::FlInterruptEnable::Error) + { + self.error_irq.set_level(true); + self.timer.schedule_poll_in(1); + } + + if self.interrupt_state.reg.is_set(FlInterruptState::Event) + && val + .reg + .is_set(registers_generated::main_flash_ctrl::bits::FlInterruptEnable::Event) + { + self.event_irq.set_level(true); + self.timer.schedule_poll_in(1); + } + + self.interrupt_enable.reg.set(val.reg.get()); + } + + fn write_page_size(&mut self, _size: emulator_types::RvSize, val: emulator_types::RvData) { + self.page_size.reg.set(val); + } + + // Return the page size of the flash storage connected to the controller + fn read_page_size(&mut self, _size: emulator_types::RvSize) -> emulator_types::RvData { + Self::PAGE_SIZE as u32 + } + + fn read_page_num(&mut self, _size: emulator_types::RvSize) -> emulator_types::RvData { + self.page_num.reg.get() + } + + fn write_page_num(&mut self, _size: emulator_types::RvSize, val: emulator_types::RvData) { + self.page_num.reg.set(val); + } + + fn read_page_addr(&mut self, _size: emulator_types::RvSize) -> emulator_types::RvData { + self.page_addr.reg.get() + } + + fn write_page_addr(&mut self, _size: emulator_types::RvSize, val: emulator_types::RvData) { + self.page_addr.reg.set(val); + } + + fn read_fl_control( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::FlControl::Register, + > { + emulator_bus::ReadWriteRegister::new(self.control.reg.get()) + } + + fn write_fl_control( + &mut self, + _size: emulator_types::RvSize, + val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::FlControl::Register, + >, + ) { + if !self.ctrl_regwen.reg.is_set(CtrlRegwen::En) { + return; + } + + self.control.reg.set(val.reg.get()); + + if self.control.reg.is_set(FlControl::Start) { + // Clear ctrl_regwen bit to prevent SW from writing to the control register while the operation is pending. + self.ctrl_regwen.reg.modify(CtrlRegwen::En::CLEAR); + + // Schedule the timer to start the operation after the delay + self.operation_start = Some(self.timer.schedule_poll_in(Self::IO_START_DELAY)); + } + } + + fn read_op_status( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::OpStatus::Register, + > { + emulator_bus::ReadWriteRegister::new(self.op_status.reg.get()) + } + + fn write_op_status( + &mut self, + _size: emulator_types::RvSize, + val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::OpStatus::Register, + >, + ) { + self.op_status.reg.set(val.reg.get()); + } + + fn read_ctrl_regwen( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::main_flash_ctrl::bits::CtrlRegwen::Register, + > { + emulator_bus::ReadWriteRegister::new(self.ctrl_regwen.reg.get()) + } +} + +impl RecoveryFlashPeripheral for DummyFlashCtrl { fn set_dma_ram(&mut self, ram: std::rc::Rc>) { self.dma_ram = Some(ram); } @@ -352,7 +549,7 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptState::Register, + registers_generated::recovery_flash_ctrl::bits::FlInterruptState::Register, > { emulator_bus::ReadWriteRegister::new(self.interrupt_state.reg.get()) } @@ -362,14 +559,20 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptState::Register, + registers_generated::recovery_flash_ctrl::bits::FlInterruptState::Register, >, ) { // Interrupt state register: SW write 1 to clear - if val.reg.is_set(FlInterruptState::Error) { + if val + .reg + .is_set(recovery_flash_ctrl::bits::FlInterruptState::Error) + { self.clear_interrupt(FlashCtrlIntType::Error); } - if val.reg.is_set(FlInterruptState::Event) { + if val + .reg + .is_set(recovery_flash_ctrl::bits::FlInterruptState::Event) + { self.clear_interrupt(FlashCtrlIntType::Event); } } @@ -379,7 +582,7 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptEnable::Register, + registers_generated::recovery_flash_ctrl::bits::FlInterruptEnable::Register, > { emulator_bus::ReadWriteRegister::new(self.interrupt_enable.reg.get()) } @@ -389,18 +592,22 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptEnable::Register, + registers_generated::recovery_flash_ctrl::bits::FlInterruptEnable::Register, >, ) { if self.interrupt_state.reg.is_set(FlInterruptState::Error) - && val.reg.is_set(FlInterruptEnable::Error) + && val + .reg + .is_set(recovery_flash_ctrl::bits::FlInterruptEnable::Error) { self.error_irq.set_level(true); self.timer.schedule_poll_in(1); } if self.interrupt_state.reg.is_set(FlInterruptState::Event) - && val.reg.is_set(FlInterruptEnable::Event) + && val + .reg + .is_set(recovery_flash_ctrl::bits::FlInterruptEnable::Event) { self.event_irq.set_level(true); self.timer.schedule_poll_in(1); @@ -439,7 +646,7 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlControl::Register, + registers_generated::recovery_flash_ctrl::bits::FlControl::Register, > { emulator_bus::ReadWriteRegister::new(self.control.reg.get()) } @@ -449,7 +656,7 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlControl::Register, + registers_generated::recovery_flash_ctrl::bits::FlControl::Register, >, ) { if !self.ctrl_regwen.reg.is_set(CtrlRegwen::En) { @@ -472,7 +679,7 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::OpStatus::Register, + registers_generated::recovery_flash_ctrl::bits::OpStatus::Register, > { emulator_bus::ReadWriteRegister::new(self.op_status.reg.get()) } @@ -482,7 +689,7 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::OpStatus::Register, + registers_generated::recovery_flash_ctrl::bits::OpStatus::Register, >, ) { self.op_status.reg.set(val.reg.get()); @@ -493,7 +700,7 @@ impl FlashPeripheral for DummyFlashCtrl { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::CtrlRegwen::Register, + registers_generated::recovery_flash_ctrl::bits::CtrlRegwen::Register, > { emulator_bus::ReadWriteRegister::new(self.ctrl_regwen.reg.get()) } @@ -508,11 +715,13 @@ mod test { use emulator_cpu::Pic; use emulator_registers_generated::root_bus::AutoRootBus; use emulator_types::{RvSize, RAM_OFFSET, RAM_SIZE}; - use registers_generated::flash_ctrl::bits::{ + use registers_generated::main_flash_ctrl::bits::{ FlControl, FlInterruptEnable, FlInterruptState, OpStatus, }; - use registers_generated::flash_ctrl::FLASH_CTRL_ADDR; + use registers_generated::main_flash_ctrl::MAIN_FLASH_CTRL_ADDR; + use registers_generated::recovery_flash_ctrl::RECOVERY_FLASH_CTRL_ADDR; use std::path::PathBuf; + use tempfile::NamedTempFile; pub const INT_STATE_OFFSET: u32 = 0x00; pub const INT_ENABLE_OFFSET: u32 = 0x04; @@ -522,20 +731,29 @@ mod test { pub const CONTROL_OFFSET: u32 = 0x14; pub const OP_STATUS_OFFSET: u32 = 0x18; + #[derive(Clone, Copy, PartialEq)] + pub enum FlashType { + Main, + Recovery, + } + // Dummy DMA RAM fn test_helper_setup_dummy_dma_ram() -> Rc> { - let ram = Rc::new(RefCell::new(Ram::new(vec![0u8; RAM_SIZE as usize]))); - ram + Rc::new(RefCell::new(Ram::new(vec![0u8; RAM_SIZE as usize]))) } fn test_helper_setup_autobus( file_path: Option, + fl_type: FlashType, clock: &Clock, dma_ram: Option>>, ) -> AutoRootBus { let pic = Pic::new(); - let flash_ctrl_error_irq = pic.register_irq(19); - let flash_ctrl_event_irq = pic.register_irq(20); + let (flash_ctrl_error_irq, flash_ctrl_event_irq) = match fl_type { + FlashType::Main => (pic.register_irq(19), pic.register_irq(20)), + FlashType::Recovery => (pic.register_irq(21), pic.register_irq(22)), + }; + let file = file_path; let mut flash_controller = Box::new( @@ -543,20 +761,35 @@ mod test { ); if let Some(dma_ram) = dma_ram { - flash_controller.set_dma_ram(dma_ram); + MainFlashPeripheral::set_dma_ram(&mut *flash_controller, dma_ram); } - AutoRootBus::new( - vec![], - None, - Some(flash_controller), - None, - None, - None, - None, - None, - None, - ) + match fl_type { + FlashType::Main => AutoRootBus::new( + vec![], + None, + Some(flash_controller), + None, + None, + None, + None, + None, + None, + None, + ), + FlashType::Recovery => AutoRootBus::new( + vec![], + None, + None, + Some(flash_controller), + None, + None, + None, + None, + None, + None, + ), + } } fn test_helper_prepare_io_page_buffer( @@ -611,33 +844,37 @@ mod test { file.write_all(data).unwrap(); } - #[test] - fn test_flash_ctrl_regs_access() { + fn test_flash_ctrl_regs_access(fl_type: FlashType) { let dummy_clock = Clock::new(); // Create a auto root bus - let mut bus = test_helper_setup_autobus(None, &dummy_clock, None); + let mut bus = test_helper_setup_autobus(None, fl_type, &dummy_clock, None); + + let flash_ctrl_base_addr: u32 = match fl_type { + FlashType::Main => MAIN_FLASH_CTRL_ADDR, + FlashType::Recovery => RECOVERY_FLASH_CTRL_ADDR, + }; // Write to the interrupt enable register and read it back bus.write( RvSize::Word, - FLASH_CTRL_ADDR + INT_ENABLE_OFFSET, + flash_ctrl_base_addr + INT_ENABLE_OFFSET, FlInterruptEnable::Error::SET.value, ) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_ENABLE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_ENABLE_OFFSET) .unwrap(), FlInterruptEnable::Error::SET.value ); bus.write( RvSize::Word, - FLASH_CTRL_ADDR + INT_ENABLE_OFFSET, + flash_ctrl_base_addr + INT_ENABLE_OFFSET, FlInterruptEnable::Event::SET.value, ) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_ENABLE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_ENABLE_OFFSET) .unwrap(), FlInterruptEnable::Event::SET.value ); @@ -645,12 +882,12 @@ mod test { // Clear the interrupt enable register and read it back bus.write( RvSize::Word, - FLASH_CTRL_ADDR + INT_ENABLE_OFFSET, + flash_ctrl_base_addr + INT_ENABLE_OFFSET, FlInterruptEnable::Error::CLEAR.value, ) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_ENABLE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_ENABLE_OFFSET) .unwrap(), FlInterruptEnable::Error::CLEAR.value ); @@ -658,25 +895,25 @@ mod test { // Write to the interrupt state register and read it back bus.write( RvSize::Word, - FLASH_CTRL_ADDR + INT_STATE_OFFSET, + flash_ctrl_base_addr + INT_STATE_OFFSET, FlInterruptState::Error::SET.value, ) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Error::CLEAR.value ); bus.write( RvSize::Word, - FLASH_CTRL_ADDR + INT_STATE_OFFSET, + flash_ctrl_base_addr + INT_STATE_OFFSET, FlInterruptState::Event::SET.value, ) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Event::CLEAR.value ); @@ -684,21 +921,21 @@ mod test { // Write to the page size register and read it back bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET, + flash_ctrl_base_addr + PAGE_SIZE_OFFSET, DummyFlashCtrl::PAGE_SIZE as u32, ) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + PAGE_SIZE_OFFSET) .unwrap(), DummyFlashCtrl::PAGE_SIZE as u32 ); // Write to the page number register and read it back - bus.write(RvSize::Word, FLASH_CTRL_ADDR + PAGE_NUM_OFFSET, 0x100) + bus.write(RvSize::Word, flash_ctrl_base_addr + PAGE_NUM_OFFSET, 0x100) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + PAGE_NUM_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + PAGE_NUM_OFFSET) .unwrap(), 0x100 ); @@ -706,27 +943,26 @@ mod test { // Write to the page address register and read it back bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_ADDR_OFFSET, + flash_ctrl_base_addr + PAGE_ADDR_OFFSET, 0x1000_0000, ) .unwrap(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + PAGE_ADDR_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + PAGE_ADDR_OFFSET) .unwrap(), 0x1000_0000 ); // read the op_status register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), 0 ); } - #[test] - fn test_write_page_success() { - let test_file = PathBuf::from("dummy_flash.bin"); + fn test_write_page_success(fl_type: FlashType) { + let test_file = NamedTempFile::new().unwrap().path().to_path_buf(); let test_data = [0xaau8; DummyFlashCtrl::PAGE_SIZE]; let test_page_num: u32 = 100; let dummy_dma_ram = test_helper_setup_dummy_dma_ram(); @@ -735,10 +971,16 @@ mod test { // Create a auto root bus let mut bus = test_helper_setup_autobus( Some(test_file.clone()), + fl_type, &dummy_clock, Some(dummy_dma_ram.clone()), ); + let flash_ctrl_base_addr: u32 = match fl_type { + FlashType::Main => MAIN_FLASH_CTRL_ADDR, + FlashType::Recovery => RECOVERY_FLASH_CTRL_ADDR, + }; + // Prepare the page buffer for write operation let w_page_buf_addr = test_helper_prepare_io_page_buffer( 0x4005_1000, @@ -752,7 +994,7 @@ mod test { // read the op_status register to make sure it is clean assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), 0 ); @@ -760,7 +1002,7 @@ mod test { // Write to the page address register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_ADDR_OFFSET, + flash_ctrl_base_addr + PAGE_ADDR_OFFSET, w_page_buf_addr.unwrap(), ) .unwrap(); @@ -768,7 +1010,7 @@ mod test { // write to the page size register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET, + flash_ctrl_base_addr + PAGE_SIZE_OFFSET, DummyFlashCtrl::PAGE_SIZE as u32, ) .unwrap(); @@ -776,14 +1018,14 @@ mod test { // write to the page number register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_NUM_OFFSET, + flash_ctrl_base_addr + PAGE_NUM_OFFSET, test_page_num, ) .unwrap(); bus.write( RvSize::Word, - FLASH_CTRL_ADDR + CONTROL_OFFSET, + flash_ctrl_base_addr + CONTROL_OFFSET, (FlControl::Start::SET + FlControl::Op.val(FlashOperation::WritePage as u32)).value, ) .unwrap(); @@ -797,14 +1039,14 @@ mod test { // Check the op_status register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), OpStatus::Done::SET.value ); // Check the interrupt state register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Event::SET.value ); @@ -816,9 +1058,8 @@ mod test { )); } - #[test] - fn test_write_page_error() { - let test_file = PathBuf::from("dummy_flash.bin"); + fn test_write_page_error(fl_type: FlashType) { + let test_file = NamedTempFile::new().unwrap().path().to_path_buf(); let test_data = [0xaau8; DummyFlashCtrl::PAGE_SIZE]; let test_page_num: u32 = DummyFlashCtrl::MAX_PAGES; @@ -828,10 +1069,16 @@ mod test { // Create a auto root bus let mut bus = test_helper_setup_autobus( Some(test_file.clone()), + fl_type, &dummy_clock, Some(dummy_dma_ram.clone()), ); + let flash_ctrl_base_addr: u32 = match fl_type { + FlashType::Main => MAIN_FLASH_CTRL_ADDR, + FlashType::Recovery => RECOVERY_FLASH_CTRL_ADDR, + }; + // Prepare the page buffer for write operation let w_page_buf_addr = test_helper_prepare_io_page_buffer( 0x4005_2000, @@ -846,7 +1093,7 @@ mod test { // Write to the page address register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_ADDR_OFFSET, + flash_ctrl_base_addr + PAGE_ADDR_OFFSET, w_page_buf_addr.unwrap(), ) .unwrap(); @@ -854,7 +1101,7 @@ mod test { // write to the page size register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET, + flash_ctrl_base_addr + PAGE_SIZE_OFFSET, DummyFlashCtrl::PAGE_SIZE as u32, ) .unwrap(); @@ -862,7 +1109,7 @@ mod test { // write to the page number register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_NUM_OFFSET, + flash_ctrl_base_addr + PAGE_NUM_OFFSET, test_page_num, ) .unwrap(); @@ -870,7 +1117,7 @@ mod test { // write to the control register with invalid operation bus.write( RvSize::Word, - FLASH_CTRL_ADDR + CONTROL_OFFSET, + flash_ctrl_base_addr + CONTROL_OFFSET, (FlControl::Start::SET + FlControl::Op.val(FlashOperation::ReadPage as u32)).value, ) .unwrap(); @@ -884,22 +1131,21 @@ mod test { // Check the op_status register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), OpStatus::Err.val(FlashOpError::ReadError as u32).value ); // Check the interrupt state register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Error::SET.value ); } - #[test] - fn test_read_page_success() { - let test_file = PathBuf::from("dummy_flash.bin"); + fn test_read_page_success(fl_type: FlashType) { + let test_file = NamedTempFile::new().unwrap().path().to_path_buf(); let test_data = [0xbbu8; DummyFlashCtrl::PAGE_SIZE]; let test_page_num: u32 = 50; @@ -908,10 +1154,16 @@ mod test { // Create a auto root bus let mut bus = test_helper_setup_autobus( Some(test_file.clone()), + fl_type, &dummy_clock, Some(dummy_dma_ram.clone()), ); + let flash_ctrl_base_addr: u32 = match fl_type { + FlashType::Main => MAIN_FLASH_CTRL_ADDR, + FlashType::Recovery => RECOVERY_FLASH_CTRL_ADDR, + }; + // Fill the test page with test data test_helper_fill_file_with_data(&test_file, test_page_num, &test_data); @@ -929,7 +1181,7 @@ mod test { // Write to the page address register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_ADDR_OFFSET, + flash_ctrl_base_addr + PAGE_ADDR_OFFSET, r_page_buf_addr.unwrap(), ) .unwrap(); @@ -937,7 +1189,7 @@ mod test { // write to the page size register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET, + flash_ctrl_base_addr + PAGE_SIZE_OFFSET, DummyFlashCtrl::PAGE_SIZE as u32, ) .unwrap(); @@ -945,7 +1197,7 @@ mod test { // write to the page number register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_NUM_OFFSET, + flash_ctrl_base_addr + PAGE_NUM_OFFSET, test_page_num, ) .unwrap(); @@ -953,7 +1205,7 @@ mod test { // write to the control register with invalid operation bus.write( RvSize::Word, - FLASH_CTRL_ADDR + CONTROL_OFFSET, + flash_ctrl_base_addr + CONTROL_OFFSET, (FlControl::Start::SET + FlControl::Op.val(FlashOperation::ReadPage as u32)).value, ) .unwrap(); @@ -966,14 +1218,14 @@ mod test { // Check the op_status register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), OpStatus::Done::SET.value ); // Check the interrupt state register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Event::SET.value ); @@ -988,9 +1240,8 @@ mod test { assert_eq!(r_page_buf, test_data); } - #[test] - fn test_read_page_error() { - let test_file = PathBuf::from("dummy_flash.bin"); + fn test_read_page_error(fl_type: FlashType) { + let test_file = NamedTempFile::new().unwrap().path().to_path_buf(); let test_page_num: u32 = DummyFlashCtrl::MAX_PAGES; let dummy_clock = Clock::new(); @@ -998,10 +1249,16 @@ mod test { // Create a auto root bus let mut bus = test_helper_setup_autobus( Some(test_file.clone()), + fl_type, &dummy_clock, Some(dummy_dma_ram.clone()), ); + let flash_ctrl_base_addr: u32 = match fl_type { + FlashType::Main => MAIN_FLASH_CTRL_ADDR, + FlashType::Recovery => RECOVERY_FLASH_CTRL_ADDR, + }; + // Prepare the page buffer for read operation let r_page_buf_addr = test_helper_prepare_io_page_buffer( 0x4005_2000, @@ -1016,7 +1273,7 @@ mod test { // Write to the page address register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_ADDR_OFFSET, + flash_ctrl_base_addr + PAGE_ADDR_OFFSET, r_page_buf_addr.unwrap(), ) .unwrap(); @@ -1024,7 +1281,7 @@ mod test { // write to the page size register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET, + flash_ctrl_base_addr + PAGE_SIZE_OFFSET, DummyFlashCtrl::PAGE_SIZE as u32, ) .unwrap(); @@ -1032,7 +1289,7 @@ mod test { // write to the page number register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_NUM_OFFSET, + flash_ctrl_base_addr + PAGE_NUM_OFFSET, test_page_num, ) .unwrap(); @@ -1040,7 +1297,7 @@ mod test { // write to the control register with invalid operation bus.write( RvSize::Word, - FLASH_CTRL_ADDR + CONTROL_OFFSET, + flash_ctrl_base_addr + CONTROL_OFFSET, (FlControl::Start::SET + FlControl::Op.val(FlashOperation::ReadPage as u32)).value, ) .unwrap(); @@ -1053,32 +1310,37 @@ mod test { // Check the op_status register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), OpStatus::Err.val(FlashOpError::ReadError as u32).value ); // Check the interrupt state register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Error::SET.value ); } - #[test] - fn test_erase_page_success() { - let test_file = PathBuf::from("dummy_flash.bin"); + fn test_erase_page_success(fl_type: FlashType) { + let test_file = NamedTempFile::new().unwrap().path().to_path_buf(); let test_page_num: u32 = 300; let dummy_clock = Clock::new(); // Create a auto root bus - let mut bus = test_helper_setup_autobus(Some(test_file.clone()), &dummy_clock, None); + let mut bus = + test_helper_setup_autobus(Some(test_file.clone()), fl_type, &dummy_clock, None); + + let flash_ctrl_base_addr: u32 = match fl_type { + FlashType::Main => MAIN_FLASH_CTRL_ADDR, + FlashType::Recovery => RECOVERY_FLASH_CTRL_ADDR, + }; // write to the page number register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_NUM_OFFSET, + flash_ctrl_base_addr + PAGE_NUM_OFFSET, test_page_num, ) .unwrap(); @@ -1086,7 +1348,7 @@ mod test { // write to the page size register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET, + flash_ctrl_base_addr + PAGE_SIZE_OFFSET, DummyFlashCtrl::PAGE_SIZE as u32, ) .unwrap(); @@ -1094,7 +1356,7 @@ mod test { // write to the control register with invalid operation bus.write( RvSize::Word, - FLASH_CTRL_ADDR + CONTROL_OFFSET, + flash_ctrl_base_addr + CONTROL_OFFSET, (FlControl::Start::SET + FlControl::Op.val(FlashOperation::ErasePage as u32)).value, ) .unwrap(); @@ -1106,13 +1368,13 @@ mod test { bus.poll(); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), OpStatus::Done::SET.value ); assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Event::SET.value ); @@ -1125,19 +1387,24 @@ mod test { )); } - #[test] - fn test_erase_page_error() { - let test_file = PathBuf::from("dummy_flash.bin"); + fn test_erase_page_error(fl_type: FlashType) { + let test_file = NamedTempFile::new().unwrap().path().to_path_buf(); let test_page_num: u32 = DummyFlashCtrl::MAX_PAGES; let dummy_clock = Clock::new(); // Create a auto root bus - let mut bus = test_helper_setup_autobus(Some(test_file.clone()), &dummy_clock, None); + let mut bus = + test_helper_setup_autobus(Some(test_file.clone()), fl_type, &dummy_clock, None); + + let flash_ctrl_base_addr: u32 = match fl_type { + FlashType::Main => MAIN_FLASH_CTRL_ADDR, + FlashType::Recovery => RECOVERY_FLASH_CTRL_ADDR, + }; // write to the page number register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_NUM_OFFSET, + flash_ctrl_base_addr + PAGE_NUM_OFFSET, test_page_num, ) .unwrap(); @@ -1145,7 +1412,7 @@ mod test { // write to the page size register bus.write( RvSize::Word, - FLASH_CTRL_ADDR + PAGE_SIZE_OFFSET, + flash_ctrl_base_addr + PAGE_SIZE_OFFSET, DummyFlashCtrl::PAGE_SIZE as u32, ) .unwrap(); @@ -1153,7 +1420,7 @@ mod test { // write to the control register with invalid operation bus.write( RvSize::Word, - FLASH_CTRL_ADDR + CONTROL_OFFSET, + flash_ctrl_base_addr + CONTROL_OFFSET, (FlControl::Start::SET + FlControl::Op.val(FlashOperation::ErasePage as u32)).value, ) .unwrap(); @@ -1166,16 +1433,87 @@ mod test { // Check the op_status register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + OP_STATUS_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + OP_STATUS_OFFSET) .unwrap(), OpStatus::Err.val(FlashOpError::EraseError as u32).value ); // Check the interrupt state register assert_eq!( - bus.read(RvSize::Word, FLASH_CTRL_ADDR + INT_STATE_OFFSET) + bus.read(RvSize::Word, flash_ctrl_base_addr + INT_STATE_OFFSET) .unwrap(), FlInterruptState::Error::SET.value ); } + + //// TEST CASE STARTED HERE + #[test] + fn test_main_flash_regs_access() { + test_flash_ctrl_regs_access(FlashType::Main); + } + + #[test] + fn test_main_flash_write_page_success() { + test_write_page_success(FlashType::Main); + } + + #[test] + fn test_main_flash_write_page_error() { + test_write_page_error(FlashType::Main); + } + + #[test] + fn test_main_flash_read_page_success() { + test_read_page_success(FlashType::Main); + } + + #[test] + fn test_main_flash_read_page_error() { + test_read_page_error(FlashType::Main); + } + + #[test] + fn test_main_flash_erase_page_success() { + test_erase_page_success(FlashType::Main); + } + + #[test] + fn test_main_flash_erase_page_error() { + test_erase_page_error(FlashType::Main); + } + + #[test] + fn test_recovery_flash_regs_access() { + test_flash_ctrl_regs_access(FlashType::Recovery); + } + + #[test] + fn test_recovery_flash_write_page_success() { + test_write_page_success(FlashType::Recovery); + } + + #[test] + fn test_recovery_flash_write_page_error() { + test_write_page_error(FlashType::Recovery); + } + + #[test] + fn test_recovery_flash_read_page_success() { + test_read_page_success(FlashType::Recovery); + } + + #[test] + fn test_recovery_flash_read_page_error() { + test_read_page_error(FlashType::Recovery); + } + + #[test] + fn test_recovery_flash_erase_page_success() { + test_erase_page_success(FlashType::Recovery); + } + + #[test] + fn test_recovery_flash_erase_page_error() { + test_erase_page_error(FlashType::Recovery); + } } diff --git a/emulator/periph/src/i3c.rs b/emulator/periph/src/i3c.rs index 006d07d..ff94eb9 100644 --- a/emulator/periph/src/i3c.rs +++ b/emulator/periph/src/i3c.rs @@ -410,7 +410,18 @@ mod tests { .tcri_send(DynamicI3cAddress::new(8).unwrap(), cmd) .unwrap(); - let mut bus = AutoRootBus::new(vec![], Some(i3c), None, None, None, None, None, None, None); + let mut bus = AutoRootBus::new( + vec![], + Some(i3c), + None, + None, + None, + None, + None, + None, + None, + None, + ); for _ in 0..10000 { clock.increment_and_process_timer_actions(1, &mut bus); } diff --git a/emulator/periph/src/root_bus.rs b/emulator/periph/src/root_bus.rs index 8634d7b..1d15da8 100644 --- a/emulator/periph/src/root_bus.rs +++ b/emulator/periph/src/root_bus.rs @@ -61,8 +61,10 @@ impl CaliptraRootBus { pub const UART_NOTIF_IRQ: u8 = 16; pub const I3C_ERROR_IRQ: u8 = 17; pub const I3C_NOTIF_IRQ: u8 = 18; - pub const FLASH_CTRL_ERROR_IRQ: u8 = 19; - pub const FLASH_CTRL_EVENT_IRQ: u8 = 20; + pub const MAIN_FLASH_CTRL_ERROR_IRQ: u8 = 19; + pub const MAIN_FLASH_CTRL_EVENT_IRQ: u8 = 20; + pub const RECOVERY_FLASH_CTRL_ERROR_IRQ: u8 = 21; + pub const RECOVERY_FLASH_CTRL_EVENT_IRQ: u8 = 22; pub fn new(mut args: CaliptraRootBusArgs) -> Result { let clock = args.clock; diff --git a/hw/flash_ctrl.rdl b/hw/flash_ctrl.rdl index 965d1b8..003f200 100644 --- a/hw/flash_ctrl.rdl +++ b/hw/flash_ctrl.rdl @@ -1,5 +1,5 @@ addrmap flash_ctrl { - reg { + reg { field { sw = rw; onwrite = woclr; diff --git a/hw/mcu.rdl b/hw/mcu.rdl index 65c7a0b..49f1496 100644 --- a/hw/mcu.rdl +++ b/hw/mcu.rdl @@ -1,6 +1,7 @@ addrmap mcu { el2_pic_ctrl el2_pic_ctrl @ 0x6000_0000; - flash_ctrl flash_ctrl @ 0x2000_8000; + flash_ctrl main_flash_ctrl @ 0x2000_8000; + flash_ctrl recovery_flash_ctrl @ 0x2000_8800; entropy_src entropy_src @ 0x2000_9000; caliptra_otp_ctrl caliptra_otp_ctrl @ 0x2000_b000; }; \ No newline at end of file diff --git a/registers/generated-emulator/src/lib.rs b/registers/generated-emulator/src/lib.rs index 0198043..8d0a667 100644 --- a/registers/generated-emulator/src/lib.rs +++ b/registers/generated-emulator/src/lib.rs @@ -4,10 +4,11 @@ // pub mod el2_pic; pub mod entropy_src; -pub mod flash; pub mod i3c; +pub mod main_flash; pub mod mbox; pub mod otp; +pub mod recovery_flash; pub mod root_bus; pub mod sha512_acc; pub mod soc; diff --git a/registers/generated-emulator/src/flash.rs b/registers/generated-emulator/src/main_flash.rs similarity index 90% rename from registers/generated-emulator/src/flash.rs rename to registers/generated-emulator/src/main_flash.rs index 4cb12b7..044ae79 100644 --- a/registers/generated-emulator/src/flash.rs +++ b/registers/generated-emulator/src/main_flash.rs @@ -4,7 +4,7 @@ // #[allow(unused_imports)] use tock_registers::interfaces::{Readable, Writeable}; -pub trait FlashPeripheral { +pub trait MainFlashPeripheral { fn set_dma_ram(&mut self, _ram: std::rc::Rc>) {} fn poll(&mut self) {} fn warm_reset(&mut self) {} @@ -14,7 +14,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptState::Register, + registers_generated::main_flash_ctrl::bits::FlInterruptState::Register, > { emulator_bus::ReadWriteRegister::new(0) } @@ -23,7 +23,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, _val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptState::Register, + registers_generated::main_flash_ctrl::bits::FlInterruptState::Register, >, ) { } @@ -32,7 +32,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptEnable::Register, + registers_generated::main_flash_ctrl::bits::FlInterruptEnable::Register, > { emulator_bus::ReadWriteRegister::new(0) } @@ -41,7 +41,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, _val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlInterruptEnable::Register, + registers_generated::main_flash_ctrl::bits::FlInterruptEnable::Register, >, ) { } @@ -62,7 +62,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlControl::Register, + registers_generated::main_flash_ctrl::bits::FlControl::Register, > { emulator_bus::ReadWriteRegister::new(0) } @@ -71,7 +71,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, _val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::FlControl::Register, + registers_generated::main_flash_ctrl::bits::FlControl::Register, >, ) { } @@ -80,7 +80,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::OpStatus::Register, + registers_generated::main_flash_ctrl::bits::OpStatus::Register, > { emulator_bus::ReadWriteRegister::new(0) } @@ -89,7 +89,7 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, _val: emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::OpStatus::Register, + registers_generated::main_flash_ctrl::bits::OpStatus::Register, >, ) { } @@ -98,15 +98,15 @@ pub trait FlashPeripheral { _size: emulator_types::RvSize, ) -> emulator_bus::ReadWriteRegister< u32, - registers_generated::flash_ctrl::bits::CtrlRegwen::Register, + registers_generated::main_flash_ctrl::bits::CtrlRegwen::Register, > { emulator_bus::ReadWriteRegister::new(0) } } -pub struct FlashBus { - pub periph: Box, +pub struct MainFlashBus { + pub periph: Box, } -impl emulator_bus::Bus for FlashBus { +impl emulator_bus::Bus for MainFlashBus { fn read( &mut self, size: emulator_types::RvSize, diff --git a/registers/generated-emulator/src/recovery_flash.rs b/registers/generated-emulator/src/recovery_flash.rs new file mode 100644 index 0000000..16c4b97 --- /dev/null +++ b/registers/generated-emulator/src/recovery_flash.rs @@ -0,0 +1,244 @@ +// Licensed under the Apache-2.0 license. +// +// generated by registers_generator with caliptra-ss repo at a621fff9df7015821eda6f7f73265fef74a01375 +// +#[allow(unused_imports)] +use tock_registers::interfaces::{Readable, Writeable}; +pub trait RecoveryFlashPeripheral { + fn set_dma_ram(&mut self, _ram: std::rc::Rc>) {} + fn poll(&mut self) {} + fn warm_reset(&mut self) {} + fn update_reset(&mut self) {} + fn read_fl_interrupt_state( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::FlInterruptState::Register, + > { + emulator_bus::ReadWriteRegister::new(0) + } + fn write_fl_interrupt_state( + &mut self, + _size: emulator_types::RvSize, + _val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::FlInterruptState::Register, + >, + ) { + } + fn read_fl_interrupt_enable( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::FlInterruptEnable::Register, + > { + emulator_bus::ReadWriteRegister::new(0) + } + fn write_fl_interrupt_enable( + &mut self, + _size: emulator_types::RvSize, + _val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::FlInterruptEnable::Register, + >, + ) { + } + fn read_page_size(&mut self, _size: emulator_types::RvSize) -> emulator_types::RvData { + 0 + } + fn write_page_size(&mut self, _size: emulator_types::RvSize, _val: emulator_types::RvData) {} + fn read_page_num(&mut self, _size: emulator_types::RvSize) -> emulator_types::RvData { + 0 + } + fn write_page_num(&mut self, _size: emulator_types::RvSize, _val: emulator_types::RvData) {} + fn read_page_addr(&mut self, _size: emulator_types::RvSize) -> emulator_types::RvData { + 0 + } + fn write_page_addr(&mut self, _size: emulator_types::RvSize, _val: emulator_types::RvData) {} + fn read_fl_control( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::FlControl::Register, + > { + emulator_bus::ReadWriteRegister::new(0) + } + fn write_fl_control( + &mut self, + _size: emulator_types::RvSize, + _val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::FlControl::Register, + >, + ) { + } + fn read_op_status( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::OpStatus::Register, + > { + emulator_bus::ReadWriteRegister::new(0) + } + fn write_op_status( + &mut self, + _size: emulator_types::RvSize, + _val: emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::OpStatus::Register, + >, + ) { + } + fn read_ctrl_regwen( + &mut self, + _size: emulator_types::RvSize, + ) -> emulator_bus::ReadWriteRegister< + u32, + registers_generated::recovery_flash_ctrl::bits::CtrlRegwen::Register, + > { + emulator_bus::ReadWriteRegister::new(0) + } +} +pub struct RecoveryFlashBus { + pub periph: Box, +} +impl emulator_bus::Bus for RecoveryFlashBus { + fn read( + &mut self, + size: emulator_types::RvSize, + addr: emulator_types::RvAddr, + ) -> Result { + match (size, addr) { + (emulator_types::RvSize::Word, 0) => Ok(emulator_types::RvData::from( + self.periph + .read_fl_interrupt_state(emulator_types::RvSize::Word) + .reg + .get(), + )), + (emulator_types::RvSize::Word, 1..=3) => { + Err(emulator_bus::BusError::LoadAddrMisaligned) + } + (emulator_types::RvSize::Word, 4) => Ok(emulator_types::RvData::from( + self.periph + .read_fl_interrupt_enable(emulator_types::RvSize::Word) + .reg + .get(), + )), + (emulator_types::RvSize::Word, 5..=7) => { + Err(emulator_bus::BusError::LoadAddrMisaligned) + } + (size, 8) => Ok(self.periph.read_page_size(size)), + (_, 9..=0xb) => Err(emulator_bus::BusError::LoadAddrMisaligned), + (size, 0xc) => Ok(self.periph.read_page_num(size)), + (_, 0xd..=0xf) => Err(emulator_bus::BusError::LoadAddrMisaligned), + (size, 0x10) => Ok(self.periph.read_page_addr(size)), + (_, 0x11..=0x13) => Err(emulator_bus::BusError::LoadAddrMisaligned), + (emulator_types::RvSize::Word, 0x14) => Ok(emulator_types::RvData::from( + self.periph + .read_fl_control(emulator_types::RvSize::Word) + .reg + .get(), + )), + (emulator_types::RvSize::Word, 0x15..=0x17) => { + Err(emulator_bus::BusError::LoadAddrMisaligned) + } + (emulator_types::RvSize::Word, 0x18) => Ok(emulator_types::RvData::from( + self.periph + .read_op_status(emulator_types::RvSize::Word) + .reg + .get(), + )), + (emulator_types::RvSize::Word, 0x19..=0x1b) => { + Err(emulator_bus::BusError::LoadAddrMisaligned) + } + (emulator_types::RvSize::Word, 0x1c) => Ok(emulator_types::RvData::from( + self.periph + .read_ctrl_regwen(emulator_types::RvSize::Word) + .reg + .get(), + )), + (emulator_types::RvSize::Word, 0x1d..=0x1f) => { + Err(emulator_bus::BusError::LoadAddrMisaligned) + } + _ => Err(emulator_bus::BusError::LoadAccessFault), + } + } + fn write( + &mut self, + size: emulator_types::RvSize, + addr: emulator_types::RvAddr, + val: emulator_types::RvData, + ) -> Result<(), emulator_bus::BusError> { + match (size, addr) { + (emulator_types::RvSize::Word, 0) => { + self.periph.write_fl_interrupt_state( + emulator_types::RvSize::Word, + emulator_bus::ReadWriteRegister::new(val), + ); + Ok(()) + } + (emulator_types::RvSize::Word, 1..=3) => { + Err(emulator_bus::BusError::StoreAddrMisaligned) + } + (emulator_types::RvSize::Word, 4) => { + self.periph.write_fl_interrupt_enable( + emulator_types::RvSize::Word, + emulator_bus::ReadWriteRegister::new(val), + ); + Ok(()) + } + (emulator_types::RvSize::Word, 5..=7) => { + Err(emulator_bus::BusError::StoreAddrMisaligned) + } + (size, 8) => { + self.periph.write_page_size(size, val); + Ok(()) + } + (_, 9..=0xb) => Err(emulator_bus::BusError::StoreAddrMisaligned), + (size, 0xc) => { + self.periph.write_page_num(size, val); + Ok(()) + } + (_, 0xd..=0xf) => Err(emulator_bus::BusError::StoreAddrMisaligned), + (size, 0x10) => { + self.periph.write_page_addr(size, val); + Ok(()) + } + (_, 0x11..=0x13) => Err(emulator_bus::BusError::StoreAddrMisaligned), + (emulator_types::RvSize::Word, 0x14) => { + self.periph.write_fl_control( + emulator_types::RvSize::Word, + emulator_bus::ReadWriteRegister::new(val), + ); + Ok(()) + } + (emulator_types::RvSize::Word, 0x15..=0x17) => { + Err(emulator_bus::BusError::StoreAddrMisaligned) + } + (emulator_types::RvSize::Word, 0x18) => { + self.periph.write_op_status( + emulator_types::RvSize::Word, + emulator_bus::ReadWriteRegister::new(val), + ); + Ok(()) + } + (emulator_types::RvSize::Word, 0x19..=0x1b) => { + Err(emulator_bus::BusError::StoreAddrMisaligned) + } + _ => Err(emulator_bus::BusError::StoreAccessFault), + } + } + fn poll(&mut self) { + self.periph.poll(); + } + fn warm_reset(&mut self) { + self.periph.warm_reset(); + } + fn update_reset(&mut self) { + self.periph.update_reset(); + } +} diff --git a/registers/generated-emulator/src/root_bus.rs b/registers/generated-emulator/src/root_bus.rs index f38dce3..cefc164 100644 --- a/registers/generated-emulator/src/root_bus.rs +++ b/registers/generated-emulator/src/root_bus.rs @@ -5,7 +5,8 @@ pub struct AutoRootBus { delegates: Vec>, pub i3c_periph: Option, - pub flash_periph: Option, + pub main_flash_periph: Option, + pub recovery_flash_periph: Option, pub entropy_src_periph: Option, pub otp_periph: Option, pub mbox_periph: Option, @@ -18,7 +19,8 @@ impl AutoRootBus { pub fn new( delegates: Vec>, i3c_periph: Option>, - flash_periph: Option>, + main_flash_periph: Option>, + recovery_flash_periph: Option>, entropy_src_periph: Option>, otp_periph: Option>, mbox_periph: Option>, @@ -29,7 +31,10 @@ impl AutoRootBus { Self { delegates, i3c_periph: i3c_periph.map(|p| crate::i3c::I3cBus { periph: p }), - flash_periph: flash_periph.map(|p| crate::flash::FlashBus { periph: p }), + main_flash_periph: main_flash_periph + .map(|p| crate::main_flash::MainFlashBus { periph: p }), + recovery_flash_periph: recovery_flash_periph + .map(|p| crate::recovery_flash::RecoveryFlashBus { periph: p }), entropy_src_periph: entropy_src_periph .map(|p| crate::entropy_src::EntropySrcBus { periph: p }), otp_periph: otp_periph.map(|p| crate::otp::OtpBus { periph: p }), @@ -56,12 +61,19 @@ impl emulator_bus::Bus for AutoRootBus { } } 0x2000_8000..=0x2000_8090 => { - if let Some(periph) = self.flash_periph.as_mut() { + if let Some(periph) = self.main_flash_periph.as_mut() { periph.read(size, addr - 0x2000_8000) } else { Err(emulator_bus::BusError::LoadAccessFault) } } + 0x2000_8800..=0x2000_8890 => { + if let Some(periph) = self.recovery_flash_periph.as_mut() { + periph.read(size, addr - 0x2000_8800) + } else { + Err(emulator_bus::BusError::LoadAccessFault) + } + } 0x2000_9000..=0x2000_a9d4 => { if let Some(periph) = self.entropy_src_periph.as_mut() { periph.read(size, addr - 0x2000_9000) @@ -132,12 +144,19 @@ impl emulator_bus::Bus for AutoRootBus { } } 0x2000_8000..=0x2000_8090 => { - if let Some(periph) = self.flash_periph.as_mut() { + if let Some(periph) = self.main_flash_periph.as_mut() { periph.write(size, addr - 0x2000_8000, val) } else { Err(emulator_bus::BusError::StoreAccessFault) } } + 0x2000_8800..=0x2000_8890 => { + if let Some(periph) = self.recovery_flash_periph.as_mut() { + periph.write(size, addr - 0x2000_8800, val) + } else { + Err(emulator_bus::BusError::StoreAccessFault) + } + } 0x2000_9000..=0x2000_a9d4 => { if let Some(periph) = self.entropy_src_periph.as_mut() { periph.write(size, addr - 0x2000_9000, val) @@ -197,7 +216,10 @@ impl emulator_bus::Bus for AutoRootBus { if let Some(periph) = self.i3c_periph.as_mut() { periph.poll(); } - if let Some(periph) = self.flash_periph.as_mut() { + if let Some(periph) = self.main_flash_periph.as_mut() { + periph.poll(); + } + if let Some(periph) = self.recovery_flash_periph.as_mut() { periph.poll(); } if let Some(periph) = self.entropy_src_periph.as_mut() { @@ -226,7 +248,10 @@ impl emulator_bus::Bus for AutoRootBus { if let Some(periph) = self.i3c_periph.as_mut() { periph.warm_reset(); } - if let Some(periph) = self.flash_periph.as_mut() { + if let Some(periph) = self.main_flash_periph.as_mut() { + periph.warm_reset(); + } + if let Some(periph) = self.recovery_flash_periph.as_mut() { periph.warm_reset(); } if let Some(periph) = self.entropy_src_periph.as_mut() { @@ -255,7 +280,10 @@ impl emulator_bus::Bus for AutoRootBus { if let Some(periph) = self.i3c_periph.as_mut() { periph.update_reset(); } - if let Some(periph) = self.flash_periph.as_mut() { + if let Some(periph) = self.main_flash_periph.as_mut() { + periph.update_reset(); + } + if let Some(periph) = self.recovery_flash_periph.as_mut() { periph.update_reset(); } if let Some(periph) = self.entropy_src_periph.as_mut() { diff --git a/registers/generated-firmware/src/lib.rs b/registers/generated-firmware/src/lib.rs index 3cb8d4a..d11b0b6 100644 --- a/registers/generated-firmware/src/lib.rs +++ b/registers/generated-firmware/src/lib.rs @@ -6,10 +6,11 @@ #![no_std] pub mod el2_pic_ctrl; pub mod entropy_src; -pub mod flash_ctrl; pub mod fuses; pub mod i3c; +pub mod main_flash_ctrl; pub mod mbox; pub mod otp_ctrl; +pub mod recovery_flash_ctrl; pub mod sha512_acc; pub mod soc; diff --git a/registers/generated-firmware/src/flash_ctrl.rs b/registers/generated-firmware/src/main_flash_ctrl.rs similarity index 85% rename from registers/generated-firmware/src/flash_ctrl.rs rename to registers/generated-firmware/src/main_flash_ctrl.rs index acbc939..d7f5c92 100644 --- a/registers/generated-firmware/src/flash_ctrl.rs +++ b/registers/generated-firmware/src/main_flash_ctrl.rs @@ -2,7 +2,7 @@ // // generated by registers_generator with caliptra-ss repo at a621fff9df7015821eda6f7f73265fef74a01375 // -pub const FLASH_CTRL_ADDR: u32 = 0x2000_8000; +pub const MAIN_FLASH_CTRL_ADDR: u32 = 0x2000_8000; pub mod bits { //! Types that represent individual registers (bitfields). use tock_registers::register_bitfields; @@ -45,15 +45,15 @@ pub mod regs { //! Types that represent registers. use tock_registers::register_structs; register_structs! { - pub FlashCtrl { - (0x0 => pub fl_interrupt_state: tock_registers::registers::ReadWrite), - (0x4 => pub fl_interrupt_enable: tock_registers::registers::ReadWrite), + pub MainFlashCtrl { + (0x0 => pub fl_interrupt_state: tock_registers::registers::ReadWrite), + (0x4 => pub fl_interrupt_enable: tock_registers::registers::ReadWrite), (0x8 => pub page_size: tock_registers::registers::ReadWrite), (0xc => pub page_num: tock_registers::registers::ReadWrite), (0x10 => pub page_addr: tock_registers::registers::ReadWrite), - (0x14 => pub fl_control: tock_registers::registers::ReadWrite), - (0x18 => pub op_status: tock_registers::registers::ReadWrite), - (0x1c => pub ctrl_regwen: tock_registers::registers::ReadOnly), + (0x14 => pub fl_control: tock_registers::registers::ReadWrite), + (0x18 => pub op_status: tock_registers::registers::ReadWrite), + (0x1c => pub ctrl_regwen: tock_registers::registers::ReadOnly), (0x20 => @END), } } diff --git a/registers/generated-firmware/src/recovery_flash_ctrl.rs b/registers/generated-firmware/src/recovery_flash_ctrl.rs new file mode 100644 index 0000000..13bb56b --- /dev/null +++ b/registers/generated-firmware/src/recovery_flash_ctrl.rs @@ -0,0 +1,60 @@ +// Licensed under the Apache-2.0 license. +// +// generated by registers_generator with caliptra-ss repo at a621fff9df7015821eda6f7f73265fef74a01375 +// +pub const RECOVERY_FLASH_CTRL_ADDR: u32 = 0x2000_8800; +pub mod bits { + //! Types that represent individual registers (bitfields). + use tock_registers::register_bitfields; + register_bitfields! { + u32, + pub CtrlRegwen [ + /// This register ensures the contents of OP_CONTROL cannot be changed by software once a flash operation has begun. \ + /// This bit defaults to 1 and is set to 0 by hardware when flash operation is initiated. When the controller completes the flash operation, \ + /// It unlocks whenever the existing flash operation completes, regardless of success or error. + En OFFSET(0) NUMBITS(1) [], + ], + pub FlControl [ + /// "0" = Read page , "1" = Write Page, "2" Erase Page + Op OFFSET(1) NUMBITS(2) [], + /// Start the operation + Start OFFSET(0) NUMBITS(1) [], + ], + pub FlInterruptEnable [ + /// Enable error interrupt + Error OFFSET(0) NUMBITS(1) [], + /// Enable event interrupt + Event OFFSET(1) NUMBITS(1) [], + ], + pub FlInterruptState [ + /// Error-related interrupts + Error OFFSET(0) NUMBITS(1) [], + /// Event-related interrupts + Event OFFSET(1) NUMBITS(1) [], + ], + pub OpStatus [ + /// Flash operation error. Set by HW, cleared by SW . + /// "0" = Read Error , "1" = Write Error, "2" Erase Error + Err OFFSET(1) NUMBITS(3) [], + /// Flash operation done. Set by HW, cleared by SW + Done OFFSET(0) NUMBITS(1) [], + ], + } +} +pub mod regs { + //! Types that represent registers. + use tock_registers::register_structs; + register_structs! { + pub RecoveryFlashCtrl { + (0x0 => pub fl_interrupt_state: tock_registers::registers::ReadWrite), + (0x4 => pub fl_interrupt_enable: tock_registers::registers::ReadWrite), + (0x8 => pub page_size: tock_registers::registers::ReadWrite), + (0xc => pub page_num: tock_registers::registers::ReadWrite), + (0x10 => pub page_addr: tock_registers::registers::ReadWrite), + (0x14 => pub fl_control: tock_registers::registers::ReadWrite), + (0x18 => pub op_status: tock_registers::registers::ReadWrite), + (0x1c => pub ctrl_regwen: tock_registers::registers::ReadOnly), + (0x20 => @END), + } + } +} diff --git a/runtime/capsules/src/flash_partition.rs b/runtime/capsules/src/flash_partition.rs index f035b58..e63791b 100644 --- a/runtime/capsules/src/flash_partition.rs +++ b/runtime/capsules/src/flash_partition.rs @@ -14,6 +14,8 @@ use kernel::{ErrorCode, ProcessId}; pub const IMAGE_PAR_DRIVER_NUM: usize = 0x8000_0006; pub const STAGING_PAR_DRIVER_NUM: usize = 0x8000_0007; +pub const RECOVERY_IMAGE_PAR_DRIVER_NUM: usize = 0x8000_0008; + pub const BUF_LEN: usize = 512; /// IDs for subscribed upcalls. diff --git a/runtime/flash/src/flash_ctrl.rs b/runtime/flash/src/flash_ctrl.rs index 89fe0f7..2bb99e6 100644 --- a/runtime/flash/src/flash_ctrl.rs +++ b/runtime/flash/src/flash_ctrl.rs @@ -8,14 +8,18 @@ use kernel::utilities::cells::{OptionalCell, TakeCell}; use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable}; use kernel::utilities::StaticRef; use kernel::ErrorCode; -use registers_generated::flash_ctrl::{ +use registers_generated::main_flash_ctrl::{ bits::{CtrlRegwen, FlControl, FlInterruptEnable, FlInterruptState, OpStatus}, - regs::FlashCtrl, - FLASH_CTRL_ADDR, + regs::MainFlashCtrl, + MAIN_FLASH_CTRL_ADDR, }; +use registers_generated::recovery_flash_ctrl::RECOVERY_FLASH_CTRL_ADDR; -pub const FLASH_CTRL_BASE: StaticRef = - unsafe { StaticRef::new(FLASH_CTRL_ADDR as *const FlashCtrl) }; +pub const MAIN_FLASH_CTRL_BASE: StaticRef = + unsafe { StaticRef::new(MAIN_FLASH_CTRL_ADDR as *const MainFlashCtrl) }; + +pub const RECOVERY_FLASH_CTRL_BASE: StaticRef = + unsafe { StaticRef::new(RECOVERY_FLASH_CTRL_ADDR as *const MainFlashCtrl) }; pub const PAGE_SIZE: usize = 256; pub const FLASH_MAX_PAGES: usize = 64 * 1024 * 1024 / PAGE_SIZE; @@ -70,14 +74,14 @@ impl AsMut<[u8]> for EmulatedFlashPage { } pub struct EmulatedFlashCtrl<'a> { - registers: StaticRef, + registers: StaticRef, flash_client: OptionalCell<&'a dyn hil::flash::Client>>, read_buf: TakeCell<'static, EmulatedFlashPage>, write_buf: TakeCell<'static, EmulatedFlashPage>, } impl<'a> EmulatedFlashCtrl<'a> { - pub fn new(base: StaticRef) -> EmulatedFlashCtrl<'a> { + pub fn new(base: StaticRef) -> EmulatedFlashCtrl<'a> { EmulatedFlashCtrl { registers: base, flash_client: OptionalCell::empty(), diff --git a/runtime/src/board.rs b/runtime/src/board.rs index f1f7cb4..584a4e2 100644 --- a/runtime/src/board.rs +++ b/runtime/src/board.rs @@ -121,6 +121,7 @@ struct VeeR { mctp_caliptra: &'static capsules_runtime::mctp::driver::MCTPDriver<'static>, // Temorarily add one partition driver for userspace testing. image_par: &'static capsules_runtime::flash_partition::FlashPartition<'static>, + recovery_image_par: &'static capsules_runtime::flash_partition::FlashPartition<'static>, } /// Mapping of integer syscalls to objects that implement syscalls. @@ -140,6 +141,9 @@ impl SyscallDriverLookup for VeeR { capsules_runtime::mctp::driver::MCTP_PLDM_DRIVER_NUM => f(Some(self.mctp_pldm)), capsules_runtime::mctp::driver::MCTP_CALIPTRA_DRIVER_NUM => f(Some(self.mctp_caliptra)), capsules_runtime::flash_partition::IMAGE_PAR_DRIVER_NUM => f(Some(self.image_par)), + capsules_runtime::flash_partition::RECOVERY_IMAGE_PAR_DRIVER_NUM => { + f(Some(self.recovery_image_par)) + } _ => f(None), } } @@ -343,12 +347,13 @@ pub unsafe fn main() { peripherals.init(); // Create a mux for the physical flash controller - let mux_flash = components::flash::FlashMuxComponent::new(&peripherals.flash_ctrl).finalize( - components::flash_mux_component_static!(flash_driver::flash_ctrl::EmulatedFlashCtrl), - ); + let mux_main_flash = components::flash::FlashMuxComponent::new(&peripherals.main_flash_ctrl) + .finalize(components::flash_mux_component_static!( + flash_driver::flash_ctrl::EmulatedFlashCtrl + )); // Instantiate a flashUser for image partition driver - let image_par_fl_user = components::flash::FlashUserComponent::new(mux_flash).finalize( + let image_par_fl_user = components::flash::FlashUserComponent::new(mux_main_flash).finalize( components::flash_user_component_static!(flash_driver::flash_ctrl::EmulatedFlashCtrl), ); @@ -366,6 +371,30 @@ pub unsafe fn main() { capsules_runtime::flash_partition::BUF_LEN )); + // Create a mux for the recovery flash controller + let mux_recovery_flash = + components::flash::FlashMuxComponent::new(&peripherals.recovery_flash_ctrl).finalize( + components::flash_mux_component_static!(flash_driver::flash_ctrl::EmulatedFlashCtrl), + ); + + // Instantiate a flashUser for recovery image partition driver + let recovery_image_par_fl_user = components::flash::FlashUserComponent::new(mux_recovery_flash) + .finalize(components::flash_user_component_static!( + flash_driver::flash_ctrl::EmulatedFlashCtrl + )); + + let _recovery_image_par = runtime_components::flash_partition::FlashPartitionComponent::new( + board_kernel, + capsules_runtime::flash_partition::RECOVERY_IMAGE_PAR_DRIVER_NUM, // Driver number + recovery_image_par_fl_user, + 0x0, // Start address of the partition. Place holder for testing + 0x200_0000, // Length of the partition. Place holder for testing + ) + .finalize(crate::flash_partition_component_static!( + virtual_flash::FlashUser<'static, flash_driver::flash_ctrl::EmulatedFlashCtrl>, + capsules_runtime::flash_partition::BUF_LEN + )); + // Need to enable all interrupts for Tock Kernel chip.enable_pic_interrupts(); chip.enable_timer_interrupts(); @@ -401,6 +430,7 @@ pub unsafe fn main() { mctp_pldm, mctp_caliptra, image_par, + recovery_image_par: _recovery_image_par, } ); diff --git a/runtime/src/chip.rs b/runtime/src/chip.rs index 4caee15..ac673a6 100644 --- a/runtime/src/chip.rs +++ b/runtime/src/chip.rs @@ -31,8 +31,10 @@ pub static mut TIMERS: InternalTimers<'static> = InternalTimers::new(); pub const UART_IRQ: u8 = 0x10; pub const I3C_ERROR_IRQ: u8 = 0x11; pub const I3C_NOTIF_IRQ: u8 = 0x12; -pub const FLASH_CTRL_ERROR_IRQ: u8 = 0x13; -pub const FLASH_CTRL_EVENT_IRQ: u8 = 0x14; +pub const MAIN_FLASH_CTRL_ERROR_IRQ: u8 = 0x13; +pub const MAIN_FLASH_CTRL_EVENT_IRQ: u8 = 0x14; +pub const RECOVERY_FLASH_CTRL_EVENT_IRQ: u8 = 0x15; +pub const RECOVERY_FLASH_CTRL_ERROR_IRQ: u8 = 0x16; pub struct VeeR<'a, I: InterruptService + 'a> { userspace_kernel_boundary: SysCall, @@ -45,7 +47,8 @@ pub struct VeeR<'a, I: InterruptService + 'a> { pub struct VeeRDefaultPeripherals<'a> { pub uart: SemihostUart<'a>, pub i3c: i3c_driver::core::I3CCore<'a, InternalTimers<'a>>, - pub flash_ctrl: flash_driver::flash_ctrl::EmulatedFlashCtrl<'a>, + pub main_flash_ctrl: flash_driver::flash_ctrl::EmulatedFlashCtrl<'a>, + pub recovery_flash_ctrl: flash_driver::flash_ctrl::EmulatedFlashCtrl<'a>, } impl<'a> VeeRDefaultPeripherals<'a> { @@ -53,8 +56,11 @@ impl<'a> VeeRDefaultPeripherals<'a> { Self { uart: SemihostUart::new(alarm), i3c: i3c_driver::core::I3CCore::new(i3c_driver::core::I3C_BASE, alarm), - flash_ctrl: flash_driver::flash_ctrl::EmulatedFlashCtrl::new( - flash_driver::flash_ctrl::FLASH_CTRL_BASE, + main_flash_ctrl: flash_driver::flash_ctrl::EmulatedFlashCtrl::new( + flash_driver::flash_ctrl::MAIN_FLASH_CTRL_BASE, + ), + recovery_flash_ctrl: flash_driver::flash_ctrl::EmulatedFlashCtrl::new( + flash_driver::flash_ctrl::RECOVERY_FLASH_CTRL_BASE, ), } } @@ -62,7 +68,8 @@ impl<'a> VeeRDefaultPeripherals<'a> { pub fn init(&'static self) { kernel::deferred_call::DeferredCallClient::register(&self.uart); self.i3c.init(); - self.flash_ctrl.init(); + self.main_flash_ctrl.init(); + self.recovery_flash_ctrl.init(); } } @@ -77,10 +84,15 @@ impl<'a> InterruptService for VeeRDefaultPeripherals<'a> { } else if interrupt == I3C_NOTIF_IRQ as u32 { self.i3c.handle_notification_interrupt(); return true; - } else if interrupt == FLASH_CTRL_ERROR_IRQ as u32 - || interrupt == FLASH_CTRL_EVENT_IRQ as u32 + } else if interrupt == MAIN_FLASH_CTRL_ERROR_IRQ as u32 + || interrupt == MAIN_FLASH_CTRL_EVENT_IRQ as u32 + { + self.main_flash_ctrl.handle_interrupt(); + return true; + } else if interrupt == RECOVERY_FLASH_CTRL_ERROR_IRQ as u32 + || interrupt == RECOVERY_FLASH_CTRL_EVENT_IRQ as u32 { - self.flash_ctrl.handle_interrupt(); + self.recovery_flash_ctrl.handle_interrupt(); return true; } debug!("Unhandled interrupt {}", interrupt); diff --git a/runtime/src/tests/flash_ctrl_test.rs b/runtime/src/tests/flash_ctrl_test.rs index efad706..498e824 100644 --- a/runtime/src/tests/flash_ctrl_test.rs +++ b/runtime/src/tests/flash_ctrl_test.rs @@ -21,7 +21,8 @@ use romtime::println; pub(crate) fn test_flash_ctrl_init() -> Option { // Safety: this is run after the board has initialized the chip. let chip = unsafe { crate::CHIP.unwrap() }; - chip.peripherals.flash_ctrl.init(); + chip.peripherals.main_flash_ctrl.init(); + chip.peripherals.recovery_flash_ctrl.init(); Some(0) } @@ -131,7 +132,7 @@ macro_rules! static_init_test { pub fn test_flash_ctrl_erase_page() -> Option { println!("Starting flash controller erase page test"); let chip = unsafe { crate::CHIP.unwrap() }; - let flash_ctrl = &chip.peripherals.flash_ctrl; + let flash_ctrl = &chip.peripherals.main_flash_ctrl; let test_cb = unsafe { static_init_test!() }; // Set up the client @@ -175,7 +176,7 @@ pub fn test_flash_ctrl_erase_page() -> Option { pub(crate) fn test_flash_ctrl_read_write_page() -> Option { println!("Starting flash controller read write page test"); let chip = unsafe { crate::CHIP.unwrap() }; - let flash_ctrl = &chip.peripherals.flash_ctrl; + let flash_ctrl = &chip.peripherals.main_flash_ctrl; let test_cb = unsafe { static_init_test!() }; // Set up the client diff --git a/runtime/src/tests/flash_storage_test.rs b/runtime/src/tests/flash_storage_test.rs index 077e6a5..8453852 100644 --- a/runtime/src/tests/flash_storage_test.rs +++ b/runtime/src/tests/flash_storage_test.rs @@ -97,7 +97,7 @@ macro_rules! static_init_fs_test_cb { pub(crate) fn test_flash_storage_erase() -> Option { println!("Starting flash storage erase test"); let chip = unsafe { crate::CHIP.unwrap() }; - let flash_ctrl = &chip.peripherals.flash_ctrl; + let flash_ctrl = &chip.peripherals.main_flash_ctrl; let flash_storage_drv = unsafe { static_init!( FlashStorageToPages, @@ -185,7 +185,7 @@ pub(crate) fn test_flash_storage_erase() -> Option { pub(crate) fn test_flash_storage_read_write() -> Option { println!("Starting flash storage read write test"); let chip = unsafe { crate::CHIP.unwrap() }; - let flash_ctrl = &chip.peripherals.flash_ctrl; + let flash_ctrl = &chip.peripherals.main_flash_ctrl; let flash_storage_drv = unsafe { static_init!( FlashStorageToPages,