123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- #![feature(naked_functions, asm_const)]
- #![no_std]
- #![no_main]
- #[macro_use]
- extern crate log;
- #[macro_use]
- mod macros;
- mod board;
- mod clint;
- mod console;
- mod dt;
- mod dynamic;
- mod fail;
- mod hart_context;
- mod hsm;
- mod reset;
- mod rfence;
- mod riscv_spec;
- mod trap;
- mod trap_stack;
- use clint::ClintDevice;
- use core::sync::atomic::{AtomicBool, Ordering};
- use core::{arch::asm, mem::MaybeUninit};
- use reset::TestDevice;
- use riscv::register::mstatus;
- use crate::board::{Board, SBI};
- use crate::clint::SIFIVECLINT;
- use crate::console::{ConsoleDevice, CONSOLE};
- use crate::hsm::{local_remote_hsm, Hsm};
- use crate::reset::RESET;
- use crate::rfence::RFence;
- use crate::riscv_spec::{current_hartid, menvcfg};
- use crate::trap::trap_vec;
- use crate::trap_stack::NUM_HART_MAX;
- #[no_mangle]
- extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
- // parse dynamic information
- let info = dynamic::read_paddr(nonstandard_a2).unwrap_or_else(fail::no_dynamic_info_available);
- static GENESIS: AtomicBool = AtomicBool::new(true);
- let is_boot_hart = if info.boot_hart == usize::MAX {
- GENESIS.swap(false, Ordering::AcqRel)
- } else {
- current_hartid() == info.boot_hart
- };
- if is_boot_hart {
- let (mpp, next_addr) =
- dynamic::mpp_next_addr(&info).unwrap_or_else(fail::invalid_dynamic_data);
- // parse the device tree
- let dtb = dt::parse_device_tree(opaque).unwrap_or_else(fail::device_tree_format);
- let dtb = dtb.share();
- let tree =
- serde_device_tree::from_raw_mut(&dtb).unwrap_or_else(fail::device_tree_deserialize);
- // TODO: The device base address needs to be parsed from FDT
- reset::init(0x100000);
- console::init(0x10000000);
- clint::init(0x2000000);
- info!("RustSBI version {}", rustsbi::VERSION);
- rustsbi::LOGO.lines().for_each(|line| info!("{}", line));
- info!("Initializing RustSBI machine-mode environment.");
- if let Some(model) = tree.model {
- info!("Model: {}", model.iter().next().unwrap_or("<unspecified>"));
- }
- info!(
- "Chosen stdout item: {}",
- tree.chosen
- .stdout_path
- .iter()
- .next()
- .unwrap_or("<unspecified>")
- );
- // Init SBI
- unsafe {
- SBI = MaybeUninit::new(Board {
- uart16550: Some(ConsoleDevice::new(&CONSOLE)),
- clint: Some(ClintDevice::new(&SIFIVECLINT, NUM_HART_MAX)),
- hsm: Some(Hsm),
- sifive_test: Some(TestDevice::new(&RESET)),
- rfence: Some(RFence),
- });
- }
- // TODO: PMP configuration needs to be obtained through the memory range in the device tree
- use riscv::register::*;
- unsafe {
- pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
- pmpaddr0::write(0);
- pmpcfg0::set_pmp(1, Range::TOR, Permission::RWX, false);
- pmpaddr1::write(usize::MAX >> 2);
- }
- // 设置陷入栈
- trap_stack::prepare_for_trap();
- // 设置内核入口
- local_remote_hsm().start(NextStage {
- start_addr: next_addr,
- next_mode: mpp,
- opaque,
- });
- info!(
- "Redirecting hart {} to 0x{:0>16x} in {:?} mode.",
- current_hartid(),
- next_addr,
- mpp
- );
- } else {
- // TODO: PMP configuration needs to be obtained through the memory range in the device tree
- use riscv::register::*;
- unsafe {
- pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
- pmpaddr0::write(0);
- pmpcfg0::set_pmp(1, Range::TOR, Permission::RWX, false);
- pmpaddr1::write(usize::MAX >> 2);
- }
- // 设置陷入栈
- trap_stack::prepare_for_trap();
- }
- clint::clear();
- unsafe {
- asm!("csrw mideleg, {}", in(reg) !0);
- asm!("csrw medeleg, {}", in(reg) !0);
- asm!("csrw mcounteren, {}", in(reg) !0);
- use riscv::register::{medeleg, mtvec};
- medeleg::clear_supervisor_env_call();
- medeleg::clear_illegal_instruction();
- menvcfg::set_bits(
- menvcfg::STCE | menvcfg::CBIE_INVALIDATE | menvcfg::CBCFE | menvcfg::CBZE,
- );
- mtvec::write(trap_vec as _, mtvec::TrapMode::Vectored);
- }
- }
- #[naked]
- #[link_section = ".text.entry"]
- #[export_name = "_start"]
- unsafe extern "C" fn start() -> ! {
- core::arch::asm!(
- // 1. Turn off interrupt
- " csrw mie, zero",
- // 2. Initialize programming langauge runtime
- // only clear bss if hartid matches preferred boot hart id
- " csrr t0, mhartid",
- " ld t1, 0(a2)",
- " li t2, {magic}",
- " bne t1, t2, 3f",
- " ld t2, 40(a2)",
- " bne t0, t2, 2f",
- " j 4f",
- "3:",
- " j 3b", // TODO multi hart preempt for runtime init
- "4:",
- // clear bss segment
- " la t0, sbss
- la t1, ebss
- 1: bgeu t0, t1, 2f
- sd zero, 0(t0)
- addi t0, t0, 8
- j 1b",
- // prepare data segment
- " la t3, sidata
- la t4, sdata
- la t5, edata
- 1: bgeu t4, t5, 2f
- ld t6, 0(t3)
- sd t6, 0(t4)
- addi t3, t3, 8
- addi t4, t4, 8
- j 1b",
- "2:",
- // 3. Prepare stack for each hart
- " call {locate_stack}",
- " call {main}",
- " csrw mscratch, sp",
- " j {hart_boot}",
- magic = const dynamic::MAGIC,
- locate_stack = sym trap_stack::locate,
- main = sym rust_main,
- hart_boot = sym trap::msoft,
- options(noreturn)
- )
- }
- #[derive(Debug)]
- pub struct NextStage {
- start_addr: usize,
- opaque: usize,
- next_mode: mstatus::MPP,
- }
- #[panic_handler]
- fn panic(info: &core::panic::PanicInfo) -> ! {
- use riscv::register::*;
- println!(
- "[rustsbi-panic] hart {} {info}",
- riscv::register::mhartid::read()
- );
- println!(
- "-----------------------------
- > mcause: {:?}
- > mepc: {:#018x}
- > mtval: {:#018x}
- -----------------------------",
- mcause::read().cause(),
- mepc::read(),
- mtval::read()
- );
- println!("[rustsbi-panic] system shutdown scheduled due to RustSBI panic");
- loop {}
- }
|