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
|
#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.
@ -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
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 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 {}
|
||||||
}
|
}
|
||||||
|
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 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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
extern "C" {
|
CURRENT_SATP = new_satp;
|
||||||
fn read_satp() -> usize;
|
}
|
||||||
|
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 {
|
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())
|
||||||
|
}
|
||||||
|
@ -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.
|
||||||
|
91
src/timer.rs
91
src/timer.rs
@ -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;
|
unsafe {
|
||||||
let period = 12_000_000 / 1000; // 12 MHz, 1 ms timer
|
// Disable, so we can update it
|
||||||
unsafe {
|
self.base.add(0x20).write_volatile(0);
|
||||||
// Disable, so we can update it
|
|
||||||
timer_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
|
||||||
|
// }
|
||||||
|
@ -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)
|
||||||
|
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 */
|
/* 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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user