From 8521093f6d1de54008007653d0b6c529b34b8a0e Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 24 Dec 2019 09:33:02 +0800 Subject: [PATCH] mem: starting to get memory manager working Signed-off-by: Sean Cross --- Cargo.lock | 40 ++++++------ memory.x | 6 +- src/irq.rs | 35 +--------- src/lib.rs | 10 +-- src/macros.rs | 46 +++++++++++++ src/main.rs | 4 ++ src/mem.rs | 127 ++++++++++++++++++++++++++++++++++++ xous-kernel-riscv-rt/link.x | 20 +++--- 8 files changed, 217 insertions(+), 71 deletions(-) create mode 100644 src/macros.rs create mode 100644 src/mem.rs diff --git a/Cargo.lock b/Cargo.lock index f642efa..4ecb93c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,16 +55,6 @@ name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "riscv-rt-macros" -version = "0.1.6" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rustc_version" version = "0.2.3" @@ -105,8 +95,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "xous-kernel" version = "0.1.0" dependencies = [ + "xous-kernel-riscv-rt 0.6.1", "xous-riscv 0.5.4", - "xous-riscv-rt 0.6.1", +] + +[[package]] +name = "xous-kernel-riscv-rt" +version = "0.6.1" +dependencies = [ + "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "xous-kernel-riscv-rt-macros 0.1.6", + "xous-riscv 0.5.4", +] + +[[package]] +name = "xous-kernel-riscv-rt-macros" +version = "0.1.6" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -117,15 +126,6 @@ dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "xous-riscv-rt" -version = "0.6.1" -dependencies = [ - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "riscv-rt-macros 0.1.6", - "xous-riscv 0.5.4", -] - [metadata] "checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" diff --git a/memory.x b/memory.x index 63598ca..ab74582 100644 --- a/memory.x +++ b/memory.x @@ -9,8 +9,10 @@ REGION_ALIAS("REGION_TEXT", FLASH); REGION_ALIAS("REGION_RODATA", FLASH); REGION_ALIAS("REGION_DATA", RAM); REGION_ALIAS("REGION_BSS", RAM); -REGION_ALIAS("REGION_HEAP", RAM); REGION_ALIAS("REGION_STACK", RAM); +REGION_ALIAS("REGION_HEAP", RAM); _lcdfb = ORIGIN(MEMLCD); -_heap_size = LENGTH(RAM) - 1M; +/* Size of the main kernel stack */ +_stack_size = 16K; +_eheap = ORIGIN(RAM) + LENGTH(RAM); diff --git a/src/irq.rs b/src/irq.rs index 83d00eb..e271d82 100644 --- a/src/irq.rs +++ b/src/irq.rs @@ -1,40 +1,7 @@ use crate::syscalls; +use crate::filled_array; use xous_riscv::register::{mstatus, vmim}; -// Shamelessly taken from -// https://stackoverflow.com/questions/36258417/using-a-macro-to-initialize-a-big-array-of-non-copy-elements -// Allows us to fill an array with a predefined value. -macro_rules! filled_array { - (@accum (0, $($_es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@as_expr [$($body)*])}; - (@accum (1, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (0, $($es),*) -> ($($body)* $($es,)*))}; - (@accum (2, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (0, $($es),*) -> ($($body)* $($es,)* $($es,)*))}; - (@accum (3, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (2, $($es),*) -> ($($body)* $($es,)*))}; - (@accum (4, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (2, $($es,)* $($es),*) -> ($($body)*))}; - (@accum (5, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)*))}; - (@accum (6, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)*))}; - (@accum (7, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)* $($es,)*))}; - (@accum (8, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (4, $($es,)* $($es),*) -> ($($body)*))}; - (@accum (16, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (8, $($es,)* $($es),*) -> ($($body)*))}; - (@accum (32, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (16, $($es,)* $($es),*) -> ($($body)*))}; - (@accum (64, $($es:expr),*) -> ($($body:tt)*)) - => {filled_array!(@accum (32, $($es,)* $($es),*) -> ($($body)*))}; - - (@as_expr $e:expr) => {$e}; - - [$e:expr; $n:tt] => { filled_array!(@accum ($n, $e) -> ()) }; -} - static mut IRQ_HANDLERS: [Option; 32] = filled_array![None; 32]; pub fn handle(irqs_pending: usize) { diff --git a/src/lib.rs b/src/lib.rs index 8732447..3981b94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,11 +2,11 @@ extern crate xous_riscv; -use core::panic::PanicInfo; -#[panic_handler] -fn handle_panic(_arg: &PanicInfo) -> ! { - loop {} -} +// use core::panic::PanicInfo; +// #[panic_handler] +// fn handle_panic(_arg: &PanicInfo) -> ! { +// loop {} +// } // Allow consumers of this library to make syscalls pub mod syscalls; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..d91f8cb --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,46 @@ +// Shamelessly taken from +// https://stackoverflow.com/questions/36258417/using-a-macro-to-initialize-a-big-array-of-non-copy-elements +// Allows us to fill an array with a predefined value. +#[macro_export] +macro_rules! filled_array { + (@accum (0, $($_es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@as_expr [$($body)*])}; + (@accum (1, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (0, $($es),*) -> ($($body)* $($es,)*))}; + (@accum (2, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (0, $($es),*) -> ($($body)* $($es,)* $($es,)*))}; + (@accum (3, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (2, $($es),*) -> ($($body)* $($es,)*))}; + (@accum (4, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (2, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (5, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)*))}; + (@accum (6, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)*))}; + (@accum (7, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)* $($es,)*))}; + (@accum (8, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (4, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (16, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (8, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (32, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (16, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (64, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (32, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (128, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (64, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (256, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (128, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (512, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (256, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (1024, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (512, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (2048, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (1024, $($es,)* $($es),*) -> ($($body)*))}; + (@accum (4096, $($es:expr),*) -> ($($body:tt)*)) + => {filled_array!(@accum (2048, $($es,)* $($es),*) -> ($($body)*))}; + + (@as_expr $e:expr) => {$e}; + + [$e:expr; $n:tt] => { filled_array!(@accum ($n, $e) -> ()) }; +} diff --git a/src/main.rs b/src/main.rs index e92c089..a77c9ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,12 +4,15 @@ extern crate xous_riscv; mod syscalls; mod irq; +mod macros; +mod mem; pub use irq::sys_interrupt_claim; use core::panic::PanicInfo; use xous_kernel_riscv_rt::xous_kernel_entry; use xous_riscv::register::{mcause, mstatus, mie, vmim, vmip}; +use mem::MemoryManager; #[panic_handler] @@ -32,6 +35,7 @@ fn xous_main() -> ! { mie::set_mext(); mstatus::set_mie(); // Enable CPU interrupts } + let mm = MemoryManager::new(); sys_interrupt_claim(2, |_| { let uart_ptr = 0xE000_1800 as *mut usize; print_str(uart_ptr, "hello, world!\r\n"); diff --git a/src/mem.rs b/src/mem.rs new file mode 100644 index 0000000..154facb --- /dev/null +++ b/src/mem.rs @@ -0,0 +1,127 @@ +use crate::syscalls::{XousError, XousPid}; +use xous_riscv::register::mstatus; + +const FLASH_START: usize = 0x20000000; +const FLASH_SIZE: usize = 16_777_216; +const FLASH_END: usize = FLASH_START + FLASH_SIZE; +const RAM_START: usize = 0x40000000; +const RAM_SIZE: usize = 16_777_216; +const RAM_END: usize = RAM_START + RAM_SIZE; +const IO_START: usize = 0xe0000000; +const IO_SIZE: usize = 65_536; +const IO_END: usize = IO_START + IO_SIZE; +const LCD_START: usize = 0xB0000000; +const LCD_SIZE: usize = 32_768; +const LCD_END: usize = LCD_START + LCD_SIZE; + +const PAGE_SIZE: usize = 4096; + +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: [u8; FLASH_PAGE_COUNT], + ram: [u8; RAM_PAGE_COUNT], + io: [u8; IO_PAGE_COUNT], + lcd: [u8; LCD_PAGE_COUNT], +} + +extern "C" { + // Boundaries of the .bss section + static mut _ebss: usize; + static mut _sbss: usize; + + // Boundaries of the .data section + static mut _edata: usize; + static mut _sdata: usize; + + // Boundaries of the stack + static mut _estack: usize; + static mut _sstack: usize; + + // Boundaries of the heap + static _sheap: usize; + static _eheap: usize; + + // Initial values of the .data section (stored in Flash) + static _sidata: usize; +} + +use core::mem::transmute; + +/// Initialzie the memory map. +/// This will go through memory and map anything that the kernel is +/// using to process 0xff, then allocate a pagetable for this process +/// and place it at the usual offset. +/// Finally, it will enable the MMU. +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], + }; + + unsafe { mstatus::clear_mie() }; + + // Map the bss section + let start_bss = unsafe { transmute::<&usize, usize>(&_sbss) }; + let end_bss = unsafe { transmute::<&usize, usize>(&_ebss) }; + let bss_range = (start_bss..end_bss).step_by(PAGE_SIZE); + + let start_data = unsafe { transmute::<&usize, usize>(&_sdata) }; + let end_data = unsafe { transmute::<&usize, usize>(&_edata) }; + let data_range = (start_data..end_data).step_by(PAGE_SIZE); + + // Note: stack grows downwards so these are swapped. + let start_stack = unsafe { transmute::<&usize, usize>(&_estack) }; + let end_stack = unsafe { transmute::<&usize, usize>(&_sstack) }; + let stack_range = (start_stack..end_stack).step_by(PAGE_SIZE); + + for region in bss_range { + mm.claim_page(region & !0xfff, 1).unwrap(); + } + + for region in data_range { + mm.claim_page(region & !0xfff, 1).unwrap(); + } + + for region in stack_range { + mm.claim_page(region & !0xfff, 1).unwrap(); + } + + unsafe { mstatus::set_mie() }; + mm + } + + fn claim_page(&mut self, addr: usize, pid: XousPid) -> Result<(), XousError> { + // Ensure the address lies on a page boundary + if addr & 0xfff != 0 { + return Err(XousError::BadAlignment); + } + + match addr { + FLASH_START..=FLASH_END => { + Self::claim_page_inner(&mut self.flash, addr - FLASH_START, pid) + } + RAM_START..=RAM_END => Self::claim_page_inner(&mut self.ram, addr - RAM_START, pid), + IO_START..=IO_END => Self::claim_page_inner(&mut self.io, addr - IO_START, pid), + LCD_START..=LCD_END => Self::claim_page_inner(&mut self.lcd, addr - LCD_START, pid), + _ => Err(XousError::BadAddress), + } + } + + fn claim_page_inner(tbl: &mut [u8], addr: usize, pid: XousPid) -> Result<(), XousError> { + let page = addr / PAGE_SIZE; + if page > tbl.len() { + return Err(XousError::BadAddress); + } + if tbl[page] != 0 { + return Err(XousError::OutOfMemory); + } + tbl[page] = pid; + Ok(()) + } +} diff --git a/xous-kernel-riscv-rt/link.x b/xous-kernel-riscv-rt/link.x index 048bef0..4db8ef3 100644 --- a/xous-kernel-riscv-rt/link.x +++ b/xous-kernel-riscv-rt/link.x @@ -74,23 +74,23 @@ SECTIONS _ebss = .; } > REGION_BSS - /* fictitious region that represents the memory available for the heap */ - .heap (NOLOAD) : - { - _sheap = .; - . += _heap_size; - . = ALIGN(4); - _eheap = .; - } > REGION_HEAP - /* fictitious region that represents the memory available for the stack */ .stack (NOLOAD) : { _estack = .; - . = _stack_start; + PROVIDE(_stack_start = .); + . += _stack_size; _sstack = .; } > REGION_STACK + /* fictitious region that represents the memory available for the heap */ + .heap (NOLOAD) : + { + . = ALIGN(4); + _sheap = .; + /* _eheap is defined elsewhere and is the remainder of RAM */ + } > REGION_HEAP + /* fake output .got section */ /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in the input files and raise an error if relocatable code