diff --git a/asm.S b/asm.S index f1cbb70..5ab81be 100644 --- a/asm.S +++ b/asm.S @@ -9,12 +9,20 @@ #endif #define REGBYTES (1 << LOG_REGBYTES) +.global enable_mmu .global return_from_interrupt .text +enable_mmu: + la sp, _estack // Trash the stack and start over return_from_interrupt: - la sp, _estack mret // Return to kmain +.global flush_mmu +flush_mmu: + sfence.vma + ret + +.global my_fence .global read_satp .text read_satp: diff --git a/bin/riscv32i-unknown-none-elf.a b/bin/riscv32i-unknown-none-elf.a index 105557d..2182ef2 100644 Binary files a/bin/riscv32i-unknown-none-elf.a and b/bin/riscv32i-unknown-none-elf.a differ diff --git a/bin/riscv32imac-unknown-none-elf.a b/bin/riscv32imac-unknown-none-elf.a index bf40cf2..b332d26 100644 Binary files a/bin/riscv32imac-unknown-none-elf.a and b/bin/riscv32imac-unknown-none-elf.a differ diff --git a/bin/riscv32imc-unknown-none-elf.a b/bin/riscv32imc-unknown-none-elf.a index bf40cf2..b332d26 100644 Binary files a/bin/riscv32imc-unknown-none-elf.a and b/bin/riscv32imc-unknown-none-elf.a differ diff --git a/bin/riscv64gc-unknown-none-elf.a b/bin/riscv64gc-unknown-none-elf.a index c1e5504..d07711b 100644 Binary files a/bin/riscv64gc-unknown-none-elf.a and b/bin/riscv64gc-unknown-none-elf.a differ diff --git a/bin/riscv64imac-unknown-none-elf.a b/bin/riscv64imac-unknown-none-elf.a index c1e5504..d07711b 100644 Binary files a/bin/riscv64imac-unknown-none-elf.a and b/bin/riscv64imac-unknown-none-elf.a differ diff --git a/src/debug.rs b/src/debug.rs index d9de310..4b34b33 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,6 +1,6 @@ +use crate::definitions::{XousError, MemoryAddress, MemorySize}; +// use crate::syscalls::sys_memory_allocate; use core::fmt::{Error, Write}; -use crate::MemoryManager; -use crate::definitions::XousError; #[macro_export] macro_rules! print @@ -33,13 +33,13 @@ pub const DEFAULT_UART: Uart = Uart { }; impl Uart { - // pub fn new(base_addr: usize) -> Uart { - // Uart { - // base: base_addr as *mut usize, - // } - // } pub fn init(&self) -> Result<(), XousError> { - // mm.claim_page(self.base as usize, 1) + // sys_memory_allocate( + // Some(MemoryAddress::new(0xe0001800).unwrap()), + // Some(MemoryAddress::new(0xe0001800).unwrap()), + // MemorySize::new(4096).unwrap(), + // ) + // .expect("Couldn't identity map"); Ok(()) } diff --git a/src/main.rs b/src/main.rs index 22ffea2..4c1a547 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,7 @@ fn handle_panic(arg: &PanicInfo) -> ! { } extern "Rust" { - fn return_from_interrupt() -> !; + fn enable_mmu() -> !; } extern "C" { /// Debug function to read the current SATP. Useful since Renode @@ -56,17 +56,55 @@ fn mmu_init() -> ! { .expect("Couldn't create identity mapping for PID1"); println!("MMU enabled, jumping to kmain"); - pt.switch_to(process1, kmain as usize).expect("Couldn't switch to PID1"); + pt.switch_to(process1, kmain as usize) + .expect("Couldn't switch to PID1"); println!("SATP: {:08x}", unsafe { read_satp() }); unsafe { - mstatus::set_spp(mstatus::SPP::Supervisor); + // When we do an "mret", return to supervisor mode. mstatus::set_mpp(mstatus::MPP::Supervisor); - println!("kmain: MSTATUS: {:?}", mstatus::read()); - return_from_interrupt() + + // Additionally, enable CPU interrupts + mstatus::set_mie(); + + println!("loader: MSTATUS: {:?}", mstatus::read()); + enable_mmu() } } +#[no_mangle] +#[inline(never)] +fn test_good_write() { + let good_ptr = 0x4001_6000 as *mut u32; + // print!("Good ptr write:"); + unsafe { good_ptr.write_volatile(0x12345678) }; + // print!("Ok\r\nGood ptr read: "); + let val = unsafe { good_ptr.read_volatile() }; + // println!("{:08x}", val); +} + +#[no_mangle] +#[inline(never)] +fn test_bad_write() { + let bad_ptr = 0x4001_f000 as *mut u32; + unsafe { bad_ptr.write_volatile(0x98765432) }; + let val = unsafe { bad_ptr.read_volatile() }; + // print!("Bad ptr write:"); + // print!("Ok\r\nBad ptr read: "); + // println!("{:08x}", val); +} + +#[no_mangle] +#[inline(never)] +fn test_uart_write() { + let io_ptr = 0xe000_1800 as *mut u32; + unsafe { io_ptr.add(0).write_volatile(65) }; + // print!("UART ptr write: "); + // print!(" Ok\r\nUART ptr read: "); + let val = unsafe { io_ptr.add(0).read_volatile() }; + println!("{:08x}", val); +} + /// This function runs with the MMU enabled, as part of PID 1 #[no_mangle] fn kmain() -> ! { @@ -75,16 +113,14 @@ fn kmain() -> ! { mie::set_msoft(); mie::set_mtimer(); mie::set_mext(); - mstatus::set_mpp(mstatus::MPP::Supervisor); - mstatus::set_spie(); - mstatus::set_mie(); // Enable CPU interrupts + // mstatus::set_spie(); } - println!("kmain: SATP: {:08x}", satp::read().bits()); - println!("kmain: MSTATUS: {:?}", mstatus::read()); - let uart = debug::DEFAULT_UART; - uart.init(); + // uart.init(); + + // println!("kmain: SATP: {:08x}", satp::read().bits()); + // println!("kmain: MSTATUS: {:?}", mstatus::read()); // sys_interrupt_claim(0, timer::irq).unwrap(); // timer::time_init(); @@ -94,6 +130,10 @@ fn kmain() -> ! { sys_interrupt_claim(2, debug::irq).expect("Couldn't claim interrupt 2"); + test_good_write(); + test_uart_write(); + test_bad_write(); + println!("Entering main loop"); // let mut last_time = timer::get_time(); loop { @@ -112,9 +152,9 @@ pub fn trap_handler() { let irqs_pending = vmip::read(); if mc.is_exception() { - println!("CPU Exception"); let ex = exception::RiscvException::from_regs(mc.bits(), mepc::read(), mtval::read()); - println!("{}", ex); + // print!("CPU Exception: "); + // println!("{}", ex); unsafe { vexriscv::asm::ebreak() }; loop {} } diff --git a/src/mem.rs b/src/mem.rs index ce7113a..1ec297c 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -158,6 +158,7 @@ impl MemoryManager { self.claim_page(region & !0xfff, 1)?; } } + self.claim_page(0xe000_1000, 1)?; unsafe { mstatus::set_mie() }; @@ -199,7 +200,7 @@ impl MemoryManager { /// # Errors /// /// * OutOfMemory - Tried to allocate a new pagetable, but ran out of memory. - fn map_page( + fn map_page_inner( &mut self, root: &mut PageTable, phys: usize, @@ -272,6 +273,9 @@ impl MemoryManager { root_page, &pt, pt ); + // self.map_page_inner(pt, 0xe0001000, 0xe001000)?; + // println!(""); + let mut ranges = [ mem_range!(&_sbss, &_ebss), mem_range!(&_sdata, &_edata), @@ -280,13 +284,31 @@ impl MemoryManager { ]; for range in &mut ranges { for region in range { - self.map_page(pt, region, region)?; + self.map_page_inner(pt, region, region)?; println!(""); } } Ok(()) } + pub fn map_page(&mut self, satp: usize, phys: usize, virt: usize) -> Result { + let root_page = (satp & ((1 << 22) - 1)) << 12; + let pid = ((satp >> 22) & ((1<<9)-1)) as XousPid; + assert!(root_page >= RAM_START); + assert!(root_page < RAM_END); + assert!(pid != 0); + let pt = unsafe { &mut (*(root_page as *mut PageTable)) }; + + self.claim_page(phys, pid)?; + match self.map_page_inner(pt, phys, virt) { + Ok(_) => Ok(MemoryAddress::new(virt).expect("Virt address was not 0")), + Err(e) => { + self.release_page(phys, pid); + Err(e) + } + } + } + /// Mark a given address as being owned by the specified process ID fn claim_page(&mut self, addr: usize, pid: XousPid) -> Result<(), XousError> { let mut mm = unsafe { &mut MM }; @@ -316,4 +338,34 @@ impl MemoryManager { _ => Err(XousError::BadAddress), } } + + /// Mark a given address as being owned by the specified process ID + fn release_page(&mut self, addr: usize, pid: XousPid) -> Result<(), XousError> { + let mut mm = unsafe { &mut MM }; + + fn release_page_inner(tbl: &mut [u8], addr: usize, pid: XousPid) -> Result<(), XousError> { + let page = addr / PAGE_SIZE; + if page > tbl.len() { + return Err(XousError::BadAddress); + } + if tbl[page] != pid { + return Err(XousError::MemoryInUse); + } + tbl[page] = 0; + Ok(()) + } + + // Ensure the address lies on a page boundary + if addr & 0xfff != 0 { + return Err(XousError::BadAlignment); + } + + match addr { + FLASH_START..=FLASH_END => release_page_inner(&mut mm.flash, addr - FLASH_START, pid), + RAM_START..=RAM_END => release_page_inner(&mut mm.ram, addr - RAM_START, pid), + IO_START..=IO_END => release_page_inner(&mut mm.io, addr - IO_START, pid), + LCD_START..=LCD_END => release_page_inner(&mut mm.lcd, addr - LCD_START, pid), + _ => Err(XousError::BadAddress), + } + } } diff --git a/src/processtable.rs b/src/processtable.rs index df36821..25a979b 100644 --- a/src/processtable.rs +++ b/src/processtable.rs @@ -2,6 +2,7 @@ use crate::definitions::{MemoryAddress, MemorySize, XousError, XousPid}; use crate::mem::MemoryManager; use crate::{filled_array, print, println}; use vexriscv::register::{mepc, mstatus, satp}; +use vexriscv::asm::sfence_vma; const MAX_PROCESS_COUNT: usize = 256; static mut CURRENT_SATP: usize = 0; @@ -22,6 +23,7 @@ static mut PT: ProcessTableInner = ProcessTableInner { extern "Rust" { fn kmain(mm: MemoryManager, pt: ProcessTable) -> !; + fn flush_mmu(r1: usize, r2: usize); } impl core::fmt::Debug for Process { @@ -58,6 +60,7 @@ impl ProcessTableInner { } satp::write(new_satp); mepc::write(pc); + unsafe { flush_mmu(0, 0) }; Ok(()) } @@ -104,9 +107,16 @@ pub fn sys_memory_allocate( virt: Option, size: MemorySize, ) -> Result { + let mut mm = MemoryManager::new()?; match phys { - Some(addr) => {} - None => {} + Some(paddr) => match virt { + Some(vaddr) => return mm.map_page(unsafe { CURRENT_SATP }, paddr.get(), vaddr.get()), + None => {}, + } + None => match virt { + Some(vaddr) => {}, + None => {}, + } } Ok(MemoryAddress::new(4096).unwrap()) diff --git a/src/syscalls.rs b/src/syscalls.rs index 7d753e1..39455dd 100644 --- a/src/syscalls.rs +++ b/src/syscalls.rs @@ -26,14 +26,14 @@ pub fn sys_interrupt_claim(irq: usize, f: fn(usize)) -> Result<(), XousError> { /// or the size isn't a multiple of the page width. /// * **OutOfMemory**: A contiguous chunk of memory couldn't be found, or the system's /// memory size has been exceeded. -#[allow(dead_code)] -pub fn sys_memory_allocate( - phys: Option, - virt: Option, - size: MemorySize, -) -> Result { - crate::processtable::sys_memory_allocate(phys, virt, size) -} +// #[allow(dead_code)] +// pub fn sys_memory_allocate( +// phys: Option, +// virt: Option, +// size: MemorySize, +// ) -> Result { +// crate::processtable::sys_memory_allocate(phys, virt, size) +// } extern "Rust" { /// Allocates kernel structures for a new process, and returns the new PID. diff --git a/src/uart.rs b/src/uart.rs deleted file mode 100644 index 645911b..0000000 --- a/src/uart.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::fmt::{Error, Write}; - -pub struct Uart {} - -impl Uart { - pub fn new() -> Uart { - Uart {} - } - - pub fn putc(&self, c: u8) { - let ptr = 0xE000_1800 as *mut u32; - unsafe { - while ptr.add(1).read_volatile() == 0 {} - ptr.add(0).write_volatile(c as u32); - } - } - - fn get(&self, base_addr: usize) -> Option { - let ptr = 0xE000_1800 as *mut u32; - unsafe { - if ptr.add(2).read_volatile() == 0 { - Some(ptr.add(0).read_volatile() as u8) - } else { - None - } - } - } -} - -// This is a slightly different syntax. Write is this "trait", meaning it is much like -// an interface where we're just guaranteeing a certain function signature. In the Write -// trait, one is absolutely required to be implemented, which is write_str. There are other -// functions, but they all rely on write_str(), so their default implementation is OK for now. -impl Write for Uart { - // The trait Write expects us to write the function write_str - // which looks like: - fn write_str(&mut self, s: &str) -> Result<(), Error> { - for c in s.bytes() { - self.putc(c); - } - // Return that we succeeded. - Ok(()) - } -} - -#[macro_export] -macro_rules! print -{ - ($($args:tt)+) => ({ - use core::fmt::Write; - let _ = write!(crate::uart::Uart::new(), $($args)+); - }); -} -#[macro_export] -macro_rules! println -{ - () => ({ - print!("\r\n") - }); - ($fmt:expr) => ({ - print!(concat!($fmt, "\r\n")) - }); - ($fmt:expr, $($args:tt)+) => ({ - print!(concat!($fmt, "\r\n"), $($args)+) - }); -}