diff --git a/boards/opentitan/src/tests/flash.rs b/boards/opentitan/src/tests/flash.rs index 85fe59eaa7..6337a09e48 100644 --- a/boards/opentitan/src/tests/flash.rs +++ b/boards/opentitan/src/tests/flash.rs @@ -2,474 +2,417 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT // Copyright Tock Contributors 2022. -//! Test the opentitan flash implementation - -mod key_value { - use crate::tests::run_kernel_op; - use crate::{SIPHASH, TICKV}; - use capsules_core::virtualizers::virtual_flash::FlashUser; - use capsules_extra::test::kv_system::KVSystemTest; - use capsules_extra::tickv::KVSystem; - use capsules_extra::tickv::{TicKVKeyType, TicKVSystem}; - use kernel::debug; - use kernel::hil::hasher::Hasher; - use kernel::static_init; - use kernel::utilities::leasable_buffer::SubSliceMut; - - #[test_case] - fn tickv_append_key() { - debug!("start TicKV append key test..."); - - unsafe { - let tickv = TICKV.unwrap(); - let sip_hasher = SIPHASH.unwrap(); - - let key_input = static_init!( - [u8; 16], - [ - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, - 0xBC, 0xDE, 0xF0 - ] - ); - let key = static_init!([u8; 8], [0; 8]); - let value = static_init!([u8; 3], [0x10, 0x20, 0x30]); - let ret = static_init!([u8; 4], [0; 4]); - - let test = static_init!( - KVSystemTest< - 'static, - TicKVSystem< - 'static, - FlashUser<'static, lowrisc::flash_ctrl::FlashCtrl<'static>>, - capsules_extra::sip_hash::SipHasher24, - 2048, - >, - TicKVKeyType, - >, - KVSystemTest::new(tickv, SubSliceMut::new(value), ret) - ); - - sip_hasher.set_client(tickv); - tickv.set_client(test); - - // Kick start the tests by generating a key - tickv - .generate_key(SubSliceMut::new(key_input), key) - .unwrap(); - } - run_kernel_op(100000); +//! Test the opentitan Flash Controller +//! Tests: read_page, write_page, erase_page +use crate::tests::run_kernel_op; +use crate::PERIPHERALS; +use core::cell::Cell; +use kernel::debug; +#[allow(unused_imports)] +use kernel::errorcode::ErrorCode; +use kernel::hil; +#[allow(unused_imports)] +use kernel::hil::flash::Flash; +use kernel::hil::flash::HasClient; +use kernel::static_init; +use kernel::utilities::cells::TakeCell; +#[allow(unused_imports)] +use lowrisc::flash_ctrl::FlashMPConfig; +#[allow(unused_imports)] +use lowrisc::flash_ctrl::FLASH_ADDR_OFFSET; +#[allow(unused_imports)] +use lowrisc::flash_ctrl::PAGE_SIZE; +#[allow(dead_code)] +struct FlashCtlCallBack { + read_pending: Cell, + write_pending: Cell, + // A lowrisc page to for reads/writes + read_in_page: TakeCell<'static, lowrisc::flash_ctrl::LowRiscPage>, + write_in_page: TakeCell<'static, lowrisc::flash_ctrl::LowRiscPage>, + // We recover the callback returned buffer into these + read_out_buf: TakeCell<'static, [u8]>, + write_out_buf: TakeCell<'static, [u8]>, + // Flag if an MP fault was detected + mp_fault_detect: Cell, +} - debug!(" [ok]"); - run_kernel_op(100); +impl<'a> FlashCtlCallBack { + fn new( + read_in_page: &'static mut lowrisc::flash_ctrl::LowRiscPage, + write_in_page: &'static mut lowrisc::flash_ctrl::LowRiscPage, + ) -> Self { + FlashCtlCallBack { + read_pending: Cell::new(false), + write_pending: Cell::new(false), + read_in_page: TakeCell::new(read_in_page), + write_in_page: TakeCell::new(write_in_page), + read_out_buf: TakeCell::empty(), + write_out_buf: TakeCell::empty(), + mp_fault_detect: Cell::new(false), + } } -} -mod protections_and_controller { - use crate::tests::run_kernel_op; - use crate::PERIPHERALS; - use core::cell::Cell; - use kernel::debug; - use kernel::errorcode::ErrorCode; - use kernel::hil; - use kernel::hil::flash::Flash; - use kernel::hil::flash::HasClient; - use kernel::static_init; - use kernel::utilities::cells::TakeCell; - use lowrisc::flash_ctrl::FlashMPConfig; - use lowrisc::flash_ctrl::FLASH_ADDR_OFFSET; - use lowrisc::flash_ctrl::PAGE_SIZE; - - struct FlashCtlCallBack { - read_pending: Cell, - write_pending: Cell, - // A lowrisc page to for reads/writes - read_in_page: TakeCell<'static, lowrisc::flash_ctrl::LowRiscPage>, - write_in_page: TakeCell<'static, lowrisc::flash_ctrl::LowRiscPage>, - // We recover the callback returned buffer into these - read_out_buf: TakeCell<'static, [u8]>, - write_out_buf: TakeCell<'static, [u8]>, - // Flag if an MP fault was detected - mp_fault_detect: Cell, + fn reset(&self) { + self.read_pending.set(false); + self.write_pending.set(false); + self.mp_fault_detect.set(false); } +} - impl<'a> FlashCtlCallBack { - fn new( - read_in_page: &'static mut lowrisc::flash_ctrl::LowRiscPage, - write_in_page: &'static mut lowrisc::flash_ctrl::LowRiscPage, - ) -> Self { - FlashCtlCallBack { - read_pending: Cell::new(false), - write_pending: Cell::new(false), - read_in_page: TakeCell::new(read_in_page), - write_in_page: TakeCell::new(write_in_page), - read_out_buf: TakeCell::empty(), - write_out_buf: TakeCell::empty(), - mp_fault_detect: Cell::new(false), +impl<'a, F: hil::flash::Flash> hil::flash::Client for FlashCtlCallBack { + fn read_complete(&self, page: &'static mut F::Page, result: Result<(), hil::flash::Error>) { + if self.read_pending.get() { + if result.is_err() { + let error = result.unwrap_err(); + assert_eq!(error, hil::flash::Error::FlashMemoryProtectionError); + self.mp_fault_detect.set(true); } - } - - fn reset(&self) { + self.read_out_buf.replace(page.as_mut()); self.read_pending.set(false); - self.write_pending.set(false); - self.mp_fault_detect.set(false); } } - impl<'a, F: hil::flash::Flash> hil::flash::Client for FlashCtlCallBack { - fn read_complete(&self, page: &'static mut F::Page, error: hil::flash::Error) { - if self.read_pending.get() { - if error == hil::flash::Error::FlashMemoryProtectionError { - self.mp_fault_detect.set(true); - } else { - assert_eq!(error, hil::flash::Error::CommandComplete); - } - self.read_out_buf.replace(page.as_mut()); - self.read_pending.set(false); + fn write_complete(&self, page: &'static mut F::Page, result: Result<(), hil::flash::Error>) { + if self.write_pending.get() { + if result.is_err() { + let error = result.unwrap_err(); + assert_eq!(error, hil::flash::Error::FlashMemoryProtectionError); + self.mp_fault_detect.set(true); } + self.write_out_buf.replace(page.as_mut()); + self.write_pending.set(false); } + } - fn write_complete(&self, page: &'static mut F::Page, error: hil::flash::Error) { - if self.write_pending.get() { - if error == hil::flash::Error::FlashMemoryProtectionError { - self.mp_fault_detect.set(true); - } else { - assert_eq!(error, hil::flash::Error::CommandComplete); - } - self.write_out_buf.replace(page.as_mut()); - self.write_pending.set(false); - } + fn erase_complete(&self, result: Result<(), hil::flash::Error>) { + // Caller may check by a successive page read to assert the erased + // page is composed of 0xFF (all erased bits should be 1) + if result.is_err() { + let error = result.unwrap_err(); + assert_eq!(error, hil::flash::Error::FlashMemoryProtectionError); + self.mp_fault_detect.set(true); } + } +} - fn erase_complete(&self, error: hil::flash::Error) { - // Caller may check by a successive page read to assert the erased - // page is composed of 0xFF (all erased bits should be 1) - if error == hil::flash::Error::FlashMemoryProtectionError { - self.mp_fault_detect.set(true); - } else { - assert_eq!(error, hil::flash::Error::CommandComplete); - } +macro_rules! static_init_test { + () => {{ + let r_in_page = static_init!( + lowrisc::flash_ctrl::LowRiscPage, + lowrisc::flash_ctrl::LowRiscPage::default() + ); + let w_in_page = static_init!( + lowrisc::flash_ctrl::LowRiscPage, + lowrisc::flash_ctrl::LowRiscPage::default() + ); + let mut val: u8 = 0; + + for i in 0..lowrisc::flash_ctrl::PAGE_SIZE { + val = val.wrapping_add(10); + r_in_page[i] = 0x00; + w_in_page[i] = 0xAA; // Arbitrary Data } - } + static_init!( + FlashCtlCallBack, + FlashCtlCallBack::new(r_in_page, w_in_page) + ) + }}; +} - macro_rules! static_init_test { - () => {{ - let r_in_page = static_init!( - lowrisc::flash_ctrl::LowRiscPage, - lowrisc::flash_ctrl::LowRiscPage::default() - ); - let w_in_page = static_init!( - lowrisc::flash_ctrl::LowRiscPage, - lowrisc::flash_ctrl::LowRiscPage::default() - ); - let mut val: u8 = 0; - - for i in 0..lowrisc::flash_ctrl::PAGE_SIZE { - val = val.wrapping_add(10); - r_in_page[i] = 0x00; - w_in_page[i] = 0xAA; // Arbitrary Data - } - static_init!( - FlashCtlCallBack, - FlashCtlCallBack::new(r_in_page, w_in_page) - ) - }}; - } +/// The only 'test_case' for flash_ctrl as directly invoked by the test runner, +/// this calls all the other tests, preserving the order in which they must +/// be ran. +#[test_case] +fn flash_ctrl_tester() { + flash_ctrl_read_write_page(); + flash_ctrl_erase_page(); + flash_ctrl_mp_basic(); + flash_ctrl_mp_functionality(); +} - /// The only 'test_case' for flash_ctrl as directly invoked by the test runner, - /// this calls all the other tests, preserving the order in which they must - /// be ran. - #[test_case] - fn flash_ctrl_tester() { - flash_ctrl_read_write_page(); - flash_ctrl_erase_page(); - flash_ctrl_mp_basic(); - flash_ctrl_mp_functionality(); - } +// Note: the tests below need to run in a particular order, hence the a, b, c... +// function name prefix (test runner seems to invoke them alphabetically). - // Note: the tests below need to run in a particular order, hence the a, b, c... - // function name prefix (test runner seems to invoke them alphabetically). +/// Tests: Erase Page -> Write Page -> Read Page +/// +/// Compare the data we wrote is stored in flash with a +/// successive read. +fn flash_ctrl_read_write_page() { + let perf = unsafe { PERIPHERALS.unwrap() }; + let flash_ctl = &perf.flash_ctrl; - /// Tests: Erase Page -> Write Page -> Read Page - /// - /// Compare the data we wrote is stored in flash with a - /// successive read. - fn flash_ctrl_read_write_page() { - let perf = unsafe { PERIPHERALS.unwrap() }; - let flash_ctl = &perf.flash_ctrl; + let cb = unsafe { static_init_test!() }; + flash_ctl.set_client(cb); + cb.reset(); - let cb = unsafe { static_init_test!() }; - flash_ctl.set_client(cb); - cb.reset(); + debug!("[FLASH_CTRL] Test page read/write...."); - debug!("[FLASH_CTRL] Test page read/write...."); - - #[cfg(feature = "hardware_tests")] - { - let page_num: usize = 511; - run_kernel_op(100); - // Lets do a page erase - assert!(flash_ctl.erase_page(page_num).is_ok()); - run_kernel_op(100); - - // Do Page Write - let write_page = cb.write_in_page.take().unwrap(); - assert!(flash_ctl.write_page(page_num, write_page).is_ok()); - cb.write_pending.set(true); - run_kernel_op(100); - // OP Complete, buffer recovered. - assert!(!cb.write_pending.get()); - cb.reset(); - - // Read the same page - let read_page = cb.read_in_page.take().unwrap(); - assert!(flash_ctl.read_page(page_num, read_page).is_ok()); - cb.read_pending.set(true); - run_kernel_op(100); - assert!(!cb.read_pending.get()); - cb.reset(); - - // Compare r/w buffer - let write_in = cb.write_out_buf.take().unwrap(); // Recovered buffer is saved here as &[u8] - let read_out = cb.read_out_buf.take().unwrap(); - - assert_eq!(write_in.len(), read_out.len()); - assert!( - write_in.iter().zip(read_out.iter()).all(|(i, j)| i == j), - "[ERR] Read data indicates flash write error on page {}", - page_num - ); - - cb.write_out_buf.replace(write_in); - cb.read_out_buf.replace(read_out); - } + #[cfg(feature = "hardware_tests")] + { + let page_num: usize = 511; + run_kernel_op(100); + // Lets do a page erase + assert!(flash_ctl.erase_page(page_num).is_ok()); + run_kernel_op(100); + // Do Page Write + let write_page = cb.write_in_page.take().unwrap(); + assert!(flash_ctl.write_page(page_num, write_page).is_ok()); + cb.write_pending.set(true); run_kernel_op(100); - debug!(" [ok]"); + // OP Complete, buffer recovered. + assert!(!cb.write_pending.get()); + cb.reset(); + + // Read the same page + let read_page = cb.read_in_page.take().unwrap(); + assert!(flash_ctl.read_page(page_num, read_page).is_ok()); + cb.read_pending.set(true); run_kernel_op(100); + assert!(!cb.read_pending.get()); + cb.reset(); + + // Compare r/w buffer + let write_in = cb.write_out_buf.take().unwrap(); // Recovered buffer is saved here as &[u8] + let read_out = cb.read_out_buf.take().unwrap(); + + assert_eq!(write_in.len(), read_out.len()); + assert!( + write_in.iter().zip(read_out.iter()).all(|(i, j)| i == j), + "[ERR] Read data indicates flash write error on page {}", + page_num + ); + + cb.write_out_buf.replace(write_in); + cb.read_out_buf.replace(read_out); } - /// Tests: Erase Page -> Write Page -> Erase Page -> Read Page - /// A page erased should set all bits to `1`s or all bytes in page to - /// `0xFF`. Assert this is true after writing data to a page and erasing - /// the page. - fn flash_ctrl_erase_page() { - let perf = unsafe { PERIPHERALS.unwrap() }; - let flash_ctl = &perf.flash_ctrl; + run_kernel_op(100); + debug!(" [ok]"); + run_kernel_op(100); +} - let cb = unsafe { static_init_test!() }; +/// Tests: Erase Page -> Write Page -> Erase Page -> Read Page +/// A page erased should set all bits to `1`s or all bytes in page to +/// `0xFF`. Assert this is true after writing data to a page and erasing +/// the page. +fn flash_ctrl_erase_page() { + let perf = unsafe { PERIPHERALS.unwrap() }; + let flash_ctl = &perf.flash_ctrl; + + let cb = unsafe { static_init_test!() }; + cb.reset(); + flash_ctl.set_client(cb); + + debug!("[FLASH_CTRL] Test page erase...."); + + #[cfg(feature = "hardware_tests")] + { + let page_num: usize = 500; + run_kernel_op(100); + // Lets do a page erase + assert!(flash_ctl.erase_page(page_num).is_ok()); + run_kernel_op(100); + + // Do Page Write + let write_page = cb.write_in_page.take().unwrap(); + assert!(flash_ctl.write_page(page_num, write_page).is_ok()); + cb.write_pending.set(true); + run_kernel_op(100); + // OP Complete, buffer recovered. + assert!(!cb.write_pending.get()); cb.reset(); - flash_ctl.set_client(cb); - debug!("[FLASH_CTRL] Test page erase...."); - - #[cfg(feature = "hardware_tests")] - { - let page_num: usize = 500; - run_kernel_op(100); - // Lets do a page erase - assert!(flash_ctl.erase_page(page_num).is_ok()); - run_kernel_op(100); - - // Do Page Write - let write_page = cb.write_in_page.take().unwrap(); - assert!(flash_ctl.write_page(page_num, write_page).is_ok()); - cb.write_pending.set(true); - run_kernel_op(100); - // OP Complete, buffer recovered. - assert!(!cb.write_pending.get()); - cb.reset(); - - // Erase again - assert!(flash_ctl.erase_page(page_num).is_ok()); - run_kernel_op(100); - - // Read Page - let read_page = cb.read_in_page.take().unwrap(); - assert!(flash_ctl.read_page(page_num, read_page).is_ok()); - cb.read_pending.set(true); - run_kernel_op(100); - assert!(!cb.read_pending.get()); - cb.reset(); - - // Check that the erased paged is all `0xFF` bytes - let read_out = cb.read_out_buf.take().unwrap(); - assert!( - read_out.iter().all(|&a| a == 0xFF), - "[ERR] Read data indicates erase failure on page {}", - page_num - ); - - cb.read_out_buf.replace(read_out); - } + // Erase again + assert!(flash_ctl.erase_page(page_num).is_ok()); run_kernel_op(100); - debug!(" [ok]"); + + // Read Page + let read_page = cb.read_in_page.take().unwrap(); + assert!(flash_ctl.read_page(page_num, read_page).is_ok()); + cb.read_pending.set(true); run_kernel_op(100); + assert!(!cb.read_pending.get()); + cb.reset(); + + // Check that the erased paged is all `0xFF` bytes + let read_out = cb.read_out_buf.take().unwrap(); + assert!( + read_out.iter().all(|&a| a == 0xFF), + "[ERR] Read data indicates erase failure on page {}", + page_num + ); + + cb.read_out_buf.replace(read_out); } + run_kernel_op(100); + debug!(" [ok]"); + run_kernel_op(100); +} - /// Tests: The basic api functionality and error handling of invalid arguments. - fn flash_ctrl_mp_basic() { - debug!("[FLASH_CTRL] Test memory protection api...."); - - #[cfg(feature = "hardware_tests")] - { - let perf = unsafe { PERIPHERALS.unwrap() }; - let flash_ctl = &perf.flash_ctrl; - // BANK1 - let base_page_addr: usize = (400 * PAGE_SIZE).saturating_add(FLASH_ADDR_OFFSET); - // Pages indexing starts with 0 and we have 512 pages. - let invalid_page_addr: usize = (512 * PAGE_SIZE).saturating_add(FLASH_ADDR_OFFSET); - let valid_num_pages: usize = 10; - // Note: Region 0 is occupied by board setup - let valid_region: usize = 6; - let invalid_region: usize = 8; - let num_regions = flash_ctl.mp_get_num_regions().unwrap(); - // WARN: Revisit these tests if cfgs have changed in HW - assert_eq!(num_regions, lowrisc::flash_ctrl::FLASH_MP_MAX_CFGS as u32); - - for region_num in 0..8 { - // All 8 regions should be unlocked at reset - assert!(flash_ctl.mp_is_region_locked(region_num).is_ok()) - } +/// Tests: The basic api functionality and error handling of invalid arguments. +fn flash_ctrl_mp_basic() { + debug!("[FLASH_CTRL] Test memory protection api...."); - let cfg_set = FlashMPConfig { - read_en: false, - write_en: true, - erase_en: false, - scramble_en: false, - ecc_en: true, - he_en: false, - }; - // Expect Fail - assert_eq!( - flash_ctl.mp_set_region_perms( - base_page_addr, - invalid_page_addr, - valid_region, - &cfg_set - ), - Err(ErrorCode::NOSUPPORT) - ); - assert_eq!( - flash_ctl.mp_set_region_perms( - invalid_page_addr, - base_page_addr, - valid_region, - &cfg_set - ), - Err(ErrorCode::NOSUPPORT) - ); - assert_eq!( - flash_ctl.mp_set_region_perms( - base_page_addr, - base_page_addr.saturating_add(valid_num_pages * PAGE_SIZE), - invalid_region, - &cfg_set - ), - Err(ErrorCode::NOSUPPORT) - ); - // Set Perms - assert!(flash_ctl - .mp_set_region_perms( - base_page_addr, - base_page_addr.saturating_add(valid_num_pages * PAGE_SIZE), - valid_region, - &cfg_set - ) - .is_ok()); - // Check Perms - assert_eq!( - flash_ctl.mp_read_region_perms(valid_region).unwrap(), - cfg_set - ); - // Lock region - assert!(flash_ctl.mp_lock_region_cfg(valid_region).is_ok()); - assert!(flash_ctl.mp_is_region_locked(valid_region).unwrap()); + #[cfg(feature = "hardware_tests")] + { + let perf = unsafe { PERIPHERALS.unwrap() }; + let flash_ctl = &perf.flash_ctrl; + // BANK1 + let base_page_addr: usize = (400 * PAGE_SIZE).saturating_add(FLASH_ADDR_OFFSET); + // Pages indexing starts with 0 and we have 512 pages. + let invalid_page_addr: usize = (512 * PAGE_SIZE).saturating_add(FLASH_ADDR_OFFSET); + let valid_num_pages: usize = 10; + // Note: Region 0 is occupied by board setup + let valid_region: usize = 6; + let invalid_region: usize = 8; + let num_regions = flash_ctl.mp_get_num_regions().unwrap(); + // WARN: Revisit these tests if cfgs have changed in HW + assert_eq!(num_regions, lowrisc::flash_ctrl::FLASH_MP_MAX_CFGS as u32); + + for region_num in 0..8 { + // All 8 regions should be unlocked at reset + assert!(flash_ctl.mp_is_region_locked(region_num).is_ok()) } - run_kernel_op(100); - debug!(" [ok]"); - run_kernel_op(100); + let cfg_set = FlashMPConfig { + read_en: false, + write_en: true, + erase_en: false, + scramble_en: false, + ecc_en: true, + he_en: false, + }; + // Expect Fail + assert_eq!( + flash_ctl.mp_set_region_perms( + base_page_addr, + invalid_page_addr, + valid_region, + &cfg_set + ), + Err(ErrorCode::NOSUPPORT) + ); + assert_eq!( + flash_ctl.mp_set_region_perms( + invalid_page_addr, + base_page_addr, + valid_region, + &cfg_set + ), + Err(ErrorCode::NOSUPPORT) + ); + assert_eq!( + flash_ctl.mp_set_region_perms( + base_page_addr, + base_page_addr.saturating_add(valid_num_pages * PAGE_SIZE), + invalid_region, + &cfg_set + ), + Err(ErrorCode::NOSUPPORT) + ); + // Set Perms + assert!(flash_ctl + .mp_set_region_perms( + base_page_addr, + base_page_addr.saturating_add(valid_num_pages * PAGE_SIZE), + valid_region, + &cfg_set + ) + .is_ok()); + // Check Perms + assert_eq!( + flash_ctl.mp_read_region_perms(valid_region).unwrap(), + cfg_set + ); + // Lock region + assert!(flash_ctl.mp_lock_region_cfg(valid_region).is_ok()); + assert!(flash_ctl.mp_is_region_locked(valid_region).unwrap()); } - /// Tests the memory protection functionality of the flash_ctrl - /// Test: Setup memory protection -> Do bad OP/cause an MP Fault -> Expect fail/assert Err(FlashMPFault) - fn flash_ctrl_mp_functionality() { - debug!("[FLASH_CTRL] Test memory protection functionality...."); - - #[cfg(feature = "hardware_tests")] - { - let perf = unsafe { PERIPHERALS.unwrap() }; - let flash_ctl = &perf.flash_ctrl; - let cb = unsafe { static_init_test!() }; - cb.reset(); - flash_ctl.set_client(cb); - - // BANK1 - let page_num: usize = 450; - let base_page_addr: usize = (page_num * PAGE_SIZE).saturating_add(FLASH_ADDR_OFFSET); - let num_pages: usize = 25; - // Note: Region 0 is occupied by board setup - let region: usize = 7; - let invalid_region: usize = 142; - - for region_num in 0..8 { - // All 8 regions should be unlocked at reset - assert!(flash_ctl.mp_is_region_locked(region_num).is_ok()) - } + run_kernel_op(100); + debug!(" [ok]"); + run_kernel_op(100); +} + +/// Tests the memory protection functionality of the flash_ctrl +/// Test: Setup memory protection -> Do bad OP/cause an MP Fault -> Expect fail/assert Err(FlashMPFault) +fn flash_ctrl_mp_functionality() { + debug!("[FLASH_CTRL] Test memory protection functionality...."); - let cfg_set = FlashMPConfig { - // NOTE: We disable read access, then later try to read to trigger the fault - read_en: false, - write_en: true, - // NOTE: We disable erase perms, then later try to erase and trigger the fault - erase_en: false, - scramble_en: true, - ecc_en: false, - he_en: true, - }; - // Set Perms - assert!(flash_ctl - .mp_set_region_perms( - base_page_addr, - base_page_addr.saturating_add(num_pages * PAGE_SIZE), - region, - &cfg_set - ) - .is_ok()); - // Check Perms - assert_eq!(flash_ctl.mp_read_region_perms(region).unwrap(), cfg_set); - // Lock Config - Expect Fail - assert_eq!( - flash_ctl.mp_lock_region_cfg(invalid_region), - Err(ErrorCode::NOSUPPORT) - ); - // Lock Config - assert!(flash_ctl.mp_lock_region_cfg(region).is_ok()); - assert!(flash_ctl.mp_is_region_locked(region).unwrap()); - - // Functionality Test 1: We disabled erase for this region, lets try to erase - assert!(flash_ctl.erase_page(page_num).is_ok()); - run_kernel_op(100); - // Ensure that a MP violation was detected - assert!(cb.mp_fault_detect.get()); - // Clear the fault - cb.reset(); - - // Functionality Test 2: We disabled read for this region, lets try to read - // This should trigger an MP fault - // Read Page - let read_page = cb.read_in_page.take().unwrap(); - assert!(flash_ctl.read_page(page_num, read_page).is_ok()); - cb.read_pending.set(true); - run_kernel_op(100); - assert!(!cb.read_pending.get()); - // Ensure that a MP violation was detected - assert!(cb.mp_fault_detect.get()); - cb.reset(); + #[cfg(feature = "hardware_tests")] + { + let perf = unsafe { PERIPHERALS.unwrap() }; + let flash_ctl = &perf.flash_ctrl; + let cb = unsafe { static_init_test!() }; + cb.reset(); + flash_ctl.set_client(cb); + + // BANK1 + let page_num: usize = 450; + let base_page_addr: usize = (page_num * PAGE_SIZE).saturating_add(FLASH_ADDR_OFFSET); + let num_pages: usize = 25; + // Note: Region 0 is occupied by board setup + let region: usize = 7; + let invalid_region: usize = 142; + + for region_num in 0..8 { + // All 8 regions should be unlocked at reset + assert!(flash_ctl.mp_is_region_locked(region_num).is_ok()) } + let cfg_set = FlashMPConfig { + // NOTE: We disable read access, then later try to read to trigger the fault + read_en: false, + write_en: true, + // NOTE: We disable erase perms, then later try to erase and trigger the fault + erase_en: false, + scramble_en: true, + ecc_en: false, + he_en: true, + }; + // Set Perms + assert!(flash_ctl + .mp_set_region_perms( + base_page_addr, + base_page_addr.saturating_add(num_pages * PAGE_SIZE), + region, + &cfg_set + ) + .is_ok()); + // Check Perms + assert_eq!(flash_ctl.mp_read_region_perms(region).unwrap(), cfg_set); + // Lock Config - Expect Fail + assert_eq!( + flash_ctl.mp_lock_region_cfg(invalid_region), + Err(ErrorCode::NOSUPPORT) + ); + // Lock Config + assert!(flash_ctl.mp_lock_region_cfg(region).is_ok()); + assert!(flash_ctl.mp_is_region_locked(region).unwrap()); + + // Functionality Test 1: We disabled erase for this region, lets try to erase + assert!(flash_ctl.erase_page(page_num).is_ok()); run_kernel_op(100); - debug!(" [ok]"); + // Ensure that a MP violation was detected + assert!(cb.mp_fault_detect.get()); + // Clear the fault + cb.reset(); + + // Functionality Test 2: We disabled read for this region, lets try to read + // This should trigger an MP fault + // Read Page + let read_page = cb.read_in_page.take().unwrap(); + assert!(flash_ctl.read_page(page_num, read_page).is_ok()); + cb.read_pending.set(true); run_kernel_op(100); + assert!(!cb.read_pending.get()); + // Ensure that a MP violation was detected + assert!(cb.mp_fault_detect.get()); + cb.reset(); } + + run_kernel_op(100); + debug!(" [ok]"); + run_kernel_op(100); } diff --git a/capsules/core/src/virtualizers/virtual_flash.rs b/capsules/core/src/virtualizers/virtual_flash.rs index 400219423b..ea3993ecf5 100644 --- a/capsules/core/src/virtualizers/virtual_flash.rs +++ b/capsules/core/src/virtualizers/virtual_flash.rs @@ -47,23 +47,31 @@ pub struct MuxFlash<'a, F: hil::flash::Flash + 'static> { } impl hil::flash::Client for MuxFlash<'_, F> { - fn read_complete(&self, pagebuffer: &'static mut F::Page, error: hil::flash::Error) { + fn read_complete( + &self, + pagebuffer: &'static mut F::Page, + result: Result<(), hil::flash::Error>, + ) { self.inflight.take().map(move |user| { - user.read_complete(pagebuffer, error); + user.read_complete(pagebuffer, result); }); self.do_next_op(); } - fn write_complete(&self, pagebuffer: &'static mut F::Page, error: hil::flash::Error) { + fn write_complete( + &self, + pagebuffer: &'static mut F::Page, + result: Result<(), hil::flash::Error>, + ) { self.inflight.take().map(move |user| { - user.write_complete(pagebuffer, error); + user.write_complete(pagebuffer, result); }); self.do_next_op(); } - fn erase_complete(&self, error: hil::flash::Error) { + fn erase_complete(&self, result: Result<(), hil::flash::Error>) { self.inflight.take().map(move |user| { - user.erase_complete(error); + user.erase_complete(result); }); self.do_next_op(); } @@ -165,21 +173,29 @@ impl<'a, F: hil::flash::Flash, C: hil::flash::Client> hil::flash::HasClien } impl<'a, F: hil::flash::Flash> hil::flash::Client for FlashUser<'a, F> { - fn read_complete(&self, pagebuffer: &'static mut F::Page, error: hil::flash::Error) { + fn read_complete( + &self, + pagebuffer: &'static mut F::Page, + result: Result<(), hil::flash::Error>, + ) { self.client.map(move |client| { - client.read_complete(pagebuffer, error); + client.read_complete(pagebuffer, result); }); } - fn write_complete(&self, pagebuffer: &'static mut F::Page, error: hil::flash::Error) { + fn write_complete( + &self, + pagebuffer: &'static mut F::Page, + result: Result<(), hil::flash::Error>, + ) { self.client.map(move |client| { - client.write_complete(pagebuffer, error); + client.write_complete(pagebuffer, result); }); } - fn erase_complete(&self, error: hil::flash::Error) { + fn erase_complete(&self, result: Result<(), hil::flash::Error>) { self.client.map(move |client| { - client.erase_complete(error); + client.erase_complete(result); }); } } diff --git a/capsules/extra/src/at24c_eeprom.rs b/capsules/extra/src/at24c_eeprom.rs index b9344930ec..c194273df7 100644 --- a/capsules/extra/src/at24c_eeprom.rs +++ b/capsules/extra/src/at24c_eeprom.rs @@ -186,9 +186,9 @@ impl I2CClient for AT24C<'static> { self.buffer.replace(buffer); self.flash_client.map(|client| { if status.is_err() { - client.read_complete(client_page, hil::flash::Error::FlashError); + client.read_complete(client_page, Err(hil::flash::Error::FlashError)); } else { - client.read_complete(client_page, hil::flash::Error::CommandComplete); + client.read_complete(client_page, Ok(())); } }); } @@ -200,9 +200,9 @@ impl I2CClient for AT24C<'static> { self.flash_client.map(|client| { if let Some(client_page) = self.client_page.take() { if status.is_err() { - client.write_complete(client_page, hil::flash::Error::FlashError); + client.write_complete(client_page, Err(hil::flash::Error::FlashError)); } else { - client.write_complete(client_page, hil::flash::Error::CommandComplete); + client.write_complete(client_page, Ok(())); } } }); @@ -213,9 +213,9 @@ impl I2CClient for AT24C<'static> { self.i2c.disable(); self.flash_client.map(move |client| { if status.is_err() { - client.erase_complete(hil::flash::Error::FlashError); + client.erase_complete(Err(hil::flash::Error::FlashError)); } else { - client.erase_complete(hil::flash::Error::CommandComplete); + client.erase_complete(Ok(())); } }); } diff --git a/capsules/extra/src/humidity.rs b/capsules/extra/src/humidity.rs index ab130db4a3..9b4e9493b2 100644 --- a/capsules/extra/src/humidity.rs +++ b/capsules/extra/src/humidity.rs @@ -25,7 +25,7 @@ //! The `command` system call support one argument `cmd` which is used to specify the specific //! operation, currently the following cmd's are supported: //! -//! * `0`: driver existence check +//! * `0`: check whether the driver exists //! * `1`: read humidity //! //! diff --git a/capsules/extra/src/log.rs b/capsules/extra/src/log.rs index cf2078d280..640fad006e 100644 --- a/capsules/extra/src/log.rs +++ b/capsules/extra/src/log.rs @@ -783,16 +783,16 @@ impl<'a, F: Flash + 'static> LogWrite<'a> for Log<'a, F> { } impl<'a, F: Flash + 'static> flash::Client for Log<'a, F> { - fn read_complete(&self, _read_buffer: &'static mut F::Page, _error: flash::Error) { + fn read_complete(&self, _read_buffer: &'static mut F::Page, _result: Result<(), flash::Error>) { // Reads are made directly from the storage volume, not through the flash interface. unreachable!(); } /// If in the middle of a write operation, reset pagebuffer and finish write. If syncing, make /// successful client callback. - fn write_complete(&self, pagebuffer: &'static mut F::Page, error: flash::Error) { - match error { - flash::Error::CommandComplete => { + fn write_complete(&self, pagebuffer: &'static mut F::Page, result: Result<(), flash::Error>) { + match result.is_ok() { + true => { match self.state.get() { State::Append => { // Reset pagebuffer and finish writing on the new page. @@ -824,21 +824,25 @@ impl<'a, F: Flash + 'static> flash::Client for Log<'a, F> { _ => unreachable!(), } } - flash::Error::FlashError | flash::Error::FlashMemoryProtectionError => { - // Make client callback with FAIL return code. - self.pagebuffer.replace(pagebuffer); - match self.state.get() { - State::Append => { - self.length.set(0); - self.records_lost.set(false); - self.error.set(Err(ErrorCode::FAIL)); - self.client_callback(); - } - State::Sync => { - self.error.set(Err(ErrorCode::FAIL)); - self.client_callback(); + false => { + match result.unwrap_err() { + flash::Error::FlashError | flash::Error::FlashMemoryProtectionError => { + // Make client callback with FAIL return code. + self.pagebuffer.replace(pagebuffer); + match self.state.get() { + State::Append => { + self.length.set(0); + self.records_lost.set(false); + self.error.set(Err(ErrorCode::FAIL)); + self.client_callback(); + } + State::Sync => { + self.error.set(Err(ErrorCode::FAIL)); + self.client_callback(); + } + _ => unreachable!(), + } } - _ => unreachable!(), } } } @@ -846,9 +850,9 @@ impl<'a, F: Flash + 'static> flash::Client for Log<'a, F> { /// Erase next page if log erase complete, else make client callback. Fails with BUSY if flash /// is busy and erase cannot be completed. - fn erase_complete(&self, error: flash::Error) { - match error { - flash::Error::CommandComplete => { + fn erase_complete(&self, result: Result<(), flash::Error>) { + match result.is_ok() { + true => { let oldest_entry_id = self.oldest_entry_id.get(); if oldest_entry_id >= self.append_entry_id.get() - self.page_size { // Erased all pages. Reset state and callback client. @@ -872,10 +876,12 @@ impl<'a, F: Flash + 'static> flash::Client for Log<'a, F> { } } } - flash::Error::FlashError | flash::Error::FlashMemoryProtectionError => { - self.error.set(Err(ErrorCode::FAIL)); - self.client_callback(); - } + false => match result.unwrap_err() { + flash::Error::FlashError | flash::Error::FlashMemoryProtectionError => { + self.error.set(Err(ErrorCode::FAIL)); + self.client_callback(); + } + }, } } } diff --git a/capsules/extra/src/mx25r6435f.rs b/capsules/extra/src/mx25r6435f.rs index 866c8e5b5f..f265b1a1c9 100644 --- a/capsules/extra/src/mx25r6435f.rs +++ b/capsules/extra/src/mx25r6435f.rs @@ -404,7 +404,7 @@ impl< self.rxbuffer.replace(read_buffer); self.client.map(move |client| { - client.read_complete(sector, hil::flash::Error::CommandComplete); + client.read_complete(sector, Ok(())); }); } else { let address = @@ -480,7 +480,7 @@ impl< self.state.set(State::Idle); self.txbuffer.replace(write_buffer); self.client.map(|client| { - client.erase_complete(hil::flash::Error::CommandComplete); + client.erase_complete(Ok(())); }); } State::WriteSectorWriteEnable { @@ -495,7 +495,7 @@ impl< self.txbuffer.replace(write_buffer); self.client.map(|client| { self.client_sector.take().map(|sector| { - client.write_complete(sector, hil::flash::Error::CommandComplete); + client.write_complete(sector, Ok(())); }); }); } else { diff --git a/capsules/extra/src/nonvolatile_to_pages.rs b/capsules/extra/src/nonvolatile_to_pages.rs index 3da4dc4fee..463182b3c9 100644 --- a/capsules/extra/src/nonvolatile_to_pages.rs +++ b/capsules/extra/src/nonvolatile_to_pages.rs @@ -192,7 +192,11 @@ impl<'a, F: hil::flash::Flash> hil::nonvolatile_storage::NonvolatileStorage<'a> } impl hil::flash::Client for NonvolatileToPages<'_, F> { - fn read_complete(&self, pagebuffer: &'static mut F::Page, _error: hil::flash::Error) { + fn read_complete( + &self, + pagebuffer: &'static mut F::Page, + _result: Result<(), hil::flash::Error>, + ) { match self.state.get() { State::Read => { // OK we got a page from flash. Copy what we actually want from it @@ -267,7 +271,11 @@ impl hil::flash::Client for NonvolatileToPages<'_, F> { } } - fn write_complete(&self, pagebuffer: &'static mut F::Page, _error: hil::flash::Error) { + fn write_complete( + &self, + pagebuffer: &'static mut F::Page, + _result: Result<(), hil::flash::Error>, + ) { // After a write we could be done, need to do another write, or need to // do a read. self.buffer.take().map(move |buffer| { @@ -308,5 +316,5 @@ impl hil::flash::Client for NonvolatileToPages<'_, F> { }); } - fn erase_complete(&self, _error: hil::flash::Error) {} + fn erase_complete(&self, _result: Result<(), hil::flash::Error>) {} } diff --git a/capsules/extra/src/tickv.rs b/capsules/extra/src/tickv.rs index 8de5655f91..bd659951b4 100644 --- a/capsules/extra/src/tickv.rs +++ b/capsules/extra/src/tickv.rs @@ -414,7 +414,7 @@ impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> hasher::Client<8> impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> flash::Client for TicKVSystem<'a, F, H, PAGE_SIZE> { - fn read_complete(&self, pagebuffer: &'static mut F::Page, _error: flash::Error) { + fn read_complete(&self, pagebuffer: &'static mut F::Page, _result: Result<(), flash::Error>) { self.tickv.set_read_buffer(pagebuffer.as_mut()); self.tickv .tickv @@ -559,7 +559,7 @@ impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> flash::Client } } - fn write_complete(&self, pagebuffer: &'static mut F::Page, _error: flash::Error) { + fn write_complete(&self, pagebuffer: &'static mut F::Page, _result: Result<(), flash::Error>) { self.tickv .tickv .controller @@ -590,7 +590,7 @@ impl<'a, F: Flash, H: Hasher<'a, 8>, const PAGE_SIZE: usize> flash::Client } } - fn erase_complete(&self, _error: flash::Error) { + fn erase_complete(&self, _result: Result<(), flash::Error>) { let (ret, tickv_buf, tickv_buf_len) = self.tickv.continue_operation(); // If we got the buffer back from TicKV then store it. diff --git a/chips/lowrisc/src/flash_ctrl.rs b/chips/lowrisc/src/flash_ctrl.rs index d0949b18eb..5e39eb8441 100644 --- a/chips/lowrisc/src/flash_ctrl.rs +++ b/chips/lowrisc/src/flash_ctrl.rs @@ -524,7 +524,7 @@ impl<'a> FlashCtrl<'a> { if let Some(buf) = read_buf { // We were doing a read self.flash_client.map(move |client| { - client.read_complete(buf, error); + client.read_complete(buf, Err(error)); }); } @@ -532,14 +532,14 @@ impl<'a> FlashCtrl<'a> { if let Some(buf) = write_buf { // We were doing a write self.flash_client.map(move |client| { - client.write_complete(buf, error); + client.write_complete(buf, Err(error)); }); } if self.registers.control.matches_all(CONTROL::OP::ERASE) { // We were doing an erase self.flash_client.map(move |client| { - client.erase_complete(error); + client.erase_complete(Err(error)); }); } } @@ -622,7 +622,7 @@ impl<'a> FlashCtrl<'a> { self.registers.op_status.set(0); // We have all of the data, call the client self.flash_client.map(move |client| { - client.read_complete(buf, hil::flash::Error::CommandComplete); + client.read_complete(buf, Ok(())); }); } else { // Still waiting on data, keep waiting @@ -638,7 +638,7 @@ impl<'a> FlashCtrl<'a> { self.registers.op_status.set(0); // We sent all of the data, call the client self.flash_client.map(move |client| { - client.write_complete(buf, hil::flash::Error::CommandComplete); + client.write_complete(buf, Ok(())); }); } else { // Still writing data, keep trying @@ -648,7 +648,7 @@ impl<'a> FlashCtrl<'a> { } } else if self.registers.control.matches_all(CONTROL::OP::ERASE) { self.flash_client.map(move |client| { - client.erase_complete(hil::flash::Error::CommandComplete); + client.erase_complete(Ok(())); }); } } diff --git a/chips/nrf52/src/nvmc.rs b/chips/nrf52/src/nvmc.rs index 9f7ca88098..dc8b09ae16 100644 --- a/chips/nrf52/src/nvmc.rs +++ b/chips/nrf52/src/nvmc.rs @@ -250,20 +250,20 @@ impl Nvmc { FlashState::Read => { self.client.map(|client| { self.buffer.take().map(|buffer| { - client.read_complete(buffer, hil::flash::Error::CommandComplete); + client.read_complete(buffer, Ok(())); }); }); } FlashState::Write => { self.client.map(|client| { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::CommandComplete); + client.write_complete(buffer, Ok(())); }); }); } FlashState::Erase => { self.client.map(|client| { - client.erase_complete(hil::flash::Error::CommandComplete); + client.erase_complete(Ok(())); }); } _ => {} diff --git a/chips/sam4l/src/flashcalw.rs b/chips/sam4l/src/flashcalw.rs index b2ff5ec8aa..df6ccb8252 100644 --- a/chips/sam4l/src/flashcalw.rs +++ b/chips/sam4l/src/flashcalw.rs @@ -497,18 +497,18 @@ impl FLASHCALW { self.client.map(|client| match attempted_operation { FlashState::Read => { self.buffer.take().map(|buffer| { - client.read_complete(buffer, hil::flash::Error::FlashError); + client.read_complete(buffer, Err(hil::flash::Error::FlashError)); }); } FlashState::WriteUnlocking { .. } | FlashState::WriteErasing { .. } | FlashState::WriteWriting => { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::FlashError); + client.write_complete(buffer, Err(hil::flash::Error::FlashError)); }); } FlashState::EraseUnlocking { .. } | FlashState::EraseErasing => { - client.erase_complete(hil::flash::Error::FlashError); + client.erase_complete(Err(hil::flash::Error::FlashError)); } _ => {} }); @@ -521,7 +521,7 @@ impl FLASHCALW { self.client.map(|client| { self.buffer.take().map(|buffer| { - client.read_complete(buffer, hil::flash::Error::CommandComplete); + client.read_complete(buffer, Ok(())); }); }); } @@ -549,7 +549,7 @@ impl FLASHCALW { self.client.map(|client| { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::CommandComplete); + client.write_complete(buffer, Ok(())); }); }); } @@ -564,7 +564,7 @@ impl FLASHCALW { self.current_state.set(FlashState::Ready); self.client.map(|client| { - client.erase_complete(hil::flash::Error::CommandComplete); + client.erase_complete(Ok(())); }); } _ => { diff --git a/chips/stm32f303xc/src/flash.rs b/chips/stm32f303xc/src/flash.rs index b241c51b58..203eba2e7c 100644 --- a/chips/stm32f303xc/src/flash.rs +++ b/chips/stm32f303xc/src/flash.rs @@ -350,7 +350,7 @@ impl Flash { self.client.map(|client| { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::CommandComplete); + client.write_complete(buffer, Ok(())); }); }); } else { @@ -368,7 +368,7 @@ impl Flash { self.state.set(FlashState::Ready); self.client.map(|client| { - client.erase_complete(hil::flash::Error::CommandComplete); + client.erase_complete(Ok(())); }); } FlashState::WriteOption => { @@ -377,7 +377,7 @@ impl Flash { self.client.map(|client| { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::CommandComplete); + client.write_complete(buffer, Ok(())); }); }); } @@ -386,7 +386,7 @@ impl Flash { self.state.set(FlashState::Ready); self.client.map(|client| { - client.erase_complete(hil::flash::Error::CommandComplete); + client.erase_complete(Ok(())); }); } _ => {} @@ -397,7 +397,7 @@ impl Flash { self.state.set(FlashState::Ready); self.client.map(|client| { self.buffer.take().map(|buffer| { - client.read_complete(buffer, hil::flash::Error::CommandComplete); + client.read_complete(buffer, Ok(())); }); }); } @@ -411,13 +411,13 @@ impl Flash { self.registers.cr.modify(Control::PG::CLEAR); self.client.map(|client| { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::FlashError); + client.write_complete(buffer, Err(hil::flash::Error::FlashError)); }); }); } FlashState::Erase => { self.client.map(|client| { - client.erase_complete(hil::flash::Error::FlashError); + client.erase_complete(Err(hil::flash::Error::FlashError)); }); } _ => {} @@ -435,7 +435,7 @@ impl Flash { self.registers.cr.modify(Control::PG::CLEAR); self.client.map(|client| { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::FlashError); + client.write_complete(buffer, Err(hil::flash::Error::FlashError)); }); }); } @@ -443,13 +443,13 @@ impl Flash { self.registers.cr.modify(Control::OPTPG::CLEAR); self.client.map(|client| { self.buffer.take().map(|buffer| { - client.write_complete(buffer, hil::flash::Error::FlashError); + client.write_complete(buffer, Err(hil::flash::Error::FlashError)); }); }); } FlashState::Erase => { self.client.map(|client| { - client.erase_complete(hil::flash::Error::FlashError); + client.erase_complete(Err(hil::flash::Error::FlashError)); }); } _ => {} diff --git a/kernel/src/hil/flash.rs b/kernel/src/hil/flash.rs index 92312ec7a2..1bb93c2214 100644 --- a/kernel/src/hil/flash.rs +++ b/kernel/src/hil/flash.rs @@ -88,9 +88,9 @@ //! } //! //! impl<'a, F: hil::flash::Flash> hil::flash::Client for FlashUser<'a, F> { -//! fn read_complete(&self, buffer: &'static mut F::Page, error: hil::flash::Error) {} -//! fn write_complete(&self, buffer: &'static mut F::Page, error: hil::flash::Error) { } -//! fn erase_complete(&self, error: hil::flash::Error) {} +//! fn read_complete(&self, buffer: &'static mut F::Page, result: Result<(), hil::flash::Error>) {} +//! fn write_complete(&self, buffer: &'static mut F::Page, result: Result<(), hil::flash::Error>) { } +//! fn erase_complete(&self, result: Result<(), hil::flash::Error>) {} //! } //! ``` @@ -99,9 +99,6 @@ use crate::ErrorCode; /// Flash errors returned in the callbacks. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Error { - /// Success. - CommandComplete, - /// An error occurred during the flash operation. FlashError, @@ -141,11 +138,11 @@ pub trait Flash { /// Implement `Client` to receive callbacks from `Flash`. pub trait Client { /// Flash read complete. - fn read_complete(&self, read_buffer: &'static mut F::Page, error: Error); + fn read_complete(&self, read_buffer: &'static mut F::Page, result: Result<(), Error>); /// Flash write complete. - fn write_complete(&self, write_buffer: &'static mut F::Page, error: Error); + fn write_complete(&self, write_buffer: &'static mut F::Page, result: Result<(), Error>); /// Flash erase complete. - fn erase_complete(&self, error: Error); + fn erase_complete(&self, result: Result<(), Error>); }