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:
Sean Cross 2020-01-20 14:43:11 +08:00
parent e7db50b177
commit de7fa677cb
5 changed files with 228 additions and 67 deletions

23
.vscode/settings.json vendored Normal file
View 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
View 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(())
}
}

View File

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

View File

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

View File

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