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;
 | 
					extern crate vexriscv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[macro_use]
 | 
				
			||||||
mod debug;
 | 
					mod debug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod definitions;
 | 
					mod definitions;
 | 
				
			||||||
mod irq;
 | 
					mod irq;
 | 
				
			||||||
mod macros;
 | 
					mod macros;
 | 
				
			||||||
@@ -20,7 +22,9 @@ use vexriscv::register::{mcause, mie, mstatus, vmim, vmip};
 | 
				
			|||||||
use xous_kernel_riscv_rt::xous_kernel_entry;
 | 
					use xous_kernel_riscv_rt::xous_kernel_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[panic_handler]
 | 
					#[panic_handler]
 | 
				
			||||||
fn handle_panic(_arg: &PanicInfo) -> ! {
 | 
					fn handle_panic(arg: &PanicInfo) -> ! {
 | 
				
			||||||
 | 
					    println!("PANIC!");
 | 
				
			||||||
 | 
					    println!("Details: {:?}", arg);
 | 
				
			||||||
    loop {}
 | 
					    loop {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,10 +46,13 @@ fn xous_main() -> ! {
 | 
				
			|||||||
    println!("Starting up...");
 | 
					    println!("Starting up...");
 | 
				
			||||||
    sys_interrupt_claim(2, debug::irq).unwrap();
 | 
					    sys_interrupt_claim(2, debug::irq).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Creating memory manager...");
 | 
				
			||||||
    let mut mm = MemoryManager::new();
 | 
					    let mut mm = MemoryManager::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Creating process table...");
 | 
				
			||||||
    let mut _pt = ProcessTable::new(&mut mm);
 | 
					    let mut _pt = ProcessTable::new(&mut mm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("Entering main loop");
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        // unsafe { vexriscv::asm::wfi() };
 | 
					        // unsafe { vexriscv::asm::wfi() };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										105
									
								
								src/mem.rs
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								src/mem.rs
									
									
									
									
									
								
							@@ -1,4 +1,5 @@
 | 
				
			|||||||
use crate::definitions::{MemoryAddress, XousError, XousPid};
 | 
					use crate::definitions::{MemoryAddress, XousError, XousPid};
 | 
				
			||||||
 | 
					use crate::processtable::Process;
 | 
				
			||||||
use crate::{print, println};
 | 
					use crate::{print, println};
 | 
				
			||||||
use core::num::NonZeroUsize;
 | 
					use core::num::NonZeroUsize;
 | 
				
			||||||
use vexriscv::register::mstatus;
 | 
					use vexriscv::register::mstatus;
 | 
				
			||||||
@@ -157,9 +158,9 @@ impl MemoryManager {
 | 
				
			|||||||
    pub fn alloc_page(&mut self, pid: XousPid) -> Result<MemoryAddress, XousError> {
 | 
					    pub fn alloc_page(&mut self, pid: XousPid) -> Result<MemoryAddress, XousError> {
 | 
				
			||||||
        // Go through all RAM pages looking for a free page.
 | 
					        // Go through all RAM pages looking for a free page.
 | 
				
			||||||
        // Optimization: start from the previous address.
 | 
					        // 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 {
 | 
					        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 {
 | 
					            if self.ram[index] == 0 {
 | 
				
			||||||
                self.ram[index] = pid;
 | 
					                self.ram[index] = pid;
 | 
				
			||||||
                let page_addr = (index * PAGE_SIZE + RAM_START) as *mut u32;
 | 
					                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) };
 | 
					                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());
 | 
					                return Ok(NonZeroUsize::new(new_page).unwrap());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Err(XousError::OutOfMemory)
 | 
					        Err(XousError::OutOfMemory)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // /// Create an identity mapping, copying the kernel to itself
 | 
					    /// Map the given page to the specified process table.  If necessary,
 | 
				
			||||||
    // pub fn create_identity(&mut self, pid: XousPid) -> Result<(), XousError> {
 | 
					    /// allocate a new page.
 | 
				
			||||||
    //     let pt = unsafe { transmute::<MemoryAddress, &mut PageTable>(satp) };
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # 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> {
 | 
					        let ref mut l1_pt = root.entries;
 | 
				
			||||||
        Err(XousError::OutOfMemory)
 | 
					        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
 | 
					    /// 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::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;
 | 
					const MAX_PROCESS_COUNT: usize = 256;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Process {
 | 
					pub struct Process {
 | 
				
			||||||
    satp: Option<MemoryAddress>,
 | 
					    pub satp: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl core::fmt::Debug for Process {
 | 
					impl core::fmt::Debug for Process {
 | 
				
			||||||
    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
 | 
					    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 {
 | 
					impl ProcessTable {
 | 
				
			||||||
    pub fn new(mm: &mut MemoryManager) -> Self {
 | 
					    pub fn new(mm: &mut MemoryManager) -> Self {
 | 
				
			||||||
        let mut pt = ProcessTable {
 | 
					        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
 | 
					        // Allocate a root page table for PID 1.  Also mark the "ASID" as "1"
 | 
				
			||||||
        // mm.create_identity(1).expect("Unable to create identity mapping");
 | 
					        // for "PID 1"
 | 
				
			||||||
        pt.processes[1].satp = Some(mm.alloc_page(1).unwrap());
 | 
					        let root_page = mm.alloc_page(1).unwrap().get();
 | 
				
			||||||
        println!("PID 1: {:?}", pt.processes[1]);
 | 
					        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
 | 
					        pt
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user