wip commit
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
3c15bd68d3
commit
95951535e4
16
asm.S
16
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
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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 {
|
||||
|
218
src/exception.rs
Normal file
218
src/exception.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
80
src/main.rs
80
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 {}
|
||||
}
|
||||
|
108
src/mem.rs
108
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<MemoryManager, XousError> {
|
||||
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<MemoryAddress, XousError> {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -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<XousPid, XousError> {
|
||||
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<ProcessTable, XousError> {
|
||||
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<XousPid, XousError> {
|
||||
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<MemoryAddress, XousError> {
|
||||
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<MemoryAddress>,
|
||||
virt: Option<MemoryAddress>,
|
||||
size: MemorySize,
|
||||
) -> Result<MemoryAddress, XousError> {
|
||||
match phys {
|
||||
Some(addr) => {}
|
||||
None => {}
|
||||
}
|
||||
|
||||
Ok(MemoryAddress::new(4096).unwrap())
|
||||
}
|
||||
|
@ -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<MemoryAddress>,
|
||||
virt: Option<MemoryAddress>,
|
||||
size: MemorySize,
|
||||
) -> Result<MemoryAddress, XousError> {
|
||||
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<MemoryAddress>,
|
||||
virt: Option<MemoryAddress>,
|
||||
size: MemorySize,
|
||||
) -> Result<MemoryAddress, XousError>;
|
||||
|
||||
/// 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.
|
||||
|
77
src/timer.rs
77
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
|
||||
pub fn enable(&self) {
|
||||
unsafe {
|
||||
// Disable, so we can update it
|
||||
timer_base.add(0x20).write_volatile(0);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
self.base.add(0x40).write_volatile(1);
|
||||
|
||||
// Set "pending" as well to clear it
|
||||
timer_base.add(0x38).write_volatile(1);
|
||||
self.base.add(0x38).write_volatile(1);
|
||||
|
||||
// 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
|
||||
// }
|
||||
|
@ -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)
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user