diff --git a/asm.S b/asm.S index 21e470d..f1cbb70 100644 --- a/asm.S +++ b/asm.S @@ -9,20 +9,10 @@ #endif #define REGBYTES (1 << LOG_REGBYTES) -.global start_kmain +.global return_from_interrupt .text -start_kmain: - li t0, (1 << 11) | (1 << 5) - csrw mstatus, t0 - csrw mepc, a0 - add a0, a1, zero - add a1, a2, zero - add a2, a3, zero - add a3, a4, zero - add a4, a5, zero - add a5, a6, zero - add a6, a7, zero - add a7, zero, zero +return_from_interrupt: + la sp, _estack mret // Return to kmain .global read_satp diff --git a/bin/riscv32i-unknown-none-elf.a b/bin/riscv32i-unknown-none-elf.a index 5bbf9fe..105557d 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 39cbe4b..bf40cf2 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 39cbe4b..bf40cf2 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 def0bcc..c1e5504 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 def0bcc..c1e5504 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 2bf1008..d9de310 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,4 +1,6 @@ use core::fmt::{Error, Write}; +use crate::MemoryManager; +use crate::definitions::XousError; #[macro_export] macro_rules! print @@ -36,6 +38,10 @@ impl Uart { // base: base_addr as *mut usize, // } // } + pub fn init(&self) -> Result<(), XousError> { + // mm.claim_page(self.base as usize, 1) + Ok(()) + } pub fn enable_rx(self) { unsafe { diff --git a/src/exception.rs b/src/exception.rs new file mode 100644 index 0000000..442159b --- /dev/null +++ b/src/exception.rs @@ -0,0 +1,218 @@ +use core::fmt; + +#[derive(PartialEq)] +pub enum RiscvException { + /// When things are all 0 + NoException, + + /// 1 0 + UserSoftwareInterrupt(usize /* mepc */), + + /// 1 1 + SupervisorSoftwareInterrupt(usize /* mepc */), + + // [reserved] + /// 1 3 + MachineSoftwareInterrupt(usize /* mepc */), + + /// 1 4 + UserTimerInterrupt(usize /* mepc */), + + /// 1 5 + SupervisorTimerInterrupt(usize /* mepc */), + + // [reserved] + /// 1 7 + MachineTimerInterrupt(usize /* mepc */), + + /// 1 8 + UserExternalInterrupt(usize /* mepc */), + + /// 1 9 + SupervisorExternalInterrupt(usize /* mepc */), + + // [reserved] + /// 1 11 + MachineExternalInterrupt(usize /* mepc */), + + ReservedInterrupt(usize /* unknown cause number */, usize /* mepc */), + + /// 0 0 + InstructionAddressMisaligned(usize /* mepc */, usize /* target address */), + + /// 0 1 + InstructionAccessFault(usize /* mepc */, usize /* target address */), + + /// 0 2 + IllegalInstruction(usize /* mepc */, usize /* instruction value */), + + /// 0 3 + Breakpoint(usize /* mepc */), + + /// 0 4 + LoadAddressMisaligned(usize /* mepc */, usize /* target address */), + + /// 0 5 + LoadAccessFault(usize /* mepc */, usize /* target address */), + + /// 0 6 + StoreAddressMisaligned(usize /* mepc */, usize /* target address */), + + /// 0 7 + StoreAccessFault(usize /* mepc */, usize /* target address */), + + /// 0 8 + CallFromUMode(usize /* mepc */), + + /// 0 9 + CallFromSMode(usize /* mepc */), + + // [reserved] + /// 0 11 + CallFromMMode(usize /* mepc */), + + /// 0 12 + InstructionPageFault(usize /* mepc */, usize /* target address */), + + /// 0 13 + LoadPageFault(usize /* mepc */, usize /* target address */), + + // [reserved] + /// 0 15 + StorePageFault(usize /* mepc */, usize /* target address */), + + ReservedFault( + usize, /* unknown cause number */ + usize, /* mepc */ + usize, /* mtval */ + ), +} + +impl fmt::Display for RiscvException { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use RiscvException::*; + match *self { + NoException => write!(f, "No trap"), + UserSoftwareInterrupt(epc) => write!(f, "User swi from 0x{:08x}", epc), + SupervisorSoftwareInterrupt(epc) => write!(f, "Supervisor swi from 0x{:08x}", epc), + // --reserved-- + MachineSoftwareInterrupt(epc) => write!(f, "Machine swi at 0x{:08x}", epc), + UserTimerInterrupt(epc) => write!(f, "User timer interrupt at 0x{:08x}", epc), + SupervisorTimerInterrupt(epc) => { + write!(f, "Supervisor timer interrupt at 0x{:08x}", epc) + } + // --reserved-- + MachineTimerInterrupt(epc) => write!(f, "Machine timer interrupt at 0x{:08x}", epc), + UserExternalInterrupt(epc) => write!(f, "User external interrupt at 0x{:08x}", epc), + SupervisorExternalInterrupt(epc) => { + write!(f, "Machine external interrupt at 0x{:08x}", epc) + } + // --reserved-- + MachineExternalInterrupt(epc) => { + write!(f, "Supervisor external interrupt at 0x{:08x}", epc) + } + ReservedInterrupt(code, epc) => { + write!(f, "Reserved interrupt 0x{:08x} at 0x{:08x}", code, epc) + } + + InstructionAddressMisaligned(epc, mtval) => write!( + f, + "Misaligned address instruction 0x{:08x} at 0x{:08x}", + mtval, epc + ), + InstructionAccessFault(epc, mtval) => write!( + f, + "Instruction access fault to 0x{:08x} at 0x{:08x}", + mtval, epc + ), + IllegalInstruction(epc, mtval) => { + write!(f, "Illegal instruction 0x{:08x} at 0x{:08x}", mtval, epc) + } + Breakpoint(epc) => write!(f, "Breakpoint at 0x{:08x}", epc), + LoadAddressMisaligned(epc, mtval) => write!( + f, + "Misaligned load address of 0x{:08x} at 0x{:08x}", + mtval, epc + ), + LoadAccessFault(epc, mtval) => { + write!(f, "Load access fault from 0x{:08x} at 0x{:08x}", mtval, epc) + } + StoreAddressMisaligned(epc, mtval) => write!( + f, + "Misaligned store address of 0x{:08x} at 0x{:08x}", + mtval, epc + ), + StoreAccessFault(epc, mtval) => { + write!(f, "Store access fault to 0x{:08x} at 0x{:08x}", mtval, epc) + } + CallFromUMode(epc) => write!(f, "Call from User mode at 0x{:08x}", epc), + CallFromSMode(epc) => write!(f, "Call from Supervisor mode at 0x{:08x}", epc), + // --reserved-- + CallFromMMode(epc) => write!(f, "Call from Machine mode at 0x{:08x}", epc), + InstructionPageFault(epc, mtval) => write!( + f, + "Instruction page fault of 0x{:08x} at 0x{:08x}", + mtval, epc + ), + LoadPageFault(epc, mtval) => { + write!(f, "Load page fault of 0x{:08x} at 0x{:08x}", mtval, epc) + } + // --reserved-- + StorePageFault(epc, mtval) => { + write!(f, "Load page fault of 0x{:08x} at 0x{:08x}", mtval, epc) + } + ReservedFault(code, epc, mtval) => write!( + f, + "Reserved interrupt 0x{:08x} with cause 0x{:08x} at 0x{:08x}", + code, mtval, epc + ), + } + } +} + +impl RiscvException { + pub fn from_regs(mcause: usize, mepc: usize, mtval: usize) -> RiscvException { + use RiscvException::*; + + if mepc == 0 && mtval == 0 { + return NoException; + } + + match mcause { + 0x80000000 => UserSoftwareInterrupt(mepc), + 0x80000001 => SupervisorSoftwareInterrupt(mepc), + // --reserved-- + 0x80000003 => MachineSoftwareInterrupt(mepc), + 0x80000004 => UserTimerInterrupt(mepc), + 0x80000005 => SupervisorTimerInterrupt(mepc), + // --reserved-- + 0x80000007 => MachineTimerInterrupt(mepc), + 0x80000008 => UserExternalInterrupt(mepc), + 0x80000009 => SupervisorExternalInterrupt(mepc), + // --reserved-- + 0x8000000b => MachineExternalInterrupt(mepc), + + 0 => InstructionAddressMisaligned(mepc, mtval), + 1 => InstructionAccessFault(mepc, mtval), + 2 => IllegalInstruction(mepc, mtval), + 3 => Breakpoint(mepc), + 4 => LoadAddressMisaligned(mepc, mtval), + 5 => LoadAccessFault(mepc, mtval), + 6 => StoreAddressMisaligned(mepc, mtval), + 7 => StoreAccessFault(mepc, mtval), + 8 => CallFromUMode(mepc), + 9 => CallFromSMode(mepc), + // --reserved-- + 11 => CallFromMMode(mepc), + 12 => InstructionPageFault(mepc, mtval), + 13 => LoadPageFault(mepc, mtval), + // --reserved-- + 15 => StorePageFault(mepc, mtval), + x @ 10 | x @ 14 | x @ 16..=0x7fffffff => ReservedFault(x, mepc, mtval), + + x => { + ReservedInterrupt(x & 0x7fffffff, mepc) + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 4fe3c91..22ffea2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ extern crate vexriscv; mod debug; mod definitions; +mod exception; mod irq; mod macros; mod mem; @@ -19,7 +20,7 @@ pub use irq::sys_interrupt_claim; use core::panic::PanicInfo; use mem::MemoryManager; use processtable::ProcessTable; -use vexriscv::register::{mcause, mepc, mie, mstatus, vmim, vmip}; +use vexriscv::register::{mcause, mepc, mie, mstatus, mtval, satp, vmim, vmip}; use xous_kernel_riscv_rt::xous_kernel_entry; #[panic_handler] @@ -29,42 +30,78 @@ fn handle_panic(arg: &PanicInfo) -> ! { loop {} } +extern "Rust" { + fn return_from_interrupt() -> !; +} +extern "C" { + /// Debug function to read the current SATP. Useful since Renode + /// doesn't support reading it any other way. + fn read_satp() -> usize; +} + #[xous_kernel_entry] -fn xous_main() -> ! { +fn mmu_init() -> ! { + let mut mm = MemoryManager::new().expect("Couldn't create memory manager"); + mm.init().expect("Couldn't initialize memory manager"); + + let mut pt = ProcessTable::new().expect("Couldn't create process table"); + + // Allocate a page to PID 1 to use as the root page table, then create + // an identity mapping in preparation for enabling the MMU. + let process1 = pt + .create_process(&mut mm) + .expect("Couldn't create process for PID1"); + let pid1_satp = pt.satp_for(process1).expect("Couldn't find SATP for PID1"); + mm.create_identity(pid1_satp) + .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"); + println!("SATP: {:08x}", unsafe { read_satp() }); + + unsafe { + mstatus::set_spp(mstatus::SPP::Supervisor); + mstatus::set_mpp(mstatus::MPP::Supervisor); + println!("kmain: MSTATUS: {:?}", mstatus::read()); + return_from_interrupt() + } +} + +/// This function runs with the MMU enabled, as part of PID 1 +#[no_mangle] +fn kmain() -> ! { unsafe { vmim::write(0); // Disable all machine interrupts mie::set_msoft(); mie::set_mtimer(); mie::set_mext(); + mstatus::set_mpp(mstatus::MPP::Supervisor); + mstatus::set_spie(); mstatus::set_mie(); // Enable CPU interrupts } + println!("kmain: SATP: {:08x}", satp::read().bits()); + println!("kmain: MSTATUS: {:?}", mstatus::read()); + let uart = debug::DEFAULT_UART; - sys_interrupt_claim(0, timer::irq).unwrap(); - timer::time_init(); + uart.init(); + + // sys_interrupt_claim(0, timer::irq).unwrap(); + // timer::time_init(); // Enable "RX_EMPTY" interrupt uart.enable_rx(); - println!("Starting up..."); - sys_interrupt_claim(2, debug::irq).unwrap(); + sys_interrupt_claim(2, debug::irq).expect("Couldn't claim interrupt 2"); - println!("Creating memory manager..."); - let mm = MemoryManager::new(); - - println!("Creating process table..."); - ProcessTable::new(mm, kmain); -} - -fn kmain(mm: MemoryManager, pt: ProcessTable) -> ! { println!("Entering main loop"); - let mut last_time = timer::get_time(); + // let mut last_time = timer::get_time(); loop { - let new_time = timer::get_time(); - if new_time >= last_time + 1000 { - last_time = new_time; - println!("Uptime: {} ms", new_time); - } + // let new_time = timer::get_time(); + // if new_time >= last_time + 1000 { + // last_time = new_time; + // println!("Uptime: {} ms", new_time); + // } // unsafe { vexriscv::asm::wfi() }; } } @@ -76,7 +113,8 @@ pub fn trap_handler() { if mc.is_exception() { println!("CPU Exception"); - println!("{:?} @ PC: {:08x}", mc.cause(), mepc::read()); + let ex = exception::RiscvException::from_regs(mc.bits(), mepc::read(), mtval::read()); + println!("{}", ex); unsafe { vexriscv::asm::ebreak() }; loop {} } diff --git a/src/mem.rs b/src/mem.rs index 9715faf..ce7113a 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -24,40 +24,49 @@ const RAM_PAGE_COUNT: usize = RAM_SIZE / PAGE_SIZE; const IO_PAGE_COUNT: usize = IO_SIZE; const LCD_PAGE_COUNT: usize = LCD_SIZE / PAGE_SIZE; -pub struct MemoryManager { +pub struct MemoryManagerInner { ram: [XousPid; RAM_PAGE_COUNT], flash: [XousPid; FLASH_PAGE_COUNT], io: [XousPid; IO_PAGE_COUNT], lcd: [XousPid; LCD_PAGE_COUNT], } -impl core::fmt::Debug for MemoryManager { +pub struct MemoryManager {} + +static mut MM: MemoryManagerInner = MemoryManagerInner { + flash: [0; FLASH_PAGE_COUNT], + ram: [0; RAM_PAGE_COUNT], + io: [0; IO_PAGE_COUNT], + lcd: [0; LCD_PAGE_COUNT], +}; + +impl core::fmt::Debug for MemoryManagerInner { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { - writeln!(fmt, "MemoryManager: ")?; + writeln!(fmt, "Ranges: ")?; writeln!( fmt, - " flash: {:08x} .. {:08x} ({})", + " flash: {:08x} .. {:08x} ({} pages)", FLASH_START, FLASH_END, self.flash.len() )?; writeln!( fmt, - " ram: {:08x} .. {:08x} ({})", + " ram: {:08x} .. {:08x} ({} pages)", RAM_START, RAM_END, self.ram.len() )?; writeln!( fmt, - " io: {:08x} .. {:08x} ({})", + " io: {:08x} .. {:08x} ({} pages)", IO_START, IO_END, self.io.len() )?; writeln!( fmt, - " lcd: {:08x} .. {:08x} ({})", + " lcd: {:08x} .. {:08x} ({} pages)", LCD_START, LCD_END, self.lcd.len() @@ -66,6 +75,12 @@ impl core::fmt::Debug for MemoryManager { } } +impl core::fmt::Debug for MemoryManager { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { + unsafe { write!(fmt, "{:?}", MM) } + } +} + /// A single RISC-V page table entry. In order to resolve an address, /// we need two entries: the top level, followed by the lower level. struct PageTable { @@ -121,48 +136,48 @@ macro_rules! mem_range { /// and place it at the usual offset. The MMU will not be enabled yet, /// as the process entry has not yet been created. impl MemoryManager { - pub fn new() -> MemoryManager { - let mut mm = MemoryManager { - flash: [0; FLASH_PAGE_COUNT], - ram: [0; RAM_PAGE_COUNT], - io: [0; IO_PAGE_COUNT], - lcd: [0; LCD_PAGE_COUNT], - }; - println!("Created Memory Manager: {:?}", mm); + pub fn new() -> Result { + Ok(MemoryManager {}) + } + + pub fn init(&mut self) -> Result<(), XousError> { + println!("Initializing Memory Manager: {:?}", self); // Claim existing pages for PID 1, in preparation for turning on - // the MMU + // the MMU. unsafe { mstatus::clear_mie() }; let mut ranges = [ mem_range!(&_sbss, &_ebss), mem_range!(&_sdata, &_edata), - mem_range!(&_estack, &_sstack), // NOTE: Stack is reversed + mem_range!(&_sstack, &_estack), mem_range!(&_stext, &_etext), ]; for range in &mut ranges { for region in range { - mm.claim_page(region & !0xfff, 1) - .expect("Unable to claim region for PID 1"); + self.claim_page(region & !0xfff, 1)?; } } unsafe { mstatus::set_mie() }; - mm + Ok(()) } /// Allocate a single page to the given process. /// Ensures the page is zeroed out prior to handing it over to /// the specified process. pub fn alloc_page(&mut self, pid: XousPid) -> Result { + assert!(pid != 0); + let mut mm = unsafe { &mut MM }; + // Go through all RAM pages looking for a free page. // Optimization: start from the previous address. // println!("Allocating page for PID {}", pid); for index in 0..RAM_PAGE_COUNT { // println!(" Checking {:08x}...", index * PAGE_SIZE + RAM_START); - if self.ram[index] == 0 { - self.ram[index] = pid; + if mm.ram[index] == 0 { + mm.ram[index] = pid; let page_addr = (index * PAGE_SIZE + RAM_START) as *mut u32; // Zero-out the page unsafe { @@ -172,7 +187,7 @@ impl MemoryManager { } let new_page = unsafe { transmute::<*mut u32, usize>(page_addr) }; // println!(" Page {:08x} is free", new_page); - return Ok(NonZeroUsize::new(new_page).unwrap()); + return Ok(NonZeroUsize::new(new_page).expect("Allocated an invalid page")); } } Err(XousError::OutOfMemory) @@ -246,55 +261,36 @@ impl MemoryManager { } /// Create an identity mapping, copying the kernel to itself - pub fn create_identity(&mut self, process: &Process) -> Result<(), XousError> { - let root_page = (process.satp & ((1 << 22) - 1)) << 12; + pub fn create_identity(&mut self, satp: MemoryAddress) -> Result<(), XousError> { + let root_page = (satp.get() & ((1 << 22) - 1)) << 12; + assert!(root_page >= RAM_START); + assert!(root_page < RAM_END); + 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 + "Root page: {:08x} pt: {:p} pt: {:p}", + root_page, &pt, pt ); let mut ranges = [ mem_range!(&_sbss, &_ebss), mem_range!(&_sdata, &_edata), - mem_range!(&_estack, &_sstack), // NOTE: Stack is reversed + mem_range!(&_sstack, &_estack), mem_range!(&_stext, &_etext), ]; for range in &mut ranges { for region in range { - // mm.claim_page(region & !0xfff, 1) - // .expect("Unable to claim region for PID 1"); self.map_page(pt, region, region)?; - // 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!(""); } } - self.map_page(pt, 0xE000_1800, 0xE000_1800)?; - // 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 - // ); - // } - // } - - // for (idx, page) in flash_orig.iter().enumerate() { Ok(()) } /// 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 }; + fn claim_page_inner(tbl: &mut [u8], addr: usize, pid: XousPid) -> Result<(), XousError> { let page = addr / PAGE_SIZE; if page > tbl.len() { @@ -313,10 +309,10 @@ impl MemoryManager { } match addr { - FLASH_START..=FLASH_END => claim_page_inner(&mut self.flash, addr - FLASH_START, pid), - RAM_START..=RAM_END => claim_page_inner(&mut self.ram, addr - RAM_START, pid), - IO_START..=IO_END => claim_page_inner(&mut self.io, addr - IO_START, pid), - LCD_START..=LCD_END => claim_page_inner(&mut self.lcd, addr - LCD_START, pid), + FLASH_START..=FLASH_END => claim_page_inner(&mut mm.flash, addr - FLASH_START, pid), + RAM_START..=RAM_END => claim_page_inner(&mut mm.ram, addr - RAM_START, pid), + IO_START..=IO_END => claim_page_inner(&mut mm.io, addr - IO_START, pid), + LCD_START..=LCD_END => claim_page_inner(&mut mm.lcd, addr - LCD_START, pid), _ => Err(XousError::BadAddress), } } diff --git a/src/processtable.rs b/src/processtable.rs index 36219df..df36821 100644 --- a/src/processtable.rs +++ b/src/processtable.rs @@ -1,14 +1,29 @@ -use crate::definitions::{MemoryAddress, XousError, XousPid}; +use crate::definitions::{MemoryAddress, MemorySize, XousError, XousPid}; use crate::mem::MemoryManager; use crate::{filled_array, print, println}; -use vexriscv::register::{mstatus, satp}; +use vexriscv::register::{mepc, mstatus, satp}; const MAX_PROCESS_COUNT: usize = 256; +static mut CURRENT_SATP: usize = 0; pub struct Process { pub satp: usize, } +pub struct ProcessTableInner { + processes: [Process; MAX_PROCESS_COUNT], +} + +pub struct ProcessTable {} + +static mut PT: ProcessTableInner = ProcessTableInner { + processes: filled_array![Process { satp: 0 }; 256], +}; + +extern "Rust" { + fn kmain(mm: MemoryManager, pt: ProcessTable) -> !; +} + impl core::fmt::Debug for Process { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { write!( @@ -22,48 +37,77 @@ impl core::fmt::Debug for Process { } } -pub struct ProcessTable { - processes: [Process; MAX_PROCESS_COUNT], -} +impl ProcessTableInner { + /// Switch to the new PID when we return to supervisor mode + pub fn switch_to(&self, pid: XousPid, pc: usize) -> Result<(), XousError> { + if pid == 0 { + return Err(XousError::ProcessNotFound); + } + if pid >= 255 { + return Err(XousError::ProcessNotFound); + } -extern "Rust" { - fn start_kmain( - kmain: extern "Rust" fn(MemoryManager, ProcessTable) -> !, - mm: MemoryManager, - pt: ProcessTable, - ) -> !; -} -extern "C" { - fn read_satp() -> usize; + let pid = pid as usize; + let new_satp = self.processes[pid].satp; + if new_satp & (1 << 31) == 0 { + return Err(XousError::ProcessNotFound); + } + + unsafe { + CURRENT_SATP = new_satp; + } + satp::write(new_satp); + mepc::write(pc); + Ok(()) + } + + pub fn alloc_pid(&mut self) -> Result { + for (idx, process) in self.processes.iter().enumerate() { + if process.satp == 0 { + return Ok((idx + 1) as XousPid); + } + } + Err(XousError::ProcessNotChild) + } } impl ProcessTable { - pub fn new(mut mm: MemoryManager, kmain: fn(MemoryManager, ProcessTable) -> !) -> ! { - let mut pt = ProcessTable { - processes: filled_array![Process { satp: 0 }; 256], - }; + pub fn new() -> Result { + Ok(ProcessTable {}) + } - // 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 >> 12) | (1 << 22); - mm.create_identity(&pt.processes[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), - ); + pub fn create_process(&mut self, mm: &mut MemoryManager) -> Result { + let mut pt = unsafe { &mut PT }; + let pid = pt.alloc_pid()?; + let root_page = mm.alloc_page(pid).expect("Couldn't allocate memory for new process page tables"); + let root_page = root_page.get(); + pt.processes[pid as usize].satp = (root_page >> 12) | ((pid as usize) << 22) | (1 << 31); + Ok(pid) + } - // Switch to Supervisor mode - mstatus::set_mpp(mstatus::MPP::Supervisor); - }; - println!("MMU enabled, jumping to kmain"); - println!("SATP: {:08x}", unsafe { read_satp() }); - unsafe { start_kmain(kmain, mm, pt) } + pub fn satp_for(&self, pid: XousPid) -> Result { + let pt = unsafe { &PT }; + match MemoryAddress::new(pt.processes[pid as usize].satp) { + Some(addr) => Ok(addr), + None => Err(XousError::ProcessNotFound) + } + } + + pub fn switch_to(&self, pid: XousPid, pc: usize) -> Result<(), XousError> { + let pt = unsafe { &PT }; + pt.switch_to(pid, pc) } } + +pub fn sys_memory_allocate( + phys: Option, + virt: Option, + size: MemorySize, +) -> Result { + match phys { + Some(addr) => {} + None => {} + } + + Ok(MemoryAddress::new(4096).unwrap()) +} diff --git a/src/syscalls.rs b/src/syscalls.rs index b9ee839..7d753e1 100644 --- a/src/syscalls.rs +++ b/src/syscalls.rs @@ -13,6 +13,28 @@ pub fn sys_interrupt_claim(irq: usize, f: fn(usize)) -> Result<(), XousError> { crate::irq::sys_interrupt_claim(irq, f) } +/// Allocates pages of memory, equal to a total of `size +/// bytes. If a physical address is specified, then this +/// can be used to allocate regions such as memory-mapped I/O. +/// If a virtual address is specified, then the returned +/// pages are located at that address. Otherwise, they +/// are located at an unspecified offset. +/// +/// # Errors +/// +/// * **BadAlignment**: Either the physical or virtual addresses aren't page-aligned, +/// 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) +} + extern "Rust" { /// Allocates kernel structures for a new process, and returns the new PID. /// This removes `page_count` page tables from the calling process at `origin_address` @@ -150,24 +172,6 @@ extern "Rust" { #[allow(dead_code)] pub fn sys_process_terminate(process_id: XousPid) -> Result<(), XousError>; - /// Allocates pages of memory, equal to a total of `size - /// bytes. If a physical address is specified, then this - /// can be used to allocate regions such as memory-mapped I/O. - /// If a virtual address is specified, then the returned - /// pages are located at that address. Otherwise, they - /// are located at an unspecified offset. - /// - /// # Errors - /// - /// * **BadAlignment**: Either the physical or virtual addresses aren't page-aligned, 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; - /// Equivalent to the Unix `sbrk` call. Adjusts the /// heap size to be equal to the specified value. Heap /// sizes start out at 0 bytes in new processes. diff --git a/src/timer.rs b/src/timer.rs index 6ecd091..2f383a6 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,43 +1,70 @@ -static mut TIME_MS: u32 = 0; +pub struct Timer { -pub fn irq(_irq_number: usize) { - let timer_base = 0xE0002800 as *mut u8; - unsafe { - TIME_MS = TIME_MS + 1; - timer_base.add(0x3c).write_volatile(1); - }; + /// Address of the timer + base: *mut u8, + + /// Number of clock cycles before the timer fires + period: u32, + + /// Current count of the timer, in milliseconds + time_ms: u32, } -pub fn get_time() -> u32 { - unsafe { TIME_MS } -} +impl Timer { + pub fn new() -> Timer { + Timer { + base: 0xE0002800 as *mut u8, + period: 12_000_000 / 1000, // 12 MHz, 1 ms timer + time_ms: 0, + } + } -pub fn time_init() { - let timer_base = 0xE0002800 as *mut u8; - let period = 12_000_000 / 1000; // 12 MHz, 1 ms timer - unsafe { - // Disable, so we can update it - timer_base.add(0x20).write_volatile(0); + pub fn enable(&self) { + unsafe { + // Disable, so we can update it + self.base.add(0x20).write_volatile(0); - // Update "reload" register - timer_base.add(0x10).write_volatile((period >> 24) as u8); - timer_base.add(0x14).write_volatile((period >> 16) as u8); - timer_base.add(0x18).write_volatile((period >> 8) as u8); - timer_base.add(0x1c).write_volatile((period >> 0) as u8); + // Update "reload" register + self.base.add(0x10).write_volatile((self.period >> 24) as u8); + self.base.add(0x14).write_volatile((self.period >> 16) as u8); + self.base.add(0x18).write_volatile((self.period >> 8) as u8); + self.base.add(0x1c).write_volatile((self.period >> 0) as u8); - // Update "load" register - timer_base.add(0x00).write_volatile((period >> 24) as u8); - timer_base.add(0x04).write_volatile((period >> 16) as u8); - timer_base.add(0x08).write_volatile((period >> 8) as u8); - timer_base.add(0x0c).write_volatile((period >> 0) as u8); + // Update "load" register + self.base.add(0x00).write_volatile((self.period >> 24) as u8); + self.base.add(0x04).write_volatile((self.period >> 16) as u8); + self.base.add(0x08).write_volatile((self.period >> 8) as u8); + self.base.add(0x0c).write_volatile((self.period >> 0) as u8); - // Enable ISR - timer_base.add(0x40).write_volatile(1); + // Enable ISR + self.base.add(0x40).write_volatile(1); - // Set "pending" as well to clear it - timer_base.add(0x38).write_volatile(1); + // Set "pending" as well to clear it + self.base.add(0x38).write_volatile(1); - // Finally, enable it - timer_base.add(0x20).write_volatile(1); + // Finally, enable it + self.base.add(0x20).write_volatile(1); + } + } + + pub fn elapsed_ms(&self) -> u32 { + return self.time_ms; } } + +// pub fn irq(_irq_number: usize) { +// let timer_base = 0xE0002800 as *mut u8; +// unsafe { +// TIME_MS = TIME_MS + 1; +// timer_base.add(0x3c).write_volatile(1); +// }; +// } + +// pub fn get_time() -> u32 { +// unsafe { TIME_MS } +// } + +// pub fn time_init() { +// let timer_base = 0xE0002800 as *mut u8; +// let period = 12_000_000 / 1000; // 12 MHz, 1 ms timer +// } diff --git a/xous-kernel-riscv-rt/asm.S b/xous-kernel-riscv-rt/asm.S index d616c36..ce46e10 100644 --- a/xous-kernel-riscv-rt/asm.S +++ b/xous-kernel-riscv-rt/asm.S @@ -72,7 +72,7 @@ _start: bgtu a2, t0, abort #endif // SKIP_MULTICORE // Allocate stacks - la sp, _stack_start + la sp, _estack #if !defined(SKIP_MULTICORE) lui t0, %hi(_hart_stack_size) add t0, t0, %lo(_hart_stack_size) diff --git a/xous-kernel-riscv-rt/bin/riscv32i-unknown-none-elf.a b/xous-kernel-riscv-rt/bin/riscv32i-unknown-none-elf.a index c59bd6e..388338f 100644 Binary files a/xous-kernel-riscv-rt/bin/riscv32i-unknown-none-elf.a and b/xous-kernel-riscv-rt/bin/riscv32i-unknown-none-elf.a differ diff --git a/xous-kernel-riscv-rt/bin/riscv32imac-unknown-none-elf.a b/xous-kernel-riscv-rt/bin/riscv32imac-unknown-none-elf.a index 8e8db7d..4f89d55 100644 Binary files a/xous-kernel-riscv-rt/bin/riscv32imac-unknown-none-elf.a and b/xous-kernel-riscv-rt/bin/riscv32imac-unknown-none-elf.a differ diff --git a/xous-kernel-riscv-rt/bin/riscv32imc-unknown-none-elf.a b/xous-kernel-riscv-rt/bin/riscv32imc-unknown-none-elf.a index 8e8db7d..4f89d55 100644 Binary files a/xous-kernel-riscv-rt/bin/riscv32imc-unknown-none-elf.a and b/xous-kernel-riscv-rt/bin/riscv32imc-unknown-none-elf.a differ diff --git a/xous-kernel-riscv-rt/bin/riscv64gc-unknown-none-elf.a b/xous-kernel-riscv-rt/bin/riscv64gc-unknown-none-elf.a index 23e0a13..06657da 100644 Binary files a/xous-kernel-riscv-rt/bin/riscv64gc-unknown-none-elf.a and b/xous-kernel-riscv-rt/bin/riscv64gc-unknown-none-elf.a differ diff --git a/xous-kernel-riscv-rt/bin/riscv64imac-unknown-none-elf.a b/xous-kernel-riscv-rt/bin/riscv64imac-unknown-none-elf.a index 23e0a13..06657da 100644 Binary files a/xous-kernel-riscv-rt/bin/riscv64imac-unknown-none-elf.a and b/xous-kernel-riscv-rt/bin/riscv64imac-unknown-none-elf.a differ diff --git a/xous-kernel-riscv-rt/link.x b/xous-kernel-riscv-rt/link.x index 02d5aaf..eddef39 100644 --- a/xous-kernel-riscv-rt/link.x +++ b/xous-kernel-riscv-rt/link.x @@ -78,10 +78,10 @@ SECTIONS /* fictitious region that represents the memory available for the stack */ .stack (NOLOAD) : { - _estack = .; - PROVIDE(_stack_start = .); - . += _stack_size; _sstack = .; + . += _stack_size; + . = ALIGN(4096); + _estack = .; } > REGION_STACK /* fictitious region that represents the memory available for the heap */