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.
This commit is contained in:
bunnie 2024-05-13 14:03:00 +08:00
parent 9b89bde46a
commit a94dce11f7
4 changed files with 38 additions and 8 deletions

View file

@ -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 =

View file

@ -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::<XousAlloc>();
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();

View file

@ -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>()];
nonce[0..4].copy_from_slice(&[0u8; 4]); // this is the `swap_count` field

View file

@ -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<core::cmp::Ordering> { 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) }
}