82 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
// src/main.rs
 | 
						|
#![no_std]
 | 
						|
#![no_main]
 | 
						|
#![feature(naked_functions)]
 | 
						|
 | 
						|
use core::panic::PanicInfo;
 | 
						|
 | 
						|
mod heap;
 | 
						|
mod uart;
 | 
						|
 | 
						|
#[naked]
 | 
						|
#[no_mangle]
 | 
						|
#[link_section = ".text.init"]
 | 
						|
unsafe extern "C" fn _enter() -> ! {
 | 
						|
    use core::arch::asm;
 | 
						|
    asm!(
 | 
						|
        // before we use the `la` pseudo-instruction for the first time,
 | 
						|
        // we need to set `gp` (google 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
 | 
						|
 | 
						|
        // set the stack pointer
 | 
						|
        "la sp, _init_stack_top",
 | 
						|
 | 
						|
        // 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:",
 | 
						|
        // BSS is clear!
 | 
						|
 | 
						|
        // "tail-call" to {start} (call without saving a return address)
 | 
						|
        "tail {start}",
 | 
						|
        start = sym start, // {start} refers to the function [start] below
 | 
						|
        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!");
 | 
						|
 | 
						|
    loop {
 | 
						|
        let c = uart::CONSOLE.lock().as_mut().and_then(uart::Device::get);
 | 
						|
        if let Some(c) = c {
 | 
						|
            print!("{}", c as char);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[panic_handler]
 | 
						|
fn on_panic(info: &PanicInfo) -> ! {
 | 
						|
    println!("{}", info);
 | 
						|
 | 
						|
    loop {}
 | 
						|
}
 | 
						|
 | 
						|
// TODO unit testing
 |