From 1ad0961c87b678d218fb0caba575387f35f4492d Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 21 Jan 2020 17:04:09 +0800 Subject: [PATCH] mem: get memory mapping working, in theory Signed-off-by: Sean Cross --- src/main.rs | 11 ++++- src/mem.rs | 105 +++++++++++++++++++++++++++++++++++++++----- src/processtable.rs | 44 ++++++++++++++----- 3 files changed, 138 insertions(+), 22 deletions(-) diff --git a/src/main.rs b/src/main.rs index 194a593..318e132 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,9 @@ extern crate vexriscv; +#[macro_use] mod debug; + mod definitions; mod irq; mod macros; @@ -20,7 +22,9 @@ use vexriscv::register::{mcause, mie, mstatus, vmim, vmip}; use xous_kernel_riscv_rt::xous_kernel_entry; #[panic_handler] -fn handle_panic(_arg: &PanicInfo) -> ! { +fn handle_panic(arg: &PanicInfo) -> ! { + println!("PANIC!"); + println!("Details: {:?}", arg); loop {} } @@ -42,10 +46,13 @@ fn xous_main() -> ! { println!("Starting up..."); sys_interrupt_claim(2, debug::irq).unwrap(); + println!("Creating memory manager..."); let mut mm = MemoryManager::new(); + + println!("Creating process table..."); let mut _pt = ProcessTable::new(&mut mm); - + println!("Entering main loop"); loop { // unsafe { vexriscv::asm::wfi() }; } diff --git a/src/mem.rs b/src/mem.rs index 97e4345..b043cf4 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -1,4 +1,5 @@ use crate::definitions::{MemoryAddress, XousError, XousPid}; +use crate::processtable::Process; use crate::{print, println}; use core::num::NonZeroUsize; use vexriscv::register::mstatus; @@ -157,9 +158,9 @@ impl MemoryManager { pub fn alloc_page(&mut self, pid: XousPid) -> Result { // Go through all RAM pages looking for a free page. // Optimization: start from the previous address. - println!("Allocating page for PID {}", pid); + // println!("Allocating page for PID {}", pid); for index in 0..RAM_PAGE_COUNT { - println!(" Checking {:08x}...", index * PAGE_SIZE + RAM_START); + // println!(" Checking {:08x}...", index * PAGE_SIZE + RAM_START); if self.ram[index] == 0 { self.ram[index] = pid; let page_addr = (index * PAGE_SIZE + RAM_START) as *mut u32; @@ -170,22 +171,106 @@ impl MemoryManager { } } let new_page = unsafe { transmute::<*mut u32, usize>(page_addr) }; - println!(" Page {:08x} is free", new_page); + // println!(" Page {:08x} is free", new_page); return Ok(NonZeroUsize::new(new_page).unwrap()); } } Err(XousError::OutOfMemory) } - // /// Create an identity mapping, copying the kernel to itself - // pub fn create_identity(&mut self, pid: XousPid) -> Result<(), XousError> { - // let pt = unsafe { transmute::(satp) }; + /// Map the given page to the specified process table. If necessary, + /// allocate a new page. + /// + /// # Errors + /// + /// * OutOfMemory - Tried to allocate a new pagetable, but ran out of memory. + fn map_page( + &mut self, + root: &mut PageTable, + phys: usize, + virt: usize, + ) -> Result<(), XousError> { + let ppn1 = (phys >> 20) & ((1 << 12) - 1); + let ppn0 = (phys >> 10) & ((1 << 10) - 1); + let ppo = (phys >> 0) & ((1 << 12) - 1); + let vpn1 = (virt >> 22) & ((1 << 10) - 1); + let vpn0 = (virt >> 10) & ((1 << 10) - 1); + let vpo = (virt >> 0) & ((1 << 12) - 1); - // Err(XousError::OutOfMemory) - // } + println!( + "Mapping phys: {:08x} -> virt: {:08x} (vpn1: {:04x} vpn0: {:04x} ppn1: {:04x} ppn0: {:04x})", + phys, virt, vpn1, vpn0, ppn1, ppn0 + ); + assert!(ppn1 < 4096); + assert!(ppn0 < 1024); + assert!(ppo < 4096); + assert!(vpn1 < 1024); + assert!(vpn0 < 1024); + assert!(vpo < 4096); - fn map_page(&mut self, satp: &mut PageTable, pid: XousPid) -> Result<(), XousError> { - Err(XousError::OutOfMemory) + let ref mut l1_pt = root.entries; + println!("l1_pt is at {:p} ({:p})", &l1_pt, &l1_pt[vpn1]); + + // Allocate a new level 1 pagetable entry if one doesn't exist. + if l1_pt[vpn1] & 1 == 0 { + println!(" top-level VPN1 {:04x}: {:08x} (will allocate a new one)", vpn1, l1_pt[vpn1]); + // Allocate the page to the kernel (PID 1) + let new_addr = self.alloc_page(1)?.get(); + println!( + " Allocated new top-level page for VPN1 {:04x} in process @ {:08x}", + vpn1, new_addr + ); + + // Mark this entry as a leaf node (WRX as 0), and indicate + // it is a valid page by setting "V". + l1_pt[vpn1] = (((new_addr >> 10) & ((1 << 22) - 1)) << 10) | 1; + println!(" New top-level page entry: {:08x}", l1_pt[vpn1]); + } + + let mut l0_pt = unsafe { + let tmp = (l1_pt[vpn1] & ((1 << 10) - 1)) as *mut PageTable; + (*tmp).entries + }; + + // Allocate a new level 0 pagetable entry if one doesn't exist. + if l0_pt[vpn0] & 1 != 0 { + panic!("Page already allocated!"); + } + l0_pt[vpn0] = (ppn1 << 20) | (ppn0 << 10) | 1 | 0xe; + Ok(()) + } + + /// Create an identity mapping, copying the kernel to itself + pub fn create_identity(&mut self, process: &Process, pid: XousPid) -> Result<(), XousError> { + let root_page = (process.satp & ((1 << 22) - 1)) << 9; + let pt = unsafe { &mut (*(root_page as *mut PageTable)) }; + println!("SATP value: {:08x} Root page: {:08x} pt: {:p} pt: {:p}", process.satp, root_page, &pt, pt); + let flash_orig = self.flash.clone(); + for (flash_idx, flash_pid) in flash_orig.iter().enumerate() { + if *flash_pid == pid { + // println!( + // "Flash addr {:08x} owned by PID {}, mapping it as ident", + // flash_idx * PAGE_SIZE + FLASH_START, + // pid + // ); + self.map_page( + pt, + flash_idx * PAGE_SIZE + FLASH_START, + flash_idx * PAGE_SIZE + FLASH_START, + )?; + print!("Entries mapped: >"); + let mut i = 0; + for (entry_idx, entry) in pt.entries.iter().enumerate() { + i = i + 1; + if *entry != 0 { + print!(" {}:{:08x}", entry_idx, entry); + } + } + println!(" < ({})", i); + println!(""); + } + } + Ok(()) } /// Mark a given address as being owned by the specified process ID diff --git a/src/processtable.rs b/src/processtable.rs index b57de9b..3432ffd 100644 --- a/src/processtable.rs +++ b/src/processtable.rs @@ -1,16 +1,24 @@ -use crate::definitions::{XousError, XousPid, MemoryAddress}; +use crate::definitions::{MemoryAddress, XousError, XousPid}; use crate::mem::MemoryManager; -use crate::{filled_array, println, print}; +use crate::{filled_array, print, println}; +use vexriscv::register::{satp, mstatus}; const MAX_PROCESS_COUNT: usize = 256; -struct Process { - satp: Option, +pub struct Process { + pub satp: usize, } impl core::fmt::Debug for Process { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { - write!(fmt, "Process (satp: 0x{:08x})", match self.satp { Some(s) => s.get(), None => 0 }) + write!( + fmt, + "Process (satp: 0x{:08x}, mode: {}, ASID: {}, PPN: {:08x})", + self.satp, + self.satp >> 31, + self.satp >> 22 & ((1 << 9) - 1), + (self.satp >> 0 & ((1 << 22) - 1)) << 9, + ) } } @@ -21,13 +29,29 @@ pub struct ProcessTable { impl ProcessTable { pub fn new(mm: &mut MemoryManager) -> Self { let mut pt = ProcessTable { - processes: filled_array![Process { satp: None }; 256], + processes: filled_array![Process { satp: 0 }; 256], }; - // Allocate a root page table for PID 1 - // mm.create_identity(1).expect("Unable to create identity mapping"); - pt.processes[1].satp = Some(mm.alloc_page(1).unwrap()); - println!("PID 1: {:?}", pt.processes[1]); + // Allocate a root page table for PID 1. Also mark the "ASID" as "1" + // for "PID 1" + let root_page = mm.alloc_page(1).unwrap().get(); + pt.processes[1].satp = (root_page >> 9) | (1 << 22); + mm.create_identity(&pt.processes[1], 1) + .expect("Unable to create identity mapping"); + println!("PID 1: {:?} root page @ {:08x}", pt.processes[1], root_page); + println!("Enabling MMU..."); + unsafe { + // Set the MMU pointer to our identity mapping + satp::set( + satp::Mode::Sv32, + (pt.processes[1].satp >> 22) & ((1 << 9) - 1), + (pt.processes[1].satp >> 0) & ((1 << 22) - 1), + ); + + // Switch to Supervisor mode + mstatus::set_mpp(mstatus::MPP::Supervisor); + }; + println!("MMU enabled"); pt } }