make susres page ownership not hard coded; mark PTs as wired

also marks the ProcessImpl page as wired too
This commit is contained in:
bunnie 2024-05-15 02:31:40 +08:00
parent ad9ef3dedc
commit f66debdd01
5 changed files with 60 additions and 9 deletions

View file

@ -206,6 +206,15 @@ impl BootConfig {
panic!("Tried to change region {:08x} that isn't in defined memory!", addr);
}
#[cfg(feature = "swap")]
pub fn mark_as_wired(&mut self, paddr: usize) {
if paddr >= self.sram_start as usize && paddr < self.sram_start as usize + self.sram_size {
self.runtime_page_tracker[(paddr - self.sram_start as usize) / PAGE_SIZE].set_wired();
} else {
panic!("Tried to wire address {:08x} that isn't in main RAM!", paddr);
}
}
/// Map the given page to the specified process table. If necessary,
/// allocate a new page.
///
@ -355,6 +364,8 @@ impl BootConfig {
FLG_R | FLG_W | FLG_VALID,
owner,
);
#[cfg(feature = "swap")]
self.mark_as_wired(addr.get()); // page table entries should never be swapped.
if VDBG {
println!("<<< Done mapping new address");
}

View file

@ -716,7 +716,7 @@ fn copy_processes(cfg: &mut BootConfig) {
// the section load address.
last_copy_vaddr = dst_page_vaddr;
if SDBG {
if SDBG && VVDBG {
println!("Looping to the next section (swap)");
println!(
" swap_free_page: {:x}, dst_page_vaddr: {:x}, src_swap_img_addr: {:x}",

View file

@ -271,10 +271,13 @@ pub fn phase_2(cfg: &mut BootConfig, fs_prehash: &[u8; 64]) {
{
let swap_size_usable = crate::swap::derive_usable_swap(swap_spec.swap_len as usize);
let mut swap_count_start = 0;
for offset in (0..(swap_size_usable / PAGE_SIZE) * core::mem::size_of::<u32>()).step_by(4096) {
for offset in
(0..(swap_size_usable / PAGE_SIZE) * core::mem::size_of::<u32>()).step_by(4096).rev()
{
let count_page = cfg.alloc() as usize; // this also zeroes the page
// we want the start page to keep refreshing, because allocations grow *down*, so the
// last iteration actually contains the base pointer of the count tracker
// last iteration actually contains the base pointer of the count tracker (due to the .rev()
// on the iterator)
swap_count_start = count_page;
cfg.map_page(
root,
@ -290,6 +293,7 @@ pub fn phase_2(cfg: &mut BootConfig, fs_prehash: &[u8; 64]) {
let counts: &mut [u32] = unsafe {
core::slice::from_raw_parts_mut(swap_count_start as *mut u32, swap_size_usable / PAGE_SIZE)
};
println!("Claiming 0x{:x} swap pages as used", cfg.last_swap_page);
for i in 0..cfg.last_swap_page {
counts[i] = loader::FLG_SWAP_USED;
}
@ -317,11 +321,32 @@ pub fn phase_2(cfg: &mut BootConfig, fs_prehash: &[u8; 64]) {
println!();
}
}
// Mark pages used by suspend/resume, otherwise they will be handed out to userspace.
// However, when not doing suspend/resume, it's safe to hand this out because it's always zeroized
// before use and never re-used on a resume cycle.
#[cfg(feature = "resume")]
{
// Mark all of stack as owned by the kernel, because this region contains the backup arguments.
// tampering in userspace of the loader stack prior to a resume can be a potent attack vector.
let rtp_len = cfg.runtime_page_tracker.len();
for page in cfg.runtime_page_tracker[1 + rtp_len - GUARD_MEMORY_BYTES / PAGE_SIZE..].iter_mut() {
*page = XousAlloc::from(1);
}
// allow susres to claim the suspend/resume marker, assumed to be at the limit of the guard memory
cfg.runtime_page_tracker[rtp_len - GUARD_MEMORY_BYTES / PAGE_SIZE] = XousAlloc::from(0);
}
println!("Runtime Page Tracker: {} bytes", cfg.runtime_page_tracker.len());
// mark pages used by suspend/resume according to their needs
cfg.runtime_page_tracker[cfg.sram_size / PAGE_SIZE - 1] = XousAlloc::from(1); // claim the loader stack -- do not allow tampering, as it contains backup kernel args
cfg.runtime_page_tracker[cfg.sram_size / PAGE_SIZE - 2] = XousAlloc::from(1); // 8k in total (to allow for digital signatures to be computed)
cfg.runtime_page_tracker[cfg.sram_size / PAGE_SIZE - 3] = XousAlloc::from(0); // allow clean suspend page to be mapped in Xous
#[cfg(feature = "swap")]
if SDBG {
println!("Occupied RPT entries:");
for (i, entry) in cfg.runtime_page_tracker.iter().enumerate() {
if entry.raw_vpn() != 0 {
println!(" {:x}: {:x} [{}]", i, entry.raw_vpn(), entry.timestamp());
}
}
}
}
/// This describes the kernel as well as initially-loaded processes
@ -402,6 +427,8 @@ impl ProgramDescription {
FLG_R | FLG_W | FLG_VALID,
pid as XousPid,
);
#[cfg(feature = "swap")]
allocator.mark_as_wired(satp_address); // don't allow the root PT to be swapped in any process
// Allocate context for this process
let thread_address = allocator.alloc() as usize;

View file

@ -85,6 +85,8 @@ impl BootConfig {
let mut num_alloc_pages = 0;
for _ in 0..4 {
let mut allocated_page_ptr = self.alloc();
#[cfg(feature = "swap")]
self.mark_as_wired(allocated_page_ptr);
num_alloc_pages += 1;
let is_aligned = allocated_page_ptr as usize & (ALIGNMENT_16K - 1) == 0;
self.change_owner(pid, allocated_page_ptr as usize);
@ -104,6 +106,8 @@ impl BootConfig {
pid
);
allocated_page_ptr = self.alloc();
#[cfg(feature = "swap")]
self.mark_as_wired(allocated_page_ptr);
self.change_owner(pid, allocated_page_ptr as usize);
}
@ -207,6 +211,8 @@ impl BootConfig {
dprintln!("Previously unmapped L1 entry");
let na = self.alloc();
#[cfg(feature = "swap")]
self.mark_as_wired(na);
let phys = PhysicalAddress::from_ptr(na);
let entry_flags =
u32::from(PAGE_TABLE_FLAGS::VALID::Enable) | u32::from(PAGE_TABLE_FLAGS::DOMAIN.val(0xf));

View file

@ -134,17 +134,24 @@ impl SwapAlloc {
| if (pid == 1) || (pid == SWAPPER_PID) { SWAP_FLG_WIRED } else { 0 };
}
/// Sets the wired bit. Used for marking page table elements as unswappable.
pub fn set_wired(&mut self) { self.vpn |= SWAP_FLG_WIRED; }
/// This is a slight abuse of the naming system to provide us cross-compatibility with the case where the
/// structure is defined as an overload of the `u8` type
pub fn to_le(&self) -> u8 { self.vpn as u8 }
pub fn is_wired(&self) -> bool { self.vpn & SWAP_FLG_WIRED != 0 }
pub fn is_wired(&self) -> bool { (self.vpn & SWAP_FLG_WIRED) != 0 }
pub fn is_valid(&self) -> bool { self.timestamp != 0 || self.vpn != 0 }
pub fn is_valid(&self) -> bool { self.vpn != 0 }
pub fn raw_pid(&self) -> u8 { self.vpn as u8 }
pub fn vaddr(&self) -> usize { (self.vpn & !0xFFFu32) as usize }
pub fn raw_vpn(&self) -> u32 { self.vpn }
pub fn timestamp(&self) -> u32 { self.timestamp }
}
impl fmt::Debug for SwapAlloc {