mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
add platform-dependent drivers for swap
precursor does direct memory mapping cramium uses a qspi interface
This commit is contained in:
parent
dddbc3c163
commit
32857a70b0
5 changed files with 358 additions and 2 deletions
|
|
@ -1,2 +1,6 @@
|
|||
pub mod cramium;
|
||||
pub use cramium::*;
|
||||
#[cfg(feature = "swap")]
|
||||
pub mod swap;
|
||||
#[cfg(feature = "swap")]
|
||||
pub use swap::*;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
use cramium_hal::iox::{Iox, IoxDir, IoxEnable, IoxFunction, IoxPort};
|
||||
use cramium_hal::sce;
|
||||
use cramium_hal::udma;
|
||||
use utralib::generated::*;
|
||||
|
||||
pub const RAM_SIZE: usize = utralib::generated::HW_SRAM_MEM_LEN;
|
||||
pub const RAM_BASE: usize = utralib::generated::HW_SRAM_MEM;
|
||||
|
||||
// Locate the hard-wired IFRAM allocations for UDMA
|
||||
pub const UART_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 4096;
|
||||
// RAM needs two buffers of 1k + 16 bytes = 2048 + 16 = 2064 bytes; round up to one page
|
||||
pub const SPIM_RAM_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 2 * 4096;
|
||||
// Flash will be released after the loader is done: it's only accessed to copy the IniS sectors into swap,
|
||||
// then abandoned. It needs 4096 bytes for Rx, and 0 bytes for Tx + 16 bytes for cmd.
|
||||
pub const SPIM_FLASH_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 4 * 4096;
|
||||
|
||||
// location of kernel, as offset from the base of ReRAM. This needs to match up with what is in link.x.
|
||||
pub const KERNEL_OFFSET: usize = 0x28000;
|
||||
|
||||
|
|
@ -121,7 +128,7 @@ pub fn early_init() {
|
|||
// the address of the UART buffer is "hard-allocated" at an offset one page from the top of
|
||||
// IFRAM0. This is a convention that must be respected by the UDMA UART library implementation
|
||||
// for things to work.
|
||||
let uart_buf_addr = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 4096;
|
||||
let uart_buf_addr = UART_IFRAM_ADDR;
|
||||
let mut udma_uart = unsafe {
|
||||
// safety: this is safe to call, because we set up clock and events prior to calling new.
|
||||
udma::Uart::get_handle(utra::udma_uart_0::HW_UDMA_UART_0_BASE, uart_buf_addr, uart_buf_addr)
|
||||
|
|
|
|||
272
loader/src/platform/cramium/swap.rs
Normal file
272
loader/src/platform/cramium/swap.rs
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
use core::mem::size_of;
|
||||
|
||||
use aes_gcm_siv::{AeadInPlace, Aes256GcmSiv, KeyInit, Nonce, Tag};
|
||||
use cramium_hal::ifram::IframRange;
|
||||
use cramium_hal::iox::*;
|
||||
use cramium_hal::udma::*;
|
||||
|
||||
use crate::bootconfig::BootConfig;
|
||||
use crate::platform::{SPIM_FLASH_IFRAM_ADDR, SPIM_RAM_IFRAM_ADDR};
|
||||
use crate::println;
|
||||
use crate::swap::*;
|
||||
|
||||
/// hard coded at offset 0 of SPI FLASH for now, until we figure out if and how to move this around.
|
||||
const SWAP_IMG_START: usize = 0;
|
||||
|
||||
pub struct SwapHal {
|
||||
image_start: usize,
|
||||
image_mac_start: usize,
|
||||
partial_nonce: [u8; 8],
|
||||
// overflow AAD with panic if it's longer than this!
|
||||
aad_storage: [u8; 64],
|
||||
aad_len: usize,
|
||||
cipher: Aes256GcmSiv,
|
||||
flash_spim: Spim,
|
||||
ram_spim: Spim,
|
||||
iox: Iox,
|
||||
udma_global: GlobalConfig,
|
||||
buf: RawPage,
|
||||
}
|
||||
|
||||
fn setup_port(
|
||||
iox: &mut Iox,
|
||||
port: IoxPort,
|
||||
pin: u8,
|
||||
function: Option<IoxFunction>,
|
||||
direction: Option<IoxDir>,
|
||||
drive: Option<IoxDriveStrength>,
|
||||
slow_slew: Option<IoxEnable>,
|
||||
schmitt: Option<IoxEnable>,
|
||||
pullup: Option<IoxEnable>,
|
||||
) {
|
||||
if let Some(f) = function {
|
||||
iox.set_alternate_function(port, pin, f);
|
||||
}
|
||||
if let Some(d) = direction {
|
||||
iox.set_gpio_dir(port, pin, d);
|
||||
}
|
||||
if let Some(t) = schmitt {
|
||||
iox.set_gpio_schmitt_trigger(port, pin, t);
|
||||
}
|
||||
if let Some(p) = pullup {
|
||||
iox.set_gpio_pullup(port, pin, p);
|
||||
}
|
||||
if let Some(s) = slow_slew {
|
||||
iox.set_slow_slew_rate(port, pin, s);
|
||||
}
|
||||
if let Some(s) = drive {
|
||||
iox.set_drive_strength(port, pin, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl SwapHal {
|
||||
pub fn new(cfg: &BootConfig) -> Option<SwapHal> {
|
||||
if let Some(swap) = cfg.swap {
|
||||
// sanity check this structure
|
||||
assert_eq!(core::mem::size_of::<SwapSourceHeader>(), 4096);
|
||||
|
||||
// setup the I/O pins
|
||||
let mut iox = Iox::new(utralib::generated::HW_IOX_BASE as *mut u32);
|
||||
// JQSPI1
|
||||
// SPIM_CLK_A[0]
|
||||
setup_port(
|
||||
&mut iox,
|
||||
IoxPort::PD,
|
||||
4,
|
||||
Some(IoxFunction::AF1),
|
||||
Some(IoxDir::Output),
|
||||
Some(IoxDriveStrength::Drive2mA),
|
||||
Some(IoxEnable::Disable),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
// SPIM_SD[0-3]_A[0]
|
||||
for i in 0..3 {
|
||||
setup_port(
|
||||
&mut iox,
|
||||
IoxPort::PD,
|
||||
i,
|
||||
Some(IoxFunction::AF1),
|
||||
None,
|
||||
Some(IoxDriveStrength::Drive2mA),
|
||||
Some(IoxEnable::Enable),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
// SPIM_CSN0_A[0]
|
||||
setup_port(
|
||||
&mut iox,
|
||||
IoxPort::PD,
|
||||
5,
|
||||
Some(IoxFunction::AF1),
|
||||
Some(IoxDir::Output),
|
||||
Some(IoxDriveStrength::Drive2mA),
|
||||
Some(IoxEnable::Enable),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
// SPIM_CSN0_A[1]
|
||||
setup_port(
|
||||
&mut iox,
|
||||
IoxPort::PD,
|
||||
6,
|
||||
Some(IoxFunction::AF1),
|
||||
Some(IoxDir::Output),
|
||||
Some(IoxDriveStrength::Drive2mA),
|
||||
Some(IoxEnable::Enable),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
/* // JPC7_13
|
||||
// SPIM_CLK_A[1]
|
||||
setup_port(
|
||||
&mut iox,
|
||||
IoxPort::PC,
|
||||
11,
|
||||
Some(IoxFunction::AF1),
|
||||
Some(IoxDir::Output),
|
||||
Some(IoxDriveStrength::Drive2mA),
|
||||
Some(IoxEnable::Disable),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
// SPIM_SD[0-3]_A[1]
|
||||
for i in 0..3 {
|
||||
setup_port(
|
||||
&mut iox,
|
||||
IoxPort::PC,
|
||||
i + 7,
|
||||
Some(IoxFunction::AF1),
|
||||
None,
|
||||
Some(IoxDriveStrength::Drive2mA),
|
||||
Some(IoxEnable::Enable),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
// SPIM_CSN0_A[0]
|
||||
setup_port(
|
||||
&mut iox,
|
||||
IoxPort::PC,
|
||||
12,
|
||||
Some(IoxFunction::AF1),
|
||||
Some(IoxDir::Output),
|
||||
Some(IoxDriveStrength::Drive2mA),
|
||||
Some(IoxEnable::Enable),
|
||||
None,
|
||||
None,
|
||||
); */
|
||||
|
||||
let mut udma_global = GlobalConfig::new(utralib::generated::HW_UDMA_CTRL_BASE as *mut u32);
|
||||
udma_global.clock_on(PeriphId::Spim0); // JQSPI1
|
||||
// udma_global.clock_on(PeriphId::Spim1); // JPC7_13
|
||||
|
||||
// safety: this is safe because clocks have been set up
|
||||
let mut flash_spim = unsafe {
|
||||
Spim::new_with_ifram(
|
||||
SpimChannel::Channel0,
|
||||
100_000_000,
|
||||
100_000_000,
|
||||
SpimClkPol::LeadingEdgeRise,
|
||||
SpimClkPha::CaptureOnLeading,
|
||||
SpimCs::Cs0,
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
0, // we will never write to flash
|
||||
4096,
|
||||
Some(8),
|
||||
IframRange::from_raw_parts(SPIM_FLASH_IFRAM_ADDR, SPIM_FLASH_IFRAM_ADDR, 4096 * 2),
|
||||
)
|
||||
};
|
||||
|
||||
let mut ram_spim = unsafe {
|
||||
Spim::new_with_ifram(
|
||||
SpimChannel::Channel0,
|
||||
100_000_000,
|
||||
100_000_000,
|
||||
SpimClkPol::LeadingEdgeRise,
|
||||
SpimClkPha::CaptureOnLeading,
|
||||
SpimCs::Cs1,
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
1024, // this is limited by the page length
|
||||
1024,
|
||||
Some(6),
|
||||
IframRange::from_raw_parts(SPIM_RAM_IFRAM_ADDR, SPIM_RAM_IFRAM_ADDR, 4096 * 2),
|
||||
)
|
||||
};
|
||||
// sanity check: read ID
|
||||
println!("flash ID: {:x}", flash_spim.mem_read_id());
|
||||
println!("ram ID: {:x}", ram_spim.mem_read_id());
|
||||
|
||||
// setup FLASH
|
||||
// - QE enable
|
||||
// - dummy cycles = 8
|
||||
flash_spim.mem_write_status_register(0b01_0000_00, 0b10_00_0_111);
|
||||
|
||||
// set SPI devices to QPI mode
|
||||
// We expect a MX25L12833F (3.3V) on CS0
|
||||
// We expect a ISS66WVS4M8BLL (3.3V) on CS1
|
||||
// Both support QPI.
|
||||
flash_spim.mem_qpi_mode(true);
|
||||
ram_spim.mem_qpi_mode(true);
|
||||
|
||||
// allocate the buf
|
||||
let mut buf = RawPage { data: [0u8; 4096] };
|
||||
// fetch the header
|
||||
flash_spim.mem_read(SWAP_IMG_START as u32, &mut buf.data);
|
||||
|
||||
// safety: buf.data is aligned to 4096-byte boundary and filled with initialized data
|
||||
let ssh: &SwapSourceHeader = unsafe { &*(buf.data.as_ptr() as *const &SwapSourceHeader) };
|
||||
let mut hal = SwapHal {
|
||||
image_start: SWAP_IMG_START as usize + 4096,
|
||||
image_mac_start: SWAP_IMG_START as usize + 4096 + ssh.mac_offset as usize,
|
||||
partial_nonce: [0u8; 8],
|
||||
aad_storage: [0u8; 64],
|
||||
aad_len: 0,
|
||||
cipher: Aes256GcmSiv::new((&swap.key).into()),
|
||||
flash_spim,
|
||||
ram_spim,
|
||||
iox,
|
||||
udma_global,
|
||||
buf,
|
||||
};
|
||||
hal.aad_storage[..ssh.aad_len as usize].copy_from_slice(&ssh.aad[..ssh.aad_len as usize]);
|
||||
hal.aad_len = ssh.aad_len as usize;
|
||||
hal.partial_nonce.copy_from_slice(&ssh.parital_nonce);
|
||||
Some(hal)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn aad(&self) -> &[u8] { &self.aad_storage[..self.aad_len] }
|
||||
|
||||
pub fn decrypt_page_at(&mut self, offset: usize) -> &[u8] {
|
||||
assert!((offset & 0xFFF) == 0, "offset is not page-aligned");
|
||||
self.flash_spim.mem_read((self.image_start + offset) as u32, &mut self.buf.data);
|
||||
let mut nonce = [0u8; size_of::<Nonce>()];
|
||||
nonce[..4].copy_from_slice(&(offset as u32).to_be_bytes());
|
||||
nonce[4..].copy_from_slice(&self.partial_nonce);
|
||||
let mut tag = [0u8; size_of::<Tag>()];
|
||||
// avoid mutable borrow problem by copying AAD to a dedicated location:
|
||||
// we could do this with a Refcell but I suspect this is probably actually
|
||||
// cheaper than the Refcell bookkeeping.
|
||||
let mut aad = [0u8; 64];
|
||||
aad[..self.aad_len].copy_from_slice(self.aad());
|
||||
self.flash_spim
|
||||
.mem_read((self.image_mac_start + (offset / 4096) * size_of::<Tag>()) as u32, &mut tag);
|
||||
match self.cipher.decrypt_in_place_detached(
|
||||
Nonce::from_slice(&nonce),
|
||||
&aad[..self.aad_len],
|
||||
&mut self.buf.data,
|
||||
(&tag).into(),
|
||||
) {
|
||||
Ok(_) => &self.buf.data,
|
||||
Err(e) => panic!("Decryption error in swap: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,8 @@
|
|||
#[cfg(feature = "swap")]
|
||||
pub mod swap;
|
||||
#[cfg(feature = "swap")]
|
||||
pub use swap::*;
|
||||
|
||||
pub const RAM_SIZE: usize = utralib::generated::HW_SRAM_EXT_MEM_LEN;
|
||||
pub const RAM_BASE: usize = utralib::generated::HW_SRAM_EXT_MEM;
|
||||
|
||||
|
|
|
|||
68
loader/src/platform/precursor/swap.rs
Normal file
68
loader/src/platform/precursor/swap.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
use core::mem::size_of;
|
||||
|
||||
use aes_gcm_siv::{AeadInPlace, Aes256GcmSiv, KeyInit, Nonce, Tag};
|
||||
|
||||
use crate::bootconfig::BootConfig;
|
||||
use crate::swap::*;
|
||||
|
||||
pub struct SwapHal {
|
||||
data_area: &'static [u8],
|
||||
mac_area: &'static [u8],
|
||||
partial_nonce: [u8; 8],
|
||||
aad: &'static [u8],
|
||||
cipher: Aes256GcmSiv,
|
||||
buf: RawPage,
|
||||
}
|
||||
|
||||
impl SwapHal {
|
||||
pub fn new(cfg: &BootConfig) -> Option<SwapHal> {
|
||||
if let Some(swap) = cfg.swap {
|
||||
// sanity check this structure
|
||||
assert_eq!(core::mem::size_of::<SwapSourceHeader>(), 4096);
|
||||
// safety: the swap source header is guaranteed to be aligned and initialized in memory
|
||||
// by the image creator.
|
||||
let ssh: &SwapSourceHeader = unsafe { &*(swap.flash_offset as *const &SwapSourceHeader) };
|
||||
let swap_len = ssh.mac_offset as usize - (swap.flash_offset as usize + 4096);
|
||||
let mut hal = SwapHal {
|
||||
// safety: the swap raw array is guaranteed to be correctly aligned by the image maker
|
||||
data_area: unsafe {
|
||||
core::slice::from_raw_parts((swap.flash_offset as usize + 4096) as *const u8, swap_len)
|
||||
},
|
||||
// safety: the mac raw array is guaranteed to be correctly aligned by the image maker
|
||||
mac_area: unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
ssh.mac_offset as *const u8,
|
||||
(swap_len / 4096) * size_of::<Tag>(),
|
||||
)
|
||||
},
|
||||
partial_nonce: [0u8; 8],
|
||||
aad: &ssh.aad[..ssh.aad_len as usize],
|
||||
cipher: Aes256GcmSiv::new((&swap.key).into()),
|
||||
buf: RawPage { data: [0u8; 4096] },
|
||||
};
|
||||
hal.partial_nonce.copy_from_slice(&ssh.parital_nonce);
|
||||
Some(hal)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt_page_at(&mut self, offset: usize) -> &[u8] {
|
||||
assert!((offset & 0xFFF) == 0, "offset is not page-aligned");
|
||||
self.buf.data.copy_from_slice(&self.data_area[offset..offset + 4096]);
|
||||
let mut nonce = [0u8; size_of::<Nonce>()];
|
||||
nonce[..4].copy_from_slice(&(offset as u32).to_be_bytes());
|
||||
nonce[4..].copy_from_slice(&self.partial_nonce);
|
||||
match self.cipher.decrypt_in_place_detached(
|
||||
Nonce::from_slice(&nonce),
|
||||
self.aad,
|
||||
&mut self.buf.data,
|
||||
(&self.mac_area
|
||||
[(offset / 4096) * size_of::<Tag>()..(offset / 4096) * size_of::<Tag>() + size_of::<Tag>()])
|
||||
.into(),
|
||||
) {
|
||||
Ok(_) => &self.buf.data,
|
||||
Err(e) => panic!("Decryption error in swap: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue