mem: get memory mapping working, in theory
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
		
							
								
								
									
										11
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								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() };
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										105
									
								
								src/mem.rs
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								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<MemoryAddress, XousError> {
 | 
			
		||||
        // 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::<MemoryAddress, &mut PageTable>(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
 | 
			
		||||
 
 | 
			
		||||
@@ -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<MemoryAddress>,
 | 
			
		||||
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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user