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:
		
							
								
								
									
										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]
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 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<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) };
 | 
			
		||||
 | 
			
		||||
        // 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<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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // /// 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> {
 | 
			
		||||
        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),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<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 {
 | 
			
		||||
    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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user