// src/main.rs #![no_std] #![no_main] #![feature(naked_functions)] use core::panic::PanicInfo; mod entry; mod heap; mod trap; mod uart; #[naked] #[no_mangle] #[link_section = ".text.init"] unsafe extern "C" fn _enter() -> ! { // TODO see if possible to replace this somehow... use core::arch::asm; asm!( // load hartid into `tp`` // if hartid =/= 0, then jump to busy loop "csrr tp, mhartid", "bnez tp, 3f", // before we use the `la` pseudo-instruction for the first time, // we need to set `gp` (look up linker relaxation) ".option push", // pushes the current option stack ".option norelax", // disable relaxation so we can properly set `gp` // this instruction compiles to: // 1: // auipc gp, %pcrel_hi(_global_pointer) // addi gp, gp, %pcrel_lo(1b) // if relaxation were on, this would simply be `mv gp, gp` or `addi gp, gp, 0` "la gp, _global_pointer", ".option pop", // pops the current option stack // delegate all traps to S-mode trap handler "li t5, 0xffff", "csrw medeleg, t5", // delegate all machine exceptions "csrw mideleg, t5", // delegate all machine interrupts // set the stack pointer "la sp, _stack_end", // Make sure machine mode is set, and enable coarse interrupts "li t0, (0b11 << 11) | (1 << 7) | (1 << 3)", "csrw mstatus, t0", // Set mtvec to the location of our trap handler function "la t1, {trap_vector}", "csrw mtvec, t1", // Set MSIE, MTIE, and MEIE on machine interrupt enable CSR: // (1 << 3) = MSIE to enable machine-/M-mode software interrupts // | (1 << 7) = MTIE to enable M-mode timer interrupts (disabled for now) // | (1 << 11) = MEIE to enable M-mode external interrupts "li t2, (1 << 3) | (1 << 11)", "csrw mie, t2", // clear the BSS "la t0, _bss_start", "la t1, _bss_end", "bgeu t0, t1, 2f", "1:", "sb zero, 0(t0)", "addi t0, t0, 1", "bne t0, t1, 1b", "2:", "j 4f", // BSS is clear! // busy loop if hartid =/= 0 "3:", "wfi", // wait for interrupt (or nop) "j 3b", "4:", // "tail-call" to {start} (call without saving a return address) "tail {start}", start = sym start, // {start} refers to the function [start] below trap_vector = sym trap::trap_handler, // {trap_vector} refers to function [trap::trap_handler] options(noreturn) // we must handle "returning" from assembly ); } extern "C" fn start() -> ! { // UNSAFE: Called exactly once, right here. unsafe { heap::init() }; // Now we're free to use dynamic allocation! // { // extern crate alloc; // use alloc::boxed::Box; // let _my_heap_pointer = Box::new(10); // // _my_heap_pointer lives on the heap! // } // println!("This should not print because the console is not initialised."); unsafe { uart::init_console(0x1000_0000) }; println!("Hello, world!"); // print current hartid println!("hartid: {}", riscv::register::mhartid::read()); // poll console for input and print characters back loop { let c = uart::CONSOLE.lock().as_mut().and_then(uart::Device::get); if let Some(c) = c { print!("{}", c as char); } } } #[no_mangle] extern "C" fn eh_personality() {} #[panic_handler] fn panic(info: &PanicInfo) -> ! { // print panic info and abort println!("{}", info); abort(); } #[no_mangle] extern "C" fn abort() -> ! { // loop wait for interrupt loop { riscv::asm::wfi(); } } // TODO unit testing