From de7fa677cbafa7880dc715c16a6898c817bdb331 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 20 Jan 2020 14:43:11 +0800 Subject: [PATCH] xous: wip commit printf works now, and we're getting the page table stuff set up. Signed-off-by: Sean Cross --- .vscode/settings.json | 23 ++++++++ src/debug.rs | 89 ++++++++++++++++++++++++++++++ src/main.rs | 48 +++++++--------- src/mem.rs | 124 ++++++++++++++++++++++++++++++------------ src/processtable.rs | 11 +++- 5 files changed, 228 insertions(+), 67 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/debug.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..94e66d6 --- /dev/null +++ b/.vscode/settings.json @@ -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" + ] +} \ No newline at end of file diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 0000000..2bf1008 --- /dev/null +++ b/src/debug.rs @@ -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 { + 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(()) + } +} diff --git a/src/main.rs b/src/main.rs index a53a357..194a593 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ #![no_main] extern crate vexriscv; + +mod debug; mod definitions; mod irq; mod macros; @@ -12,22 +14,16 @@ mod syscalls; pub use irq::sys_interrupt_claim; use core::panic::PanicInfo; -use xous_kernel_riscv_rt::xous_kernel_entry; -use vexriscv::register::{mcause, mstatus, mie, vmim, vmip}; use mem::MemoryManager; use processtable::ProcessTable; +use vexriscv::register::{mcause, mie, mstatus, vmim, vmip}; +use xous_kernel_riscv_rt::xous_kernel_entry; #[panic_handler] fn handle_panic(_arg: &PanicInfo) -> ! { loop {} } -fn print_str(uart: *mut usize, s: &str) { - for c in s.bytes() { - unsafe { uart.write_volatile(c as usize) }; - } -} - #[xous_kernel_entry] fn xous_main() -> ! { unsafe { @@ -37,30 +33,21 @@ fn xous_main() -> ! { mie::set_mext(); 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 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 { - unsafe { vexriscv::asm::wfi() }; + // unsafe { vexriscv::asm::wfi() }; } } @@ -69,7 +56,10 @@ pub fn trap_handler() { let mc = mcause::read(); let irqs_pending = vmip::read(); - if mc.is_exception() {} + if mc.is_exception() { + unsafe { vexriscv::asm::ebreak() }; + loop {} + } if irqs_pending != 0 { irq::handle(irqs_pending); diff --git a/src/mem.rs b/src/mem.rs index 04727c0..97e4345 100644 --- a/src/mem.rs +++ b/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 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 IO_PAGE_COUNT: usize = IO_SIZE; const LCD_PAGE_COUNT: usize = LCD_SIZE / PAGE_SIZE; + pub struct MemoryManager { flash: [XousPid; FLASH_PAGE_COUNT], ram: [XousPid; RAM_PAGE_COUNT], @@ -28,6 +30,43 @@ pub struct MemoryManager { 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 { entries: [usize; 1024], } @@ -59,6 +98,14 @@ extern "C" { 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 { ( $s:expr, $e:expr ) => {{ 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 /// 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, @@ -80,35 +127,10 @@ impl MemoryManager { io: [0; IO_PAGE_COUNT], lcd: [0; LCD_PAGE_COUNT], }; + println!("Created Memory Manager: {:?}", mm); - mm - } - - /// Allocate a single page to the given process. - pub fn alloc_page(&mut self, pid: XousPid) -> Result { - // 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::(satp) }; - + // Claim existing pages for PID 1, in preparation for turning on + // the MMU unsafe { mstatus::clear_mie() }; let ranges = [ @@ -119,16 +141,49 @@ impl MemoryManager { ]; for range in &ranges { for region in range.clone() { - self.map_page(pt, pid)?; - self.claim_page(region & !0xfff, 1)?; + mm.claim_page(region & !0xfff, 1) + .expect("Unable to claim region for PID 1"); } } 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 { + // 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) } + // /// Create an identity mapping, copying the kernel to itself + // pub fn create_identity(&mut self, pid: XousPid) -> Result<(), XousError> { + // let pt = unsafe { transmute::(satp) }; + + // Err(XousError::OutOfMemory) + // } + fn map_page(&mut self, satp: &mut PageTable, pid: XousPid) -> Result<(), XousError> { Err(XousError::OutOfMemory) } @@ -153,14 +208,11 @@ impl MemoryManager { } match addr { - FLASH_START..=FLASH_END => { - claim_page_inner(&mut self.flash, addr - FLASH_START, pid) - } + 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), _ => Err(XousError::BadAddress), } } - } diff --git a/src/processtable.rs b/src/processtable.rs index c8da59b..b57de9b 100644 --- a/src/processtable.rs +++ b/src/processtable.rs @@ -1,6 +1,6 @@ use crate::definitions::{XousError, XousPid, MemoryAddress}; use crate::mem::MemoryManager; -use crate::filled_array; +use crate::{filled_array, println, print}; const MAX_PROCESS_COUNT: usize = 256; @@ -8,6 +8,12 @@ struct Process { satp: Option, } +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 { processes: [Process; MAX_PROCESS_COUNT], } @@ -19,8 +25,9 @@ impl ProcessTable { }; // 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()); - mm.create_identity(pt.processes[1].satp.unwrap(), 1).expect("Unable to create identity mapping"); + println!("PID 1: {:?}", pt.processes[1]); pt } }