From a94dce11f7e8c82bfb1eb90d3392aa92ff77600d Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 13 May 2024 14:03:00 +0800 Subject: [PATCH] add loader support for rpt tracking/mapping trying to condense most of the RPT API into the loader so that the userspace can use a single dependency for this. We can't condense the kernel API into the loader unfortunately, because the kernel actually uses a different type for representing a process. This is probably a mistake, and is something that may be fixed later so we can merge the representations. --- loader/src/main.rs | 1 + loader/src/phase2.rs | 8 +++++-- loader/src/platform/precursor/swap.rs | 4 ++-- loader/src/swap.rs | 33 +++++++++++++++++++++++---- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/loader/src/main.rs b/loader/src/main.rs index 9d279d463..de5ab0e69 100644 --- a/loader/src/main.rs +++ b/loader/src/main.rs @@ -234,6 +234,7 @@ fn boot_sequence(args: KernelArguments, _signature: u32, fs_prehash: [u8; 64]) - "RPT looks corrupted, suspect stack overflow in loader. Increase GUARD_MEMORY_BYTES!" ); } + // compute the virtual addresses of all of these "manually" let arg_offset = cfg.args.base as usize - krn_struct_start + KERNEL_ARGUMENT_OFFSET; let ip_offset = cfg.processes.as_ptr() as usize - krn_struct_start + KERNEL_ARGUMENT_OFFSET; let rpt_offset = diff --git a/loader/src/phase2.rs b/loader/src/phase2.rs index 799968de2..ae402cef3 100644 --- a/loader/src/phase2.rs +++ b/loader/src/phase2.rs @@ -254,8 +254,12 @@ pub fn phase_2(cfg: &mut BootConfig, fs_prehash: &[u8; 64]) { if let Some(desc) = cfg.swap { swap_spec.key.copy_from_slice(&cfg.swap_hal.as_ref().unwrap().get_swap_key()); swap_spec.pid_count = cfg.init_process_count as u32 + 1; - // we only track main ram area (which is also the only swappable memory) to save space - swap_spec.rpt_len_bytes = (cfg.sram_size / 4096) as u32; + // duplicated code from loader/src/phase1.rs/allocate_regions() + let rpt_pages = cfg.sram_size / PAGE_SIZE; + let proposed_alloc = rpt_pages * mem::size_of::(); + let page_aligned_alloc = (proposed_alloc + PAGE_SIZE - 1) & !(PAGE_SIZE - 1); + swap_spec.rpt_len_pages = (page_aligned_alloc / PAGE_SIZE) as u32; + swap_spec.rpt_base_phys = cfg.runtime_page_tracker.as_ptr() as usize as u32; swap_spec.swap_base = desc.ram_offset; swap_spec.swap_len = desc.ram_size; (swap_spec.mac_base, swap_spec.mac_len) = cfg.swap_hal.as_ref().unwrap().mac_base_bounds(); diff --git a/loader/src/platform/precursor/swap.rs b/loader/src/platform/precursor/swap.rs index 3a14339ab..b150d3fcc 100644 --- a/loader/src/platform/precursor/swap.rs +++ b/loader/src/platform/precursor/swap.rs @@ -169,8 +169,8 @@ impl SwapHal { /// Used to examine contents of swap RAM. Swap count is fixed at 0 by this routine. Decrypted data is /// returned as a slice. pub fn decrypt_swap_from(&mut self, src_offset: usize, dst_vaddr: usize, dst_pid: u8) -> &[u8] { - println!("Decrypt swap:"); - println!(" offset: {:x}, vaddr: {:x}, pid: {}", src_offset, dst_vaddr, dst_pid); + // println!("Decrypt swap:"); + // println!(" offset: {:x}, vaddr: {:x}, pid: {}", src_offset, dst_vaddr, dst_pid); assert!(src_offset & (PAGE_SIZE - 1) == 0); let mut nonce = [0u8; size_of::()]; nonce[0..4].copy_from_slice(&[0u8; 4]); // this is the `swap_count` field diff --git a/loader/src/swap.rs b/loader/src/swap.rs index cc32b6bb7..2b8455647 100644 --- a/loader/src/swap.rs +++ b/loader/src/swap.rs @@ -3,7 +3,6 @@ use core::mem::size_of; use aes_gcm_siv::Tag; -use crate::XousPid; use crate::PAGE_SIZE; use crate::SWAPPER_PID; @@ -67,7 +66,11 @@ pub struct SwapSpec { /// Count of PIDs in the system. Could be a u8, but, make it a u32 because we have /// the space and word alignment is good for stuff being tossed through unsafe pointers. pub pid_count: u32, - pub rpt_len_bytes: u32, + /// Physical address of the RPT base (the table for main RAM allocs) + pub rpt_base_phys: u32, + /// Length of the memory tracker mapping region in *pages*. This can correspond to a region + /// that is strictly larger than needed by the RPT. + pub rpt_len_pages: u32, /// Base address of swap memory. If swap is memory-mapped, this is a virtual address. /// If swap is device-mapped, it's the physical offset in the device. pub swap_base: u32, @@ -114,14 +117,14 @@ pub const SWAP_FLG_WIRED: u32 = 0x1_00; #[derive(Copy, Clone)] pub struct SwapAlloc { - _timestamp: u32, + timestamp: u32, /// virtual_page_number[19:0] | flags[3:0] | pid[7:0] vpn: u32, } impl SwapAlloc { /// Allocations in the loader all start out as "wired", with no virtual address for tracking. - pub fn from(pid: u8) -> SwapAlloc { SwapAlloc { _timestamp: 0, vpn: pid as u32 | SWAP_FLG_WIRED } } + pub fn from(pid: u8) -> SwapAlloc { SwapAlloc { timestamp: 0, vpn: pid as u32 | SWAP_FLG_WIRED } } /// As the page tables are laid in, we can update the tracker with the virtual address. If /// the page it belongs to the kernel or swapper, mark it as unswappable (WIRED) @@ -134,6 +137,10 @@ impl SwapAlloc { /// 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_valid(&self) -> bool { self.timestamp != 0 || self.vpn != 0 } } impl fmt::Debug for SwapAlloc { @@ -145,3 +152,21 @@ impl fmt::Debug for SwapAlloc { .finish() } } + +impl PartialEq for SwapAlloc { + fn eq(&self, other: &Self) -> bool { self.timestamp == other.timestamp } +} + +impl Eq for SwapAlloc {} + +impl PartialOrd for SwapAlloc { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } +} + +impl Ord for SwapAlloc { + // Note: the ordering will give us a min-heap (reversed from the "usual sense") + fn cmp(&self, other: &Self) -> core::cmp::Ordering { other.timestamp.cmp(&self.timestamp) } + + // Note: the ordering will give us a max-heap (keep comment around for debugging) + // fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.timestamp.cmp(&other.timestamp) } +}