xous: wip commit
printf works now, and we're getting the page table stuff set up. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
e7db50b177
commit
de7fa677cb
23
.vscode/settings.json
vendored
Normal file
23
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"TXFULL",
|
||||||
|
"Uart",
|
||||||
|
"concat",
|
||||||
|
"ebss",
|
||||||
|
"edata",
|
||||||
|
"eheap",
|
||||||
|
"estack",
|
||||||
|
"etext",
|
||||||
|
"getc",
|
||||||
|
"mstatus",
|
||||||
|
"pagetable",
|
||||||
|
"putc",
|
||||||
|
"satp",
|
||||||
|
"sbss",
|
||||||
|
"sdata",
|
||||||
|
"sheap",
|
||||||
|
"sidata",
|
||||||
|
"sstack",
|
||||||
|
"stext"
|
||||||
|
]
|
||||||
|
}
|
89
src/debug.rs
Normal file
89
src/debug.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use core::fmt::{Error, Write};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print
|
||||||
|
{
|
||||||
|
($($args:tt)+) => ({
|
||||||
|
use core::fmt::Write;
|
||||||
|
let _ = write!(crate::debug::DEFAULT_UART, $($args)+);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println
|
||||||
|
{
|
||||||
|
() => ({
|
||||||
|
print!("\r\n")
|
||||||
|
});
|
||||||
|
($fmt:expr) => ({
|
||||||
|
print!(concat!($fmt, "\r\n"))
|
||||||
|
});
|
||||||
|
($fmt:expr, $($args:tt)+) => ({
|
||||||
|
print!(concat!($fmt, "\r\n"), $($args)+)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Uart {
|
||||||
|
base: *mut usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DEFAULT_UART: Uart = Uart {
|
||||||
|
base: 0xE000_1800 as *mut usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Uart {
|
||||||
|
// pub fn new(base_addr: usize) -> Uart {
|
||||||
|
// Uart {
|
||||||
|
// base: base_addr as *mut usize,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn enable_rx(self) {
|
||||||
|
unsafe {
|
||||||
|
self.base
|
||||||
|
.add(5)
|
||||||
|
.write_volatile(self.base.add(5).read_volatile() | 2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn putc(&self, c: u8) {
|
||||||
|
unsafe {
|
||||||
|
// Wait until TXFULL is `0`
|
||||||
|
while self.base.add(1).read_volatile() != 0 {
|
||||||
|
()
|
||||||
|
}
|
||||||
|
self.base.add(0).write_volatile(c as usize)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getc(&self) -> Option<u8> {
|
||||||
|
unsafe {
|
||||||
|
// If EV_PENDING_RX is 1, return the pending character.
|
||||||
|
// Otherwise, return None.
|
||||||
|
match self.base.add(4).read_volatile() & 2 {
|
||||||
|
0 => None,
|
||||||
|
ack => {
|
||||||
|
let c = Some(self.base.add(0).read_volatile() as u8);
|
||||||
|
self.base.add(4).write_volatile(ack);
|
||||||
|
c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq(irq_number: usize) {
|
||||||
|
println!(
|
||||||
|
"Interrupt {}: Key pressed: {}",
|
||||||
|
irq_number,
|
||||||
|
DEFAULT_UART.getc().unwrap() as char
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for Uart {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), Error> {
|
||||||
|
for c in s.bytes() {
|
||||||
|
self.putc(c);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
48
src/main.rs
48
src/main.rs
@ -2,6 +2,8 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate vexriscv;
|
extern crate vexriscv;
|
||||||
|
|
||||||
|
mod debug;
|
||||||
mod definitions;
|
mod definitions;
|
||||||
mod irq;
|
mod irq;
|
||||||
mod macros;
|
mod macros;
|
||||||
@ -12,22 +14,16 @@ mod syscalls;
|
|||||||
pub use irq::sys_interrupt_claim;
|
pub use irq::sys_interrupt_claim;
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use xous_kernel_riscv_rt::xous_kernel_entry;
|
|
||||||
use vexriscv::register::{mcause, mstatus, mie, vmim, vmip};
|
|
||||||
use mem::MemoryManager;
|
use mem::MemoryManager;
|
||||||
use processtable::ProcessTable;
|
use processtable::ProcessTable;
|
||||||
|
use vexriscv::register::{mcause, mie, mstatus, vmim, vmip};
|
||||||
|
use xous_kernel_riscv_rt::xous_kernel_entry;
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn handle_panic(_arg: &PanicInfo) -> ! {
|
fn handle_panic(_arg: &PanicInfo) -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_str(uart: *mut usize, s: &str) {
|
|
||||||
for c in s.bytes() {
|
|
||||||
unsafe { uart.write_volatile(c as usize) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[xous_kernel_entry]
|
#[xous_kernel_entry]
|
||||||
fn xous_main() -> ! {
|
fn xous_main() -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -37,30 +33,21 @@ fn xous_main() -> ! {
|
|||||||
mie::set_mext();
|
mie::set_mext();
|
||||||
mstatus::set_mie(); // Enable CPU interrupts
|
mstatus::set_mie(); // Enable CPU interrupts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let uart = debug::DEFAULT_UART;
|
||||||
|
|
||||||
|
// Enable "RX_EMPTY" interrupt
|
||||||
|
uart.enable_rx();
|
||||||
|
|
||||||
|
println!("Starting up...");
|
||||||
|
sys_interrupt_claim(2, debug::irq).unwrap();
|
||||||
|
|
||||||
let mut mm = MemoryManager::new();
|
let mut mm = MemoryManager::new();
|
||||||
let mut pt = ProcessTable::new(&mut mm);
|
let mut _pt = ProcessTable::new(&mut mm);
|
||||||
|
|
||||||
sys_interrupt_claim(2, |_| {
|
|
||||||
let uart_ptr = 0xE000_1800 as *mut usize;
|
|
||||||
print_str(uart_ptr, "hello, world!\r\n");
|
|
||||||
// Acknowledge the IRQ
|
|
||||||
unsafe {
|
|
||||||
uart_ptr.add(0).read_volatile();
|
|
||||||
|
|
||||||
// Acknowledge the event
|
|
||||||
uart_ptr.add(4).write_volatile(3);
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Enable interrupts
|
|
||||||
let uart_ptr = 0xE000_1800 as *mut usize;
|
|
||||||
unsafe { uart_ptr.add(4).write_volatile(3) };
|
|
||||||
unsafe { uart_ptr.add(5).write_volatile(3) };
|
|
||||||
print_str(uart_ptr, "greetings!\r\n");
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { vexriscv::asm::wfi() };
|
// unsafe { vexriscv::asm::wfi() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +56,10 @@ pub fn trap_handler() {
|
|||||||
let mc = mcause::read();
|
let mc = mcause::read();
|
||||||
let irqs_pending = vmip::read();
|
let irqs_pending = vmip::read();
|
||||||
|
|
||||||
if mc.is_exception() {}
|
if mc.is_exception() {
|
||||||
|
unsafe { vexriscv::asm::ebreak() };
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
if irqs_pending != 0 {
|
if irqs_pending != 0 {
|
||||||
irq::handle(irqs_pending);
|
irq::handle(irqs_pending);
|
||||||
|
124
src/mem.rs
124
src/mem.rs
@ -1,4 +1,5 @@
|
|||||||
use crate::definitions::{XousError, XousPid, MemoryAddress};
|
use crate::definitions::{MemoryAddress, XousError, XousPid};
|
||||||
|
use crate::{print, println};
|
||||||
use core::num::NonZeroUsize;
|
use core::num::NonZeroUsize;
|
||||||
use vexriscv::register::mstatus;
|
use vexriscv::register::mstatus;
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ const FLASH_PAGE_COUNT: usize = FLASH_SIZE / PAGE_SIZE;
|
|||||||
const RAM_PAGE_COUNT: usize = RAM_SIZE / PAGE_SIZE;
|
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 MemoryManager {
|
||||||
flash: [XousPid; FLASH_PAGE_COUNT],
|
flash: [XousPid; FLASH_PAGE_COUNT],
|
||||||
ram: [XousPid; RAM_PAGE_COUNT],
|
ram: [XousPid; RAM_PAGE_COUNT],
|
||||||
@ -28,6 +30,43 @@ pub struct MemoryManager {
|
|||||||
lcd: [XousPid; LCD_PAGE_COUNT],
|
lcd: [XousPid; LCD_PAGE_COUNT],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Debug for MemoryManager {
|
||||||
|
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
|
||||||
|
writeln!(fmt, "MemoryManager: ")?;
|
||||||
|
writeln!(
|
||||||
|
fmt,
|
||||||
|
" flash: {:08x} .. {:08x} ({})",
|
||||||
|
FLASH_START,
|
||||||
|
FLASH_END,
|
||||||
|
self.flash.len()
|
||||||
|
)?;
|
||||||
|
writeln!(
|
||||||
|
fmt,
|
||||||
|
" ram: {:08x} .. {:08x} ({})",
|
||||||
|
RAM_START,
|
||||||
|
RAM_END,
|
||||||
|
self.ram.len()
|
||||||
|
)?;
|
||||||
|
writeln!(
|
||||||
|
fmt,
|
||||||
|
" io: {:08x} .. {:08x} ({})",
|
||||||
|
IO_START,
|
||||||
|
IO_END,
|
||||||
|
self.io.len()
|
||||||
|
)?;
|
||||||
|
writeln!(
|
||||||
|
fmt,
|
||||||
|
" lcd: {:08x} .. {:08x} ({})",
|
||||||
|
LCD_START,
|
||||||
|
LCD_END,
|
||||||
|
self.lcd.len()
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
struct PageTable {
|
||||||
entries: [usize; 1024],
|
entries: [usize; 1024],
|
||||||
}
|
}
|
||||||
@ -59,6 +98,14 @@ extern "C" {
|
|||||||
|
|
||||||
use core::mem::transmute;
|
use core::mem::transmute;
|
||||||
|
|
||||||
|
/// Enable transmuting from pointers-to-addresses to addresses.
|
||||||
|
/// This is required because the linker creates variables
|
||||||
|
/// such as _stext that are located at specific offsets -- such
|
||||||
|
/// as the start of the text section -- and their address is
|
||||||
|
/// the actual piece of data we want.
|
||||||
|
/// Rust really doesn't like going from addresses to values, so
|
||||||
|
/// we transmute from one to the other in order to construct a
|
||||||
|
/// range that we can loop through.
|
||||||
macro_rules! mem_range {
|
macro_rules! mem_range {
|
||||||
( $s:expr, $e:expr ) => {{
|
( $s:expr, $e:expr ) => {{
|
||||||
let start = unsafe { transmute::<&usize, usize>(&$s) };
|
let start = unsafe { transmute::<&usize, usize>(&$s) };
|
||||||
@ -67,7 +114,7 @@ macro_rules! mem_range {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialzie the memory map.
|
/// Initialize the memory map.
|
||||||
/// This will go through memory and map anything that the kernel is
|
/// This will go through memory and map anything that the kernel is
|
||||||
/// using to process 1, then allocate a pagetable for this process
|
/// using to process 1, then allocate a pagetable for this process
|
||||||
/// 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,
|
||||||
@ -80,35 +127,10 @@ impl MemoryManager {
|
|||||||
io: [0; IO_PAGE_COUNT],
|
io: [0; IO_PAGE_COUNT],
|
||||||
lcd: [0; LCD_PAGE_COUNT],
|
lcd: [0; LCD_PAGE_COUNT],
|
||||||
};
|
};
|
||||||
|
println!("Created Memory Manager: {:?}", mm);
|
||||||
|
|
||||||
mm
|
// Claim existing pages for PID 1, in preparation for turning on
|
||||||
}
|
// the MMU
|
||||||
|
|
||||||
/// Allocate a single page to the given process.
|
|
||||||
pub fn alloc_page(&mut self, pid: XousPid) -> Result<MemoryAddress, XousError> {
|
|
||||||
// Go through all RAM pages looking for a free page.
|
|
||||||
// Optimization: start from the previous address.
|
|
||||||
for index in 0..RAM_PAGE_COUNT {
|
|
||||||
if self.ram[index] == 0 {
|
|
||||||
self.ram[index] = pid;
|
|
||||||
let page_addr = (index * PAGE_SIZE + RAM_START) as *mut u32;
|
|
||||||
// Zero-out the page
|
|
||||||
unsafe {
|
|
||||||
for i in 0..PAGE_SIZE/4 {
|
|
||||||
*page_addr.add(i) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let new_page = unsafe { transmute::<*mut u32, usize>(page_addr) };
|
|
||||||
return Ok(NonZeroUsize::new(new_page).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(XousError::OutOfMemory)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an identity mapping, copying the kernel to itself
|
|
||||||
pub fn create_identity(&mut self, satp: MemoryAddress, pid: XousPid) -> Result<(), XousError> {
|
|
||||||
let pt = unsafe { transmute::<MemoryAddress, &mut PageTable>(satp) };
|
|
||||||
|
|
||||||
unsafe { mstatus::clear_mie() };
|
unsafe { mstatus::clear_mie() };
|
||||||
|
|
||||||
let ranges = [
|
let ranges = [
|
||||||
@ -119,16 +141,49 @@ impl MemoryManager {
|
|||||||
];
|
];
|
||||||
for range in &ranges {
|
for range in &ranges {
|
||||||
for region in range.clone() {
|
for region in range.clone() {
|
||||||
self.map_page(pt, pid)?;
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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> {
|
||||||
|
// 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;
|
||||||
|
let page_addr = (index * PAGE_SIZE + RAM_START) as *mut u32;
|
||||||
|
// Zero-out the page
|
||||||
|
unsafe {
|
||||||
|
for i in 0..PAGE_SIZE / 4 {
|
||||||
|
*page_addr.add(i) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let new_page = unsafe { transmute::<*mut u32, usize>(page_addr) };
|
||||||
|
println!(" Page {:08x} is free", new_page);
|
||||||
|
return Ok(NonZeroUsize::new(new_page).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(XousError::OutOfMemory)
|
Err(XousError::OutOfMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /// Create an identity mapping, copying the kernel to itself
|
||||||
|
// pub fn create_identity(&mut self, pid: XousPid) -> Result<(), XousError> {
|
||||||
|
// let pt = unsafe { transmute::<MemoryAddress, &mut PageTable>(satp) };
|
||||||
|
|
||||||
|
// Err(XousError::OutOfMemory)
|
||||||
|
// }
|
||||||
|
|
||||||
fn map_page(&mut self, satp: &mut PageTable, pid: XousPid) -> Result<(), XousError> {
|
fn map_page(&mut self, satp: &mut PageTable, pid: XousPid) -> Result<(), XousError> {
|
||||||
Err(XousError::OutOfMemory)
|
Err(XousError::OutOfMemory)
|
||||||
}
|
}
|
||||||
@ -153,14 +208,11 @@ impl MemoryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match addr {
|
match addr {
|
||||||
FLASH_START..=FLASH_END => {
|
FLASH_START..=FLASH_END => claim_page_inner(&mut self.flash, addr - FLASH_START, pid),
|
||||||
claim_page_inner(&mut self.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 self.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 self.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 self.lcd, addr - LCD_START, pid),
|
||||||
_ => Err(XousError::BadAddress),
|
_ => Err(XousError::BadAddress),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::definitions::{XousError, XousPid, MemoryAddress};
|
use crate::definitions::{XousError, XousPid, MemoryAddress};
|
||||||
use crate::mem::MemoryManager;
|
use crate::mem::MemoryManager;
|
||||||
use crate::filled_array;
|
use crate::{filled_array, println, print};
|
||||||
|
|
||||||
const MAX_PROCESS_COUNT: usize = 256;
|
const MAX_PROCESS_COUNT: usize = 256;
|
||||||
|
|
||||||
@ -8,6 +8,12 @@ struct Process {
|
|||||||
satp: Option<MemoryAddress>,
|
satp: Option<MemoryAddress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Debug for Process {
|
||||||
|
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
|
||||||
|
write!(fmt, "Process (satp: 0x{:08x})", match self.satp { Some(s) => s.get(), None => 0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ProcessTable {
|
pub struct ProcessTable {
|
||||||
processes: [Process; MAX_PROCESS_COUNT],
|
processes: [Process; MAX_PROCESS_COUNT],
|
||||||
}
|
}
|
||||||
@ -19,8 +25,9 @@ impl ProcessTable {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Allocate a root page table for PID 1
|
// Allocate a root page table for PID 1
|
||||||
|
// mm.create_identity(1).expect("Unable to create identity mapping");
|
||||||
pt.processes[1].satp = Some(mm.alloc_page(1).unwrap());
|
pt.processes[1].satp = Some(mm.alloc_page(1).unwrap());
|
||||||
mm.create_identity(pt.processes[1].satp.unwrap(), 1).expect("Unable to create identity mapping");
|
println!("PID 1: {:?}", pt.processes[1]);
|
||||||
pt
|
pt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user