#![no_std] #![no_main] #![feature(naked_functions)] #![allow(static_mut_refs)] #[macro_use] extern crate rcore_console; use core::{ arch::{asm, naked_asm}, ptr::null, }; use sbi_testing::sbi; use uart16550::Uart16550; const RISCV_HEAD_FLAGS: u64 = 0; const RISCV_HEADER_VERSION: u32 = 0x2; const RISCV_IMAGE_MAGIC: u64 = 0x5643534952; /* Magic number, little endian, "RISCV" */ const RISCV_IMAGE_MAGIC2: u32 = 0x05435352; /* Magic number 2, little endian, "RSC\x05" */ /// boot header #[naked] #[unsafe(no_mangle)] #[unsafe(link_section = ".head.text")] unsafe extern "C" fn _boot_header() -> ! { unsafe { naked_asm!( "j _start", ".word 0", ".balign 8", ".dword 0x200000", ".dword iend - istart", ".dword {RISCV_HEAD_FLAGS}", ".word {RISCV_HEADER_VERSION}", ".word 0", ".dword 0", ".dword {RISCV_IMAGE_MAGIC}", ".balign 4", ".word {RISCV_IMAGE_MAGIC2}", ".word 0", RISCV_HEAD_FLAGS = const RISCV_HEAD_FLAGS, RISCV_HEADER_VERSION = const RISCV_HEADER_VERSION, RISCV_IMAGE_MAGIC = const RISCV_IMAGE_MAGIC, RISCV_IMAGE_MAGIC2 = const RISCV_IMAGE_MAGIC2, ); } } /// 内核入口。 /// /// # Safety /// /// 裸函数。 #[naked] #[unsafe(no_mangle)] #[unsafe(link_section = ".text.entry")] unsafe extern "C" fn _start(hartid: usize, device_tree_paddr: usize) -> ! { const STACK_SIZE: usize = 16384; // 16 KiB #[unsafe(link_section = ".bss.uninit")] static mut STACK: [u8; STACK_SIZE] = [0u8; STACK_SIZE]; unsafe { naked_asm!( // clear bss segment " la t0, sbss la t1, ebss 1: bgeu t0, t1, 2f sd zero, 0(t0) addi t0, t0, 8 j 1b", "2:", " la sp, {stack} + {stack_size}", " j {main}", stack_size = const STACK_SIZE, stack = sym STACK, main = sym rust_main, ) } } extern "C" fn rust_main(hartid: usize, dtb_pa: usize) -> ! { let BoardInfo { smp, frequency, uart, } = BoardInfo::parse(dtb_pa); unsafe { UART = Uart16550Map(uart as _) }; rcore_console::init_console(&Console); rcore_console::set_log_level(option_env!("LOG")); println!( r" _____ _ _ __ _ |_ _|__ ___| |_ | |/ /___ _ __ _ __ ___| | | |/ _ \/ __| __| | ' // _ \ '__| '_ \ / _ \ | | | __/\__ \ |_ | . \ __/ | | | | | __/ | |_|\___||___/\__| |_|\_\___|_| |_| |_|\___|_| ================================================ | boot hart id | {hartid:20} | | smp | {smp:20} | | timebase frequency | {frequency:17} Hz | | dtb physical address | {dtb_pa:#20x} | ------------------------------------------------" ); let testing = sbi_testing::Testing { hartid, hart_mask: (1 << smp) - 1, hart_mask_base: 0, delay: frequency, }; if testing.test() { sbi::system_reset(sbi::Shutdown, sbi::NoReason); } else { sbi::system_reset(sbi::Shutdown, sbi::SystemFailure); } unreachable!() } #[cfg_attr(not(test), panic_handler)] fn panic(info: &core::panic::PanicInfo) -> ! { let (hart_id, pc): (usize, usize); unsafe { asm!("mv {}, tp", out(reg) hart_id) }; unsafe { asm!("auipc {}, 0", out(reg) pc) }; println!("[test-kernel-panic] hart {hart_id} {info}"); println!("[test-kernel-panic] pc = {pc:#x}"); println!("[test-kernel-panic] SBI test FAILED due to panic"); sbi::system_reset(sbi::Shutdown, sbi::SystemFailure); loop {} } struct BoardInfo { smp: usize, frequency: u64, uart: usize, } impl BoardInfo { fn parse(dtb_pa: usize) -> Self { use dtb_walker::{Dtb, DtbObj, HeaderError as E, Property, Str, WalkOperation::*}; let mut ans = Self { smp: 0, frequency: 0, uart: 0, }; unsafe { Dtb::from_raw_parts_filtered(dtb_pa as _, |e| { matches!(e, E::Misaligned(4) | E::LastCompVersion(_)) }) } .unwrap() .walk(|ctx, obj| match obj { DtbObj::SubNode { name } => { if ctx.is_root() && (name == Str::from("cpus") || name == Str::from("soc")) { StepInto } else if ctx.name() == Str::from("cpus") && name.starts_with("cpu@") { ans.smp += 1; StepOver } else if ctx.name() == Str::from("soc") && (name.starts_with("uart") || name.starts_with("serial")) { StepInto } else { StepOver } } DtbObj::Property(Property::Reg(mut reg)) => { if ctx.name().starts_with("uart") || ctx.name().starts_with("serial") { ans.uart = reg.next().unwrap().start; } StepOut } DtbObj::Property(Property::General { name, value }) => { if ctx.name() == Str::from("cpus") && name == Str::from("timebase-frequency") { ans.frequency = match *value { [a, b, c, d] => u32::from_be_bytes([a, b, c, d]) as _, [a, b, c, d, e, f, g, h] => u64::from_be_bytes([a, b, c, d, e, f, g, h]), _ => unreachable!(), }; } StepOver } DtbObj::Property(_) => StepOver, }); ans } } struct Console; static mut UART: Uart16550Map = Uart16550Map(null()); pub struct Uart16550Map(*const Uart16550); unsafe impl Sync for Uart16550Map {} impl Uart16550Map { #[inline] pub fn get(&self) -> &Uart16550 { unsafe { &*self.0 } } } impl rcore_console::Console for Console { #[inline] fn put_char(&self, c: u8) { unsafe { UART.get().write(core::slice::from_ref(&c)) }; } #[inline] fn put_str(&self, s: &str) { unsafe { UART.get().write(s.as_bytes()) }; } }