wip commit

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2020-01-23 10:29:20 +08:00
parent 3c15bd68d3
commit 95951535e4
20 changed files with 506 additions and 183 deletions

16
asm.S
View File

@ -9,20 +9,10 @@
#endif #endif
#define REGBYTES (1 << LOG_REGBYTES) #define REGBYTES (1 << LOG_REGBYTES)
.global start_kmain .global return_from_interrupt
.text .text
start_kmain: return_from_interrupt:
li t0, (1 << 11) | (1 << 5) la sp, _estack
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
mret // Return to kmain mret // Return to kmain
.global read_satp .global read_satp

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,6 @@
use core::fmt::{Error, Write}; use core::fmt::{Error, Write};
use crate::MemoryManager;
use crate::definitions::XousError;
#[macro_export] #[macro_export]
macro_rules! print macro_rules! print
@ -36,6 +38,10 @@ impl Uart {
// base: base_addr as *mut usize, // 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) { pub fn enable_rx(self) {
unsafe { unsafe {

218
src/exception.rs Normal file
View File

@ -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)
}
}
}
}

View File

@ -7,6 +7,7 @@ extern crate vexriscv;
mod debug; mod debug;
mod definitions; mod definitions;
mod exception;
mod irq; mod irq;
mod macros; mod macros;
mod mem; mod mem;
@ -19,7 +20,7 @@ pub use irq::sys_interrupt_claim;
use core::panic::PanicInfo; use core::panic::PanicInfo;
use mem::MemoryManager; use mem::MemoryManager;
use processtable::ProcessTable; 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; use xous_kernel_riscv_rt::xous_kernel_entry;
#[panic_handler] #[panic_handler]
@ -29,42 +30,78 @@ fn handle_panic(arg: &PanicInfo) -> ! {
loop {} 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] #[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 { unsafe {
vmim::write(0); // Disable all machine interrupts vmim::write(0); // Disable all machine interrupts
mie::set_msoft(); mie::set_msoft();
mie::set_mtimer(); mie::set_mtimer();
mie::set_mext(); mie::set_mext();
mstatus::set_mpp(mstatus::MPP::Supervisor);
mstatus::set_spie();
mstatus::set_mie(); // Enable CPU interrupts mstatus::set_mie(); // Enable CPU interrupts
} }
println!("kmain: SATP: {:08x}", satp::read().bits());
println!("kmain: MSTATUS: {:?}", mstatus::read());
let uart = debug::DEFAULT_UART; let uart = debug::DEFAULT_UART;
sys_interrupt_claim(0, timer::irq).unwrap(); uart.init();
timer::time_init();
// sys_interrupt_claim(0, timer::irq).unwrap();
// timer::time_init();
// Enable "RX_EMPTY" interrupt // Enable "RX_EMPTY" interrupt
uart.enable_rx(); uart.enable_rx();
println!("Starting up..."); sys_interrupt_claim(2, debug::irq).expect("Couldn't claim interrupt 2");
sys_interrupt_claim(2, debug::irq).unwrap();
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"); println!("Entering main loop");
let mut last_time = timer::get_time(); // let mut last_time = timer::get_time();
loop { loop {
let new_time = timer::get_time(); // let new_time = timer::get_time();
if new_time >= last_time + 1000 { // if new_time >= last_time + 1000 {
last_time = new_time; // last_time = new_time;
println!("Uptime: {} ms", new_time); // println!("Uptime: {} ms", new_time);
} // }
// unsafe { vexriscv::asm::wfi() }; // unsafe { vexriscv::asm::wfi() };
} }
} }
@ -76,7 +113,8 @@ pub fn trap_handler() {
if mc.is_exception() { if mc.is_exception() {
println!("CPU 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() }; unsafe { vexriscv::asm::ebreak() };
loop {} loop {}
} }

View File

@ -24,40 +24,49 @@ const RAM_PAGE_COUNT: usize = RAM_SIZE / PAGE_SIZE;
const IO_PAGE_COUNT: usize = IO_SIZE; const IO_PAGE_COUNT: usize = IO_SIZE;
const LCD_PAGE_COUNT: usize = LCD_SIZE / PAGE_SIZE; const LCD_PAGE_COUNT: usize = LCD_SIZE / PAGE_SIZE;
pub struct MemoryManager { pub struct MemoryManagerInner {
ram: [XousPid; RAM_PAGE_COUNT], ram: [XousPid; RAM_PAGE_COUNT],
flash: [XousPid; FLASH_PAGE_COUNT], flash: [XousPid; FLASH_PAGE_COUNT],
io: [XousPid; IO_PAGE_COUNT], io: [XousPid; IO_PAGE_COUNT],
lcd: [XousPid; LCD_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> { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
writeln!(fmt, "MemoryManager: ")?; writeln!(fmt, "Ranges: ")?;
writeln!( writeln!(
fmt, fmt,
" flash: {:08x} .. {:08x} ({})", " flash: {:08x} .. {:08x} ({} pages)",
FLASH_START, FLASH_START,
FLASH_END, FLASH_END,
self.flash.len() self.flash.len()
)?; )?;
writeln!( writeln!(
fmt, fmt,
" ram: {:08x} .. {:08x} ({})", " ram: {:08x} .. {:08x} ({} pages)",
RAM_START, RAM_START,
RAM_END, RAM_END,
self.ram.len() self.ram.len()
)?; )?;
writeln!( writeln!(
fmt, fmt,
" io: {:08x} .. {:08x} ({})", " io: {:08x} .. {:08x} ({} pages)",
IO_START, IO_START,
IO_END, IO_END,
self.io.len() self.io.len()
)?; )?;
writeln!( writeln!(
fmt, fmt,
" lcd: {:08x} .. {:08x} ({})", " lcd: {:08x} .. {:08x} ({} pages)",
LCD_START, LCD_START,
LCD_END, LCD_END,
self.lcd.len() 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, /// 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. /// we need two entries: the top level, followed by the lower level.
struct PageTable { struct PageTable {
@ -121,48 +136,48 @@ macro_rules! mem_range {
/// and place it at the usual offset. The MMU will not be enabled yet, /// and place it at the usual offset. The MMU will not be enabled yet,
/// as the process entry has not yet been created. /// as the process entry has not yet been created.
impl MemoryManager { impl MemoryManager {
pub fn new() -> MemoryManager { pub fn new() -> Result<MemoryManager, XousError> {
let mut mm = MemoryManager { Ok(MemoryManager {})
flash: [0; FLASH_PAGE_COUNT], }
ram: [0; RAM_PAGE_COUNT],
io: [0; IO_PAGE_COUNT], pub fn init(&mut self) -> Result<(), XousError> {
lcd: [0; LCD_PAGE_COUNT], println!("Initializing Memory Manager: {:?}", self);
};
println!("Created Memory Manager: {:?}", mm);
// Claim existing pages for PID 1, in preparation for turning on // Claim existing pages for PID 1, in preparation for turning on
// the MMU // the MMU.
unsafe { mstatus::clear_mie() }; unsafe { mstatus::clear_mie() };
let mut ranges = [ let mut ranges = [
mem_range!(&_sbss, &_ebss), mem_range!(&_sbss, &_ebss),
mem_range!(&_sdata, &_edata), mem_range!(&_sdata, &_edata),
mem_range!(&_estack, &_sstack), // NOTE: Stack is reversed mem_range!(&_sstack, &_estack),
mem_range!(&_stext, &_etext), mem_range!(&_stext, &_etext),
]; ];
for range in &mut ranges { for range in &mut ranges {
for region in range { for region in range {
mm.claim_page(region & !0xfff, 1) self.claim_page(region & !0xfff, 1)?;
.expect("Unable to claim region for PID 1");
} }
} }
unsafe { mstatus::set_mie() }; unsafe { mstatus::set_mie() };
mm Ok(())
} }
/// Allocate a single page to the given process. /// Allocate a single page to the given process.
/// Ensures the page is zeroed out prior to handing it over to /// Ensures the page is zeroed out prior to handing it over to
/// the specified process. /// the specified process.
pub fn alloc_page(&mut self, pid: XousPid) -> Result<MemoryAddress, XousError> { pub fn alloc_page(&mut self, pid: XousPid) -> Result<MemoryAddress, XousError> {
assert!(pid != 0);
let mut mm = unsafe { &mut MM };
// 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 mm.ram[index] == 0 {
self.ram[index] = pid; mm.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;
// Zero-out the page // Zero-out the page
unsafe { unsafe {
@ -172,7 +187,7 @@ 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).expect("Allocated an invalid page"));
} }
} }
Err(XousError::OutOfMemory) Err(XousError::OutOfMemory)
@ -246,55 +261,36 @@ impl MemoryManager {
} }
/// Create an identity mapping, copying the kernel to itself /// Create an identity mapping, copying the kernel to itself
pub fn create_identity(&mut self, process: &Process) -> Result<(), XousError> { pub fn create_identity(&mut self, satp: MemoryAddress) -> Result<(), XousError> {
let root_page = (process.satp & ((1 << 22) - 1)) << 12; 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)) }; let pt = unsafe { &mut (*(root_page as *mut PageTable)) };
println!( println!(
"SATP value: {:08x} Root page: {:08x} pt: {:p} pt: {:p}", "Root page: {:08x} pt: {:p} pt: {:p}",
process.satp, root_page, &pt, pt root_page, &pt, pt
); );
let mut ranges = [ let mut ranges = [
mem_range!(&_sbss, &_ebss), mem_range!(&_sbss, &_ebss),
mem_range!(&_sdata, &_edata), mem_range!(&_sdata, &_edata),
mem_range!(&_estack, &_sstack), // NOTE: Stack is reversed mem_range!(&_sstack, &_estack),
mem_range!(&_stext, &_etext), mem_range!(&_stext, &_etext),
]; ];
for range in &mut ranges { for range in &mut ranges {
for region in range { for region in range {
// mm.claim_page(region & !0xfff, 1)
// .expect("Unable to claim region for PID 1");
self.map_page(pt, region, region)?; 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!(""); 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(()) 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
fn claim_page(&mut self, addr: usize, pid: XousPid) -> Result<(), XousError> { 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> { fn claim_page_inner(tbl: &mut [u8], addr: usize, pid: XousPid) -> Result<(), XousError> {
let page = addr / PAGE_SIZE; let page = addr / PAGE_SIZE;
if page > tbl.len() { if page > tbl.len() {
@ -313,10 +309,10 @@ impl MemoryManager {
} }
match addr { match addr {
FLASH_START..=FLASH_END => claim_page_inner(&mut self.flash, addr - FLASH_START, pid), FLASH_START..=FLASH_END => claim_page_inner(&mut mm.flash, addr - FLASH_START, pid),
RAM_START..=RAM_END => claim_page_inner(&mut self.ram, addr - RAM_START, pid), RAM_START..=RAM_END => claim_page_inner(&mut mm.ram, addr - RAM_START, pid),
IO_START..=IO_END => claim_page_inner(&mut self.io, addr - IO_START, pid), IO_START..=IO_END => claim_page_inner(&mut mm.io, addr - IO_START, pid),
LCD_START..=LCD_END => claim_page_inner(&mut self.lcd, addr - LCD_START, pid), LCD_START..=LCD_END => claim_page_inner(&mut mm.lcd, addr - LCD_START, pid),
_ => Err(XousError::BadAddress), _ => Err(XousError::BadAddress),
} }
} }

View File

@ -1,14 +1,29 @@
use crate::definitions::{MemoryAddress, XousError, XousPid}; use crate::definitions::{MemoryAddress, MemorySize, XousError, XousPid};
use crate::mem::MemoryManager; use crate::mem::MemoryManager;
use crate::{filled_array, print, println}; use crate::{filled_array, print, println};
use vexriscv::register::{mstatus, satp}; use vexriscv::register::{mepc, mstatus, satp};
const MAX_PROCESS_COUNT: usize = 256; const MAX_PROCESS_COUNT: usize = 256;
static mut CURRENT_SATP: usize = 0;
pub struct Process { pub struct Process {
pub satp: usize, 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 { 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!( write!(
@ -22,48 +37,77 @@ impl core::fmt::Debug for Process {
} }
} }
pub struct ProcessTable { impl ProcessTableInner {
processes: [Process; MAX_PROCESS_COUNT], /// 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" { let pid = pid as usize;
fn start_kmain( let new_satp = self.processes[pid].satp;
kmain: extern "Rust" fn(MemoryManager, ProcessTable) -> !, if new_satp & (1 << 31) == 0 {
mm: MemoryManager, return Err(XousError::ProcessNotFound);
pt: ProcessTable, }
) -> !;
unsafe {
CURRENT_SATP = new_satp;
}
satp::write(new_satp);
mepc::write(pc);
Ok(())
}
pub fn alloc_pid(&mut self) -> Result<XousPid, XousError> {
for (idx, process) in self.processes.iter().enumerate() {
if process.satp == 0 {
return Ok((idx + 1) as XousPid);
}
}
Err(XousError::ProcessNotChild)
} }
extern "C" {
fn read_satp() -> usize;
} }
impl ProcessTable { impl ProcessTable {
pub fn new(mut mm: MemoryManager, kmain: fn(MemoryManager, ProcessTable) -> !) -> ! { pub fn new() -> Result<ProcessTable, XousError> {
let mut pt = ProcessTable { Ok(ProcessTable {})
processes: filled_array![Process { satp: 0 }; 256], }
};
// Allocate a root page table for PID 1. Also mark the "ASID" as "1" pub fn create_process(&mut self, mm: &mut MemoryManager) -> Result<XousPid, XousError> {
// for "PID 1" let mut pt = unsafe { &mut PT };
let root_page = mm.alloc_page(1).unwrap().get(); let pid = pt.alloc_pid()?;
pt.processes[1].satp = (root_page >> 12) | (1 << 22); let root_page = mm.alloc_page(pid).expect("Couldn't allocate memory for new process page tables");
mm.create_identity(&pt.processes[1]) let root_page = root_page.get();
.expect("Unable to create identity mapping"); pt.processes[pid as usize].satp = (root_page >> 12) | ((pid as usize) << 22) | (1 << 31);
println!("PID 1: {:?} root page @ {:08x}", pt.processes[1], root_page); Ok(pid)
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 pub fn satp_for(&self, pid: XousPid) -> Result<MemoryAddress, XousError> {
mstatus::set_mpp(mstatus::MPP::Supervisor); let pt = unsafe { &PT };
}; match MemoryAddress::new(pt.processes[pid as usize].satp) {
println!("MMU enabled, jumping to kmain"); Some(addr) => Ok(addr),
println!("SATP: {:08x}", unsafe { read_satp() }); None => Err(XousError::ProcessNotFound)
unsafe { start_kmain(kmain, mm, pt) }
} }
} }
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<MemoryAddress>,
virt: Option<MemoryAddress>,
size: MemorySize,
) -> Result<MemoryAddress, XousError> {
match phys {
Some(addr) => {}
None => {}
}
Ok(MemoryAddress::new(4096).unwrap())
}

View File

@ -13,6 +13,28 @@ pub fn sys_interrupt_claim(irq: usize, f: fn(usize)) -> Result<(), XousError> {
crate::irq::sys_interrupt_claim(irq, f) 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<MemoryAddress>,
virt: Option<MemoryAddress>,
size: MemorySize,
) -> Result<MemoryAddress, XousError> {
crate::processtable::sys_memory_allocate(phys, virt, size)
}
extern "Rust" { extern "Rust" {
/// Allocates kernel structures for a new process, and returns the new PID. /// 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` /// This removes `page_count` page tables from the calling process at `origin_address`
@ -150,24 +172,6 @@ extern "Rust" {
#[allow(dead_code)] #[allow(dead_code)]
pub fn sys_process_terminate(process_id: XousPid) -> Result<(), XousError>; 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<MemoryAddress>,
virt: Option<MemoryAddress>,
size: MemorySize,
) -> Result<MemoryAddress, XousError>;
/// Equivalent to the Unix `sbrk` call. Adjusts the /// Equivalent to the Unix `sbrk` call. Adjusts the
/// heap size to be equal to the specified value. Heap /// heap size to be equal to the specified value. Heap
/// sizes start out at 0 bytes in new processes. /// sizes start out at 0 bytes in new processes.

View File

@ -1,43 +1,70 @@
static mut TIME_MS: u32 = 0; pub struct Timer {
pub fn irq(_irq_number: usize) { /// Address of the timer
let timer_base = 0xE0002800 as *mut u8; base: *mut u8,
unsafe {
TIME_MS = TIME_MS + 1; /// Number of clock cycles before the timer fires
timer_base.add(0x3c).write_volatile(1); period: u32,
};
/// Current count of the timer, in milliseconds
time_ms: u32,
} }
pub fn get_time() -> u32 { impl Timer {
unsafe { TIME_MS } 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() { pub fn enable(&self) {
let timer_base = 0xE0002800 as *mut u8;
let period = 12_000_000 / 1000; // 12 MHz, 1 ms timer
unsafe { unsafe {
// Disable, so we can update it // Disable, so we can update it
timer_base.add(0x20).write_volatile(0); self.base.add(0x20).write_volatile(0);
// Update "reload" register // Update "reload" register
timer_base.add(0x10).write_volatile((period >> 24) as u8); self.base.add(0x10).write_volatile((self.period >> 24) as u8);
timer_base.add(0x14).write_volatile((period >> 16) as u8); self.base.add(0x14).write_volatile((self.period >> 16) as u8);
timer_base.add(0x18).write_volatile((period >> 8) as u8); self.base.add(0x18).write_volatile((self.period >> 8) as u8);
timer_base.add(0x1c).write_volatile((period >> 0) as u8); self.base.add(0x1c).write_volatile((self.period >> 0) as u8);
// Update "load" register // Update "load" register
timer_base.add(0x00).write_volatile((period >> 24) as u8); self.base.add(0x00).write_volatile((self.period >> 24) as u8);
timer_base.add(0x04).write_volatile((period >> 16) as u8); self.base.add(0x04).write_volatile((self.period >> 16) as u8);
timer_base.add(0x08).write_volatile((period >> 8) as u8); self.base.add(0x08).write_volatile((self.period >> 8) as u8);
timer_base.add(0x0c).write_volatile((period >> 0) as u8); self.base.add(0x0c).write_volatile((self.period >> 0) as u8);
// Enable ISR // Enable ISR
timer_base.add(0x40).write_volatile(1); self.base.add(0x40).write_volatile(1);
// Set "pending" as well to clear it // Set "pending" as well to clear it
timer_base.add(0x38).write_volatile(1); self.base.add(0x38).write_volatile(1);
// Finally, enable it // Finally, enable it
timer_base.add(0x20).write_volatile(1); 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
// }

View File

@ -72,7 +72,7 @@ _start:
bgtu a2, t0, abort bgtu a2, t0, abort
#endif // SKIP_MULTICORE #endif // SKIP_MULTICORE
// Allocate stacks // Allocate stacks
la sp, _stack_start la sp, _estack
#if !defined(SKIP_MULTICORE) #if !defined(SKIP_MULTICORE)
lui t0, %hi(_hart_stack_size) lui t0, %hi(_hart_stack_size)
add t0, t0, %lo(_hart_stack_size) add t0, t0, %lo(_hart_stack_size)

View File

@ -78,10 +78,10 @@ SECTIONS
/* fictitious region that represents the memory available for the stack */ /* fictitious region that represents the memory available for the stack */
.stack (NOLOAD) : .stack (NOLOAD) :
{ {
_estack = .;
PROVIDE(_stack_start = .);
. += _stack_size;
_sstack = .; _sstack = .;
. += _stack_size;
. = ALIGN(4096);
_estack = .;
} > REGION_STACK } > REGION_STACK
/* fictitious region that represents the memory available for the heap */ /* fictitious region that represents the memory available for the heap */