Skip to content

Commit 90769df

Browse files
authored
Merge pull request #645 from betrusted-io/pddb-baosec-bringup
Pddb baosec bringup
2 parents 9386952 + d4a713b commit 90769df

File tree

29 files changed

+616
-658
lines changed

29 files changed

+616
-658
lines changed

Cargo.lock

+3-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kernel/src/arch/riscv/mem.rs

+6
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ fn translate_flags(req_flags: MemoryFlags) -> MMUFlags {
6565
if req_flags & xous_kernel::MemoryFlags::X == xous_kernel::MemoryFlags::X {
6666
flags |= MMUFlags::X;
6767
}
68+
if req_flags & xous_kernel::MemoryFlags::P == xous_kernel::MemoryFlags::P {
69+
flags |= MMUFlags::P;
70+
}
6871
flags
6972
}
7073

@@ -80,6 +83,9 @@ fn untranslate_flags(req_flags: usize) -> MemoryFlags {
8083
if req_flags & MMUFlags::X == MMUFlags::X {
8184
flags |= xous_kernel::MemoryFlags::X;
8285
}
86+
if req_flags & MMUFlags::P == MMUFlags::P {
87+
flags |= xous_kernel::MemoryFlags::P;
88+
}
8389
flags
8490
}
8591

kernel/src/mem.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use core::fmt;
66
use xous_kernel::{MemoryFlags, MemoryRange, PID, arch::*};
77

88
pub use crate::arch::mem::MemoryMapping;
9-
use crate::arch::process::Process;
9+
use crate::arch::{
10+
mem::{MMUFlags, flush_mmu, pagetable_entry},
11+
process::Process,
12+
};
1013
#[cfg(feature = "swap")]
1114
use crate::swap::SwapAlloc;
1215

@@ -628,13 +631,17 @@ impl MemoryManager {
628631
// round up to the nearest page boundary
629632
let end = (virt_ptr as usize + size + PAGE_SIZE - 1) & !(PAGE_SIZE - 1);
630633
for virt in (start..end).step_by(PAGE_SIZE) {
631-
// read/write is provisionally allowed - this allows us to cache writeable
632-
// data using the swap mechanism and only do built write-outs when the page is
633-
// retired. However this is somewhat dangerous because it means we could lose
634-
// data on power-down or if we screw up the tracking of dirty pages (dirty bit is
635-
// not automatically set on write/update). Valid is not set, because it's not
634+
// Pages are read-only. Writes take a special call to ensure atomicity of write
635+
// updates (and subsequent page unmap). Valid is not set, because it's not
636636
// wired into memory, and "P" (swap) is set to indicate this is a swapper managed page.
637-
mm.reserve_address(self, virt, MemoryFlags::R | MemoryFlags::W | MemoryFlags::P)?;
637+
mm.reserve_address(self, virt, MemoryFlags::R | MemoryFlags::P)?;
638+
639+
// now mark the page as USER
640+
let pte = pagetable_entry(virt)?;
641+
unsafe {
642+
pte.write_volatile(pte.read_volatile() | MMUFlags::USER.bits());
643+
flush_mmu();
644+
}
638645
}
639646
// note that the region returned is snapped to the nearest page boundary, even if
640647
// the use called us with unaligned addresses.

kernel/src/swap.rs

+69-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
use core::cmp::Ordering;
55

6+
use loader::SWAP_FLG_WIRED;
67
use xous_kernel::SWAPPER_PID;
78
use xous_kernel::arch::EXCEPTION_STACK_TOP;
9+
use xous_kernel::arch::MMAP_VIRT_BASE;
810
use xous_kernel::arch::PAGE_SIZE;
9-
use xous_kernel::arch::SWAP_FLG_WIRED;
1011
use xous_kernel::arch::SWAP_RPT_VADDR;
1112
use xous_kernel::{PID, SysCallResult, TID};
1213

@@ -39,6 +40,7 @@ pub enum SwapAbi {
3940
HardOom = 4,
4041
StealPage = 5,
4142
ReleaseMemory = 6,
43+
WritePage = 7,
4244
}
4345
/// SYNC WITH `xous-swapper/src/main.rs`
4446
impl SwapAbi {
@@ -51,6 +53,7 @@ impl SwapAbi {
5153
4 => HardOom,
5254
5 => StealPage,
5355
6 => ReleaseMemory,
56+
7 => WritePage,
5457
_ => Invalid,
5558
}
5659
}
@@ -64,6 +67,9 @@ pub enum BlockingSwapOp {
6467
/// PID of the target block, current paddr of block, original vaddr in the space of target block PID,
6568
/// physical address of block. Returns to PID of the target block.
6669
ReadFromSwap(PID, TID, usize, usize, usize),
70+
/// PID of the target block, current paddr of block, original vaddr in the space of target block PID,
71+
/// physical address of block. Returns to PID of the target block.
72+
WriteToFlash(PID, TID, PID, usize, usize),
6773
/// Immediate OOM. Drop everything and try to recover; from here until exit, everything runs in
6874
/// an un-interruptable context, no progress allowed. This currently can only originate from one
6975
/// location, if we need multi-location origin then we have to also track the re-entry point in the
@@ -644,7 +650,7 @@ impl Swap {
644650
/// evict_page)
645651
///
646652
/// This call diverges into the userspace swapper.
647-
/// Divergent calls must turn of IRQs before memory spaces are changed.
653+
/// Divergent calls must turn off IRQs before memory spaces are changed.
648654
pub fn retrieve_page_syscall(&mut self, target_vaddr_in_pid: usize, paddr: usize) -> ! {
649655
let target_pid = crate::arch::process::current_pid();
650656
let target_tid = crate::arch::process::current_tid();
@@ -670,6 +676,34 @@ impl Swap {
670676
}
671677
}
672678

679+
pub fn write_page_syscall(
680+
&mut self,
681+
src_pid: PID,
682+
flash_offset: usize,
683+
page_vaddr_in_swapper: usize,
684+
) -> ! {
685+
let target_pid = crate::arch::process::current_pid();
686+
let target_tid = crate::arch::process::current_tid();
687+
688+
#[cfg(feature = "debug-swap-verbose")]
689+
println!(
690+
"write_page - userspace activate for pid{:?}/tid{:?} for vaddr {:x?} -> offset {:x?}",
691+
target_pid, target_tid, page_vaddr_in_swapper, flash_offset
692+
);
693+
// prevent context switching to avoid re-entrant calls while handling a call
694+
self.swap_stop_irq();
695+
// this is safe because the syscall pre-amble checks that we're in the swapper context
696+
unsafe {
697+
self.blocking_activate_swapper(BlockingSwapOp::WriteToFlash(
698+
target_pid,
699+
target_tid,
700+
src_pid,
701+
page_vaddr_in_swapper,
702+
flash_offset,
703+
));
704+
}
705+
}
706+
673707
/// Safety:
674708
/// - the current page table mapping context must be PID 2 (the swapper's PID) for this to work
675709
/// - interrupts must have been disabled prior to setting the context to PID 2
@@ -685,6 +719,12 @@ impl Swap {
685719
self.swapper_args[3] = vaddr_in_pid;
686720
self.swapper_args[4] = vaddr_in_swap;
687721
}
722+
BlockingSwapOp::WriteToFlash(_pid, _tid, _src_pid, vaddr_in_swap, flash_offset) => {
723+
self.swapper_args[0] = self.swapper_state;
724+
self.swapper_args[1] = 4; // WriteToFlash
725+
self.swapper_args[2] = vaddr_in_swap;
726+
self.swapper_args[3] = flash_offset;
727+
}
688728
BlockingSwapOp::HardOomSyscall(_tid, _pid) => {
689729
self.swapper_args[0] = self.swapper_state;
690730
self.swapper_args[1] = 3; // HardOom
@@ -751,6 +791,33 @@ impl Swap {
751791
});
752792
(pid, tid)
753793
}
794+
// Called from any process. Clear the dirty bit on the RPT when exiting. No pages are unmapped
795+
// by this routine, that would be handled by the OOMer, if at all.
796+
Some(BlockingSwapOp::WriteToFlash(pid, tid, src_pid, _vpage_addr_in_swapper, flash_offset)) => {
797+
// this works because the V:P mapping for the flash memory is 1:1 for the LSBs
798+
let flash_vaddr = MMAP_VIRT_BASE + flash_offset;
799+
// evict_page_inner marks the page as swapped/invalid in src_pid, but also maps the page
800+
// into the swapper's address space
801+
let swap_vaddr = crate::arch::mem::evict_page_inner(src_pid, flash_vaddr).unwrap();
802+
803+
// release the page from the swapper's address space
804+
MemoryManager::with_mut(|mm| {
805+
let paddr = crate::arch::mem::virt_to_phys(swap_vaddr).unwrap() as usize;
806+
#[cfg(feature = "debug-swap-verbose")]
807+
println!("Release flash backing page - paddr {:x}", paddr);
808+
// this call unmaps the virtual page from the page table
809+
crate::arch::mem::unmap_page_inner(mm, swap_vaddr).expect("couldn't unmap page");
810+
// This call releases the physical page from the RPT - the pid has to match that of
811+
// the original owner. This is the "pointy end" of the stick;
812+
// after this call, the memory is now back into the free pool.
813+
mm.release_page_swap(paddr as *mut usize, src_pid)
814+
.expect("couldn't free page that was swapped out");
815+
});
816+
817+
// Unhalt IRQs
818+
self.swap_restore_irq();
819+
(pid, tid)
820+
}
754821
Some(BlockingSwapOp::HardOomSyscall(tid, pid)) => {
755822
// We enter this from the swapper's memory space
756823
assert!(

kernel/src/syscall.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,20 @@ pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallR
11141114
Err(xous_kernel::Error::AccessDenied)
11151115
}
11161116
}
1117+
SwapAbi::WritePage => {
1118+
if pid.get() != xous_kernel::SWAPPER_PID {
1119+
return Err(xous_kernel::Error::AccessDenied);
1120+
}
1121+
let src_pid = PID::new(a1 as u8).unwrap();
1122+
// strip off the virtual addres prefix: by definition this region is 1:1 mapped in the
1123+
// LSBs
1124+
let flash_offset = a2 & 0x0FFF_FFFF;
1125+
let page_vaddr_in_swapper = a3;
1126+
Swap::with_mut(|swap| {
1127+
swap.write_page_syscall(src_pid, flash_offset, page_vaddr_in_swapper);
1128+
});
1129+
Ok(xous_kernel::Result::Ok)
1130+
}
11171131
SwapAbi::Invalid => {
11181132
println!(
11191133
"Invalid SwapOp: {:x} {:x} {:x} {:x} {:x} {:x} {:x}",

libs/cramium-hal/src/board/baosec.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ pub const APP_UART_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRA
3030
// display buffer: 1 page for double-buffering, rounded up to 1 page for commands
3131
pub const DISPLAY_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 5 * 4096;
3232

33-
// Flash needs 4096 bytes for Rx, and 0 bytes for Tx + 16 bytes for cmd for 2 pages total. This is released
34-
// after boot.
33+
// Flash needs 4096 bytes for Rx, and 0 or 256 bytes for Tx + 16 bytes for cmd for 2 pages total.
3534
pub const SPIM_FLASH_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 7 * 4096;
3635

3736
// one page for the I2C driver

libs/cramium-hal/src/udma/spim.rs

+21-21
Original file line numberDiff line numberDiff line change
@@ -584,8 +584,8 @@ impl Spim {
584584
// last iteration falls through without waiting...
585585
if words_sent < total_words {
586586
while self.udma_busy(Bank::Tx) {
587-
#[cfg(feature = "std")]
588-
xous::yield_slice();
587+
// #[cfg(feature = "std")]
588+
// xous::yield_slice();
589589
}
590590
}
591591
}
@@ -842,8 +842,8 @@ impl Spim {
842842
let cmd_list = [SpimCmd::SendCmd(self.mode, 8, cmd as u16)];
843843
self.send_cmd_list(&cmd_list);
844844
while self.udma_busy(Bank::Custom) {
845-
#[cfg(feature = "std")]
846-
xous::yield_slice();
845+
// #[cfg(feature = "std")]
846+
// xous::yield_slice();
847847
}
848848
}
849849

@@ -868,8 +868,8 @@ impl Spim {
868868
};
869869
self.send_cmd_list(&cmd_list);
870870
while self.udma_busy(Bank::Rx) {
871-
#[cfg(feature = "std")]
872-
xous::yield_slice();
871+
// #[cfg(feature = "std")]
872+
// xous::yield_slice();
873873
}
874874

875875
let ret = u32::from_le_bytes([self.rx_buf()[0], self.rx_buf()[1], self.rx_buf()[2], 0x0]);
@@ -899,8 +899,8 @@ impl Spim {
899899
};
900900
self.send_cmd_list(&cmd_list);
901901
while self.udma_busy(Bank::Rx) {
902-
#[cfg(feature = "std")]
903-
xous::yield_slice();
902+
// #[cfg(feature = "std")]
903+
// xous::yield_slice();
904904
}
905905

906906
let ret =
@@ -947,8 +947,8 @@ impl Spim {
947947
self.send_cmd_list(&cmd_list);
948948

949949
while self.udma_busy(Bank::Tx) {
950-
#[cfg(feature = "std")]
951-
xous::yield_slice();
950+
// #[cfg(feature = "std")]
951+
// xous::yield_slice();
952952
}
953953
self.mem_cs(false);
954954
}
@@ -1140,8 +1140,8 @@ impl Spim {
11401140
};
11411141
self.send_cmd_list(&cmd_list);
11421142
while self.udma_busy(Bank::Rx) {
1143-
#[cfg(feature = "std")]
1144-
xous::yield_slice();
1143+
// #[cfg(feature = "std")]
1144+
// xous::yield_slice();
11451145
}
11461146
let ret = self.rx_buf()[0];
11471147

@@ -1163,8 +1163,8 @@ impl Spim {
11631163
};
11641164
self.send_cmd_list(&cmd_list);
11651165
while self.udma_busy(Bank::Rx) {
1166-
#[cfg(feature = "std")]
1167-
xous::yield_slice();
1166+
// #[cfg(feature = "std")]
1167+
// xous::yield_slice();
11681168
}
11691169
let ret = self.rx_buf()[0];
11701170

@@ -1183,8 +1183,8 @@ impl Spim {
11831183
self.send_cmd_list(&cmd_list);
11841184

11851185
while self.udma_busy(Bank::Tx) {
1186-
#[cfg(feature = "std")]
1187-
xous::yield_slice();
1186+
// #[cfg(feature = "std")]
1187+
// xous::yield_slice();
11881188
}
11891189
self.mem_cs(false);
11901190
}
@@ -1237,8 +1237,8 @@ impl Spim {
12371237
self.send_cmd_list(&cmd_list);
12381238

12391239
while self.udma_busy(Bank::Tx) {
1240-
#[cfg(feature = "std")]
1241-
xous::yield_slice();
1240+
// #[cfg(feature = "std")]
1241+
// xous::yield_slice();
12421242
}
12431243
self.mem_cs(false);
12441244
}
@@ -1290,7 +1290,7 @@ impl Spim {
12901290
true
12911291
}
12921292

1293-
/// This routine can data that is strictly a multiple of a page length (256 bytes)
1293+
/// This routine can write data that is strictly a multiple of a page length (256 bytes)
12941294
pub fn mem_flash_write_page(&mut self, addr: u32, buf: &[u8; FLASH_PAGE_LEN]) -> bool {
12951295
// crate::println!("write_page: {:x}, {:x?}", addr, &buf[..8]);
12961296
// enable writes: set wren mode
@@ -1321,8 +1321,8 @@ impl Spim {
13211321
self.send_cmd_list(&cmd_list);
13221322

13231323
while self.udma_busy(Bank::Tx) {
1324-
#[cfg(feature = "std")]
1325-
xous::yield_slice();
1324+
// #[cfg(feature = "std")]
1325+
// xous::yield_slice();
13261326
}
13271327
self.mem_cs(false);
13281328

loader/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ pub const FLG_D: usize = 0x80;
2222
pub const FLG_P: usize = 0x200;
2323

2424
pub const SWAP_FLG_WIRED: u32 = 0x1_00;
25+
// Note: this flag is currently not used. It was an aborted attempt to do
26+
// auto-write on dirty page but due to lack of hw synchronization we couldn't
27+
// guarantee atomicity. Flag can be removed or re-used in the future if another
28+
// attempt is tried on a system that has hardware dirty page updating.
29+
pub const SWAP_FLG_DIRTY: u32 = 0x2_00;
2530
pub const FLG_SWAP_USED: u32 = 0x8000_0000;
2631

2732
// Locate the hard-wired IFRAM allocations for UDMA

loader/src/main.rs

+3
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ fn clear_ram(cfg: &mut BootConfig) {
512512
// stay there forever, if not explicitly cleared. This clear adds a couple seconds
513513
// to a cold boot, but it's probably worth it. Note that it doesn't happen on a suspend/resume.
514514
let ram: *mut u32 = cfg.sram_start as *mut u32;
515+
#[cfg(feature = "swap")]
516+
let clear_limit = ((2 * 4096 + core::mem::size_of::<BootConfig>()) + 4095) & !4095;
517+
#[cfg(not(feature = "swap"))]
515518
let clear_limit = ((4096 + core::mem::size_of::<BootConfig>()) + 4095) & !4095;
516519
if VDBG {
517520
println!("Stack clearing limit: {:x}", clear_limit);

0 commit comments

Comments
 (0)