Signed-off-by: Sean Cross <sean@xobs.io>
master
Sean Cross 3 years ago
parent 3c15bd68d3
commit 95951535e4
  1. 16
      asm.S
  2. BIN
      bin/riscv32i-unknown-none-elf.a
  3. BIN
      bin/riscv32imac-unknown-none-elf.a
  4. BIN
      bin/riscv32imc-unknown-none-elf.a
  5. BIN
      bin/riscv64gc-unknown-none-elf.a
  6. BIN
      bin/riscv64imac-unknown-none-elf.a
  7. 6
      src/debug.rs
  8. 218
      src/exception.rs
  9. 80
      src/main.rs
  10. 108
      src/mem.rs
  11. 126
      src/processtable.rs
  12. 40
      src/syscalls.rs
  13. 103
      src/timer.rs
  14. 2
      xous-kernel-riscv-rt/asm.S
  15. BIN
      xous-kernel-riscv-rt/bin/riscv32i-unknown-none-elf.a
  16. BIN
      xous-kernel-riscv-rt/bin/riscv32imac-unknown-none-elf.a
  17. BIN
      xous-kernel-riscv-rt/bin/riscv32imc-unknown-none-elf.a
  18. BIN
      xous-kernel-riscv-rt/bin/riscv64gc-unknown-none-elf.a
  19. BIN
      xous-kernel-riscv-rt/bin/riscv64imac-unknown-none-elf.a
  20. 6
      xous-kernel-riscv-rt/link.x

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.

@ -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 {

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

@ -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();
println!("Creating memory manager...");
let mm = MemoryManager::new();
println!("Creating process table...");
ProcessTable::new(mm, kmain);
}
sys_interrupt_claim(2, debug::irq).expect("Couldn't claim interrupt 2");
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 {}
}

@ -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],
};
// 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),
);
// 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 new() -> Result<ProcessTable, XousError> {
Ok(ProcessTable {})
}
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)
}
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.

@ -1,43 +1,70 @@
static mut TIME_MS: u32 = 0;
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 struct Timer {
/// Address of the timer
base: *mut u8,
pub fn get_time() -> u32 {
unsafe { TIME_MS }
/// Number of clock cycles before the timer fires
period: u32,
/// Current count of the timer, in milliseconds
time_ms: u32,
}
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);
// 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 "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);
// Enable ISR
timer_base.add(0x40).write_volatile(1);
// Set "pending" as well to clear it
timer_base.add(0x38).write_volatile(1);
// Finally, enable it
timer_base.add(0x20).write_volatile(1);
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 enable(&self) {
unsafe {
// Disable, so we can update it
self.base.add(0x20).write_volatile(0);
// 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
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
self.base.add(0x40).write_volatile(1);
// Set "pending" as well to clear it
self.base.add(0x38).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
// }

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

@ -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…
Cancel
Save