mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
prelim take at a HAL for cramium targets for flash read/write
This commit is contained in:
parent
22a72125bd
commit
c68d8b1a77
1 changed files with 117 additions and 1 deletions
|
|
@ -1,9 +1,11 @@
|
|||
use core::fmt::Write;
|
||||
use core::mem::size_of;
|
||||
use std::cell::RefCell;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use aes_gcm_siv::{AeadInPlace, Aes256GcmSiv, Error, KeyInit, Nonce, Tag};
|
||||
use cramium_api::*;
|
||||
use cramium_hal::board::SPIM_RAM_IFRAM_ADDR;
|
||||
use cramium_hal::board::{SPIM_FLASH_IFRAM_ADDR, SPIM_RAM_IFRAM_ADDR};
|
||||
use cramium_hal::ifram::IframRange;
|
||||
use cramium_hal::udma::*;
|
||||
use loader::swap::SwapSpec;
|
||||
|
|
@ -20,6 +22,9 @@ pub struct SwapHal {
|
|||
swap_mac_start: usize,
|
||||
cipher: Aes256GcmSiv,
|
||||
ram_spim: Spim,
|
||||
flash_spim: RefCell<Spim>,
|
||||
// pre-allocate space for merging writes to SPI erase sectors
|
||||
buffer: RefCell<[u8; FLASH_SECTOR_LEN]>,
|
||||
}
|
||||
impl SwapHal {
|
||||
pub fn new(spec: &SwapSpec) -> Self {
|
||||
|
|
@ -54,6 +59,25 @@ impl SwapHal {
|
|||
IframRange::from_raw_parts(SPIM_RAM_IFRAM_ADDR, SWAP_HAL_VADDR, PAGE_SIZE),
|
||||
)
|
||||
},
|
||||
flash_spim: RefCell::new(unsafe {
|
||||
Spim::new_with_ifram(
|
||||
channel,
|
||||
25_000_000,
|
||||
50_000_000,
|
||||
SpimClkPol::LeadingEdgeRise,
|
||||
SpimClkPha::CaptureOnLeading,
|
||||
SpimCs::Cs0,
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
1024, // this is limited by the page length
|
||||
4096,
|
||||
Some(6),
|
||||
Some(SpimMode::Quad), // we're in quad because the loader put us here
|
||||
IframRange::from_raw_parts(SPIM_FLASH_IFRAM_ADDR, SPIM_FLASH_IFRAM_ADDR, PAGE_SIZE * 2),
|
||||
)
|
||||
}),
|
||||
buffer: RefCell::new([0u8; PAGE_SIZE]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,4 +168,96 @@ impl SwapHal {
|
|||
}
|
||||
self.cipher.decrypt_in_place_detached(Nonce::from_slice(&nonce), aad, buf, (&tag).into())
|
||||
}
|
||||
|
||||
/// This wrapper handles arbitrary alignments of `offset` nad sizes of `buf`
|
||||
pub fn flash_read(&self, buf: &mut [u8], offset: usize) {
|
||||
let mut retries = 0;
|
||||
while !self.flash_spim.borrow_mut().mem_read(offset as u32, buf, false) {
|
||||
writeln!(
|
||||
DebugUart {},
|
||||
"FLASH read timeout of data at offset {:x}; data result: {:x?} .. {:x?}",
|
||||
offset,
|
||||
&buf[..16],
|
||||
&buf[buf.len() - 16..]
|
||||
)
|
||||
.ok();
|
||||
retries += 1;
|
||||
if retries > 2 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This wrapper handles arbitrary alignments of `offset` and sizes of `buf`
|
||||
/// `offset` is the offset from the start of FLASH in bytes.
|
||||
pub fn flash_write(&mut self, buf: &[u8], offset: usize) {
|
||||
let mut written = 0;
|
||||
|
||||
// compute amount of data in the FLASH sector buffer to preserve: everything up to the offset
|
||||
let preserve_to = offset & (FLASH_SECTOR_LEN - 1);
|
||||
// 1. check for misaligned page starts
|
||||
if preserve_to != 0 {
|
||||
let replace_end = if buf.len() + preserve_to >= FLASH_SECTOR_LEN {
|
||||
FLASH_SECTOR_LEN
|
||||
} else {
|
||||
buf.len() + preserve_to
|
||||
};
|
||||
let preserve_start = offset & !(FLASH_SECTOR_LEN - 1);
|
||||
{
|
||||
// read in the ROM contents for the page in question. This fully replaces self.buffer,
|
||||
// so we don't need to zeroize it.
|
||||
let mut buff_mut = self.buffer.borrow_mut();
|
||||
self.flash_read(&mut buff_mut[..], preserve_start);
|
||||
}
|
||||
self.buffer.borrow_mut()[preserve_to..replace_end]
|
||||
.copy_from_slice(&buf[..replace_end - preserve_to]);
|
||||
// erase the containing sector
|
||||
self.flash_spim.borrow_mut().flash_erase_sector((offset & !(FLASH_SECTOR_LEN - 1)) as u32);
|
||||
// program the sector: we can use write_page because we're strictly aligned and page-length
|
||||
for (page, addr) in self
|
||||
.buffer
|
||||
.borrow()
|
||||
.chunks_exact(FLASH_PAGE_LEN)
|
||||
.zip((preserve_start..(preserve_start + FLASH_SECTOR_LEN)).step_by(FLASH_PAGE_LEN))
|
||||
{
|
||||
self.flash_spim.borrow_mut().mem_flash_write_page(addr as u32, page.try_into().unwrap());
|
||||
}
|
||||
written += replace_end - preserve_to;
|
||||
}
|
||||
if written == buf.len() {
|
||||
return;
|
||||
}
|
||||
// 2. write remaining pages
|
||||
let remaining_len = buf.len() - written;
|
||||
// this is OK here because we took care of any misaligned start data in step 1.
|
||||
let aligned_start = (offset + (FLASH_SECTOR_LEN - 1)) & !(FLASH_SECTOR_LEN);
|
||||
for sector in (aligned_start
|
||||
..(aligned_start + (remaining_len + (FLASH_SECTOR_LEN - 1)) & !(FLASH_SECTOR_LEN - 1)))
|
||||
.step_by(FLASH_SECTOR_LEN)
|
||||
{
|
||||
assert!(buf.len() >= written);
|
||||
let remaining_chunk = buf.len() - written;
|
||||
{
|
||||
let mut buff_mut = self.buffer.borrow_mut();
|
||||
if remaining_chunk < FLASH_SECTOR_LEN {
|
||||
// this full replaces self.buffer, so we don't need to zeroize it
|
||||
self.flash_read(&mut buff_mut[..], sector);
|
||||
buff_mut[..remaining_chunk].copy_from_slice(&buf[written..]);
|
||||
written += remaining_chunk;
|
||||
} else {
|
||||
buff_mut.copy_from_slice(&buf[written..(written + FLASH_SECTOR_LEN)]);
|
||||
written += FLASH_SECTOR_LEN;
|
||||
}
|
||||
}
|
||||
self.flash_spim.borrow_mut().flash_erase_sector((sector & !(FLASH_SECTOR_LEN - 1)) as u32);
|
||||
for (page, addr) in self
|
||||
.buffer
|
||||
.borrow()
|
||||
.chunks_exact(FLASH_PAGE_LEN)
|
||||
.zip((sector..(sector + FLASH_SECTOR_LEN)).step_by(FLASH_PAGE_LEN))
|
||||
{
|
||||
self.flash_spim.borrow_mut().mem_flash_write_page(addr as u32, page.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue