123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- #![no_std]
- #![no_main]
- #![feature(naked_functions)]
- #![feature(alloc_error_handler)]
- #![feature(llvm_asm)]
- #![feature(asm)]
- #![feature(global_asm)]
- mod hal;
- use core::alloc::Layout;
- use core::panic::PanicInfo;
- use linked_list_allocator::LockedHeap;
- use rustsbi::{print, println, enter_privileged};
- use riscv::register::{
- mcause::{self, Exception, Interrupt, Trap},
- medeleg, mepc, mhartid, mideleg, mie, mip, misa::{self, MXL},
- mstatus::{self, MPP},
- mtval,
- mtvec::{self, TrapMode},
- };
- #[global_allocator]
- static ALLOCATOR: LockedHeap = LockedHeap::empty();
- #[panic_handler]
- fn panic(info: &PanicInfo) -> ! {
- println!("{}", info);
- loop {}
- }
- #[alloc_error_handler]
- fn oom(_layout: Layout) -> ! {
- loop {}
- }
- // #[export_name = "_mp_hook"]
- pub extern "C" fn _mp_hook() -> bool {
- mhartid::read() == 0
- }
- #[export_name = "_start"]
- #[link_section = ".text.entry"] // this is stable
- #[naked]
- fn main() -> ! {
- unsafe {
- llvm_asm!(
- "
- csrr a2, mhartid
- lui t0, %hi(_max_hart_id)
- add t0, t0, %lo(_max_hart_id)
- bgtu a2, t0, _start_abort
- la sp, _stack_start
- lui t0, %hi(_hart_stack_size)
- add t0, t0, %lo(_hart_stack_size)
- .ifdef __riscv_mul
- mul t0, a2, t0
- .else
- beqz a2, 2f // Jump if single-hart
- mv t1, a2
- mv t2, t0
- 1:
- add t0, t0, t2
- addi t1, t1, -1
- bnez t1, 1b
- 2:
- .endif
- sub sp, sp, t0
- csrw mscratch, zero
- j _start_success
-
- _start_abort:
- wfi
- j _start_abort
- _start_success:
-
- "
- )
- };
- // Ref: https://github.com/qemu/qemu/blob/aeb07b5f6e69ce93afea71027325e3e7a22d2149/hw/riscv/boot.c#L243
- let dtb_pa = unsafe {
- let dtb_pa: usize;
- llvm_asm!("":"={a1}"(dtb_pa));
- dtb_pa
- };
- if _mp_hook() {
- // init
- }
- /* setup trap */
- extern "C" {
- fn _start_trap();
- }
- unsafe {
- mtvec::write(_start_trap as usize, TrapMode::Direct);
- }
- /* main function start */
- extern "C" {
- static mut _sheap: u8;
- static _heap_size: u8;
- }
- if mhartid::read() == 0 {
- let sheap = unsafe { &mut _sheap } as *mut _ as usize;
- let heap_size = unsafe { &_heap_size } as *const u8 as usize;
- unsafe {
- ALLOCATOR.lock().init(sheap, heap_size);
- }
- // 其实这些参数不用提供,直接通过pac库生成
- let serial = hal::Ns16550a::new(0x10000000, 0, 11_059_200, 115200);
- // use through macro
- use rustsbi::legacy_stdio::init_legacy_stdio_embedded_hal;
- init_legacy_stdio_embedded_hal(serial);
- let clint = hal::Clint::new(0x2000000 as *mut u8);
- use rustsbi::init_ipi;
- init_ipi(clint);
- // todo: do not create two instances
- let clint = hal::Clint::new(0x2000000 as *mut u8);
- use rustsbi::init_timer;
- init_timer(clint);
- use rustsbi::init_reset;
- init_reset(hal::Reset);
- }
- // 把S的中断全部委托给S层
- unsafe {
- mideleg::set_sext();
- mideleg::set_stimer();
- mideleg::set_ssoft();
- medeleg::set_instruction_misaligned();
- medeleg::set_breakpoint();
- medeleg::set_user_env_call();
- medeleg::set_instruction_page_fault();
- medeleg::set_load_page_fault();
- medeleg::set_store_page_fault();
- mie::set_mext();
- // 不打开mie::set_mtimer
- mie::set_msoft();
- }
- if mhartid::read() == 0 {
- println!("[rustsbi] Version 0.1.0");
- println!("{}", rustsbi::LOGO);
- println!("[rustsbi] Platform: QEMU");
- let isa = misa::read();
- if let Some(isa) = isa {
- let mxl_str = match isa.mxl() {
- MXL::XLEN32 => "RV32",
- MXL::XLEN64 => "RV64",
- MXL::XLEN128 => "RV128",
- };
- print!("[rustsbi] misa: {}", mxl_str);
- for ext in 'A'..='Z' {
- if isa.has_extension(ext) {
- print!("{}", ext);
- }
- }
- println!("");
- }
- println!("[rustsbi] mideleg: {:#x}", mideleg::read().bits());
- println!("[rustsbi] medeleg: {:#x}", medeleg::read().bits());
- println!("[rustsbi] Kernel entry: 0x80200000");
- }
- extern "C" {
- fn _s_mode_start();
- }
- unsafe {
- mepc::write(_s_mode_start as usize);
- mstatus::set_mpp(MPP::Supervisor);
- enter_privileged(mhartid::read(), dtb_pa);
- }
- }
- global_asm!(
- "
- _s_mode_start:
- .option push
- .option norelax
- 1:
- auipc ra, %pcrel_hi(1f)
- ld ra, %pcrel_lo(1b)(ra)
- jr ra
- .align 3
- 1:
- .dword 0x80200000
- .option pop
- ");
- global_asm!(
- "
- .equ REGBYTES, 8
- .macro STORE reg, offset
- sd \\reg, \\offset*REGBYTES(sp)
- .endm
- .macro LOAD reg, offset
- ld \\reg, \\offset*REGBYTES(sp)
- .endm
- .section .text
- .global _start_trap
- .p2align 2
- _start_trap:
- csrrw sp, mscratch, sp
- bnez sp, 1f
- /* from M level, load sp */
- csrrw sp, mscratch, zero
- 1:
- addi sp, sp, -16 * REGBYTES
- STORE ra, 0
- STORE t0, 1
- STORE t1, 2
- STORE t2, 3
- STORE t3, 4
- STORE t4, 5
- STORE t5, 6
- STORE t6, 7
- STORE a0, 8
- STORE a1, 9
- STORE a2, 10
- STORE a3, 11
- STORE a4, 12
- STORE a5, 13
- STORE a6, 14
- STORE a7, 15
- mv a0, sp
- call _start_trap_rust
- LOAD ra, 0
- LOAD t0, 1
- LOAD t1, 2
- LOAD t2, 3
- LOAD t3, 4
- LOAD t4, 5
- LOAD t5, 6
- LOAD t6, 7
- LOAD a0, 8
- LOAD a1, 9
- LOAD a2, 10
- LOAD a3, 11
- LOAD a4, 12
- LOAD a5, 13
- LOAD a6, 14
- LOAD a7, 15
- addi sp, sp, 16 * REGBYTES
- csrrw sp, mscratch, sp
- mret
- "
- );
- // #[doc(hidden)]
- // #[export_name = "_mp_hook"]
- // pub extern "Rust" fn _mp_hook() -> bool {
- // match mhartid::read() {
- // 0 => true,
- // _ => loop {
- // unsafe { riscv::asm::wfi() }
- // },
- // }
- // }
- #[allow(unused)]
- struct TrapFrame {
- ra: usize,
- t0: usize,
- t1: usize,
- t2: usize,
- t3: usize,
- t4: usize,
- t5: usize,
- t6: usize,
- a0: usize,
- a1: usize,
- a2: usize,
- a3: usize,
- a4: usize,
- a5: usize,
- a6: usize,
- a7: usize,
- }
- #[export_name = "_start_trap_rust"]
- extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
- let cause = mcause::read().cause();
- match cause {
- Trap::Exception(Exception::SupervisorEnvCall) => {
- let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3];
- // 调用rust_sbi库的处理函数
- let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
- // 把返回值送还给TrapFrame
- trap_frame.a0 = ans.error;
- trap_frame.a1 = ans.value;
- // 跳过ecall指令
- mepc::write(mepc::read().wrapping_add(4));
- }
- Trap::Interrupt(Interrupt::MachineSoft) => {
- // 机器软件中断返回给S层
- unsafe {
- mip::set_ssoft();
- mie::clear_msoft();
- }
- }
- Trap::Interrupt(Interrupt::MachineTimer) => {
- // 机器时间中断返回给S层
- unsafe {
- mip::set_stimer();
- mie::clear_mtimer();
- }
- }
- Trap::Exception(Exception::IllegalInstruction) => {
- #[inline]
- unsafe fn get_vaddr_u32(vaddr: usize) -> u32 {
- let mut ans: u32;
- llvm_asm!("
- li t0, (1 << 17)
- mv t1, $1
- csrrs t0, mstatus, t0
- lwu t1, 0(t1)
- csrw mstatus, t0
- mv $0, t1
- "
- :"=r"(ans)
- :"r"(vaddr)
- :"t0", "t1");
- ans
- }
- let vaddr = mepc::read();
- let ins = unsafe { get_vaddr_u32(vaddr) };
- if ins & 0xFFFFF07F == 0xC0102073 {
- // rdtime
- let rd = ((ins >> 7) & 0b1_1111) as u8;
- // todo: one instance only
- let clint = hal::Clint::new(0x2000000 as *mut u8);
- let time_usize = clint.get_mtime() as usize;
- match rd {
- 10 => trap_frame.a0 = time_usize,
- 11 => trap_frame.a1 = time_usize,
- 12 => trap_frame.a2 = time_usize,
- 13 => trap_frame.a3 = time_usize,
- 14 => trap_frame.a4 = time_usize,
- 15 => trap_frame.a5 = time_usize,
- 16 => trap_frame.a6 = time_usize,
- 17 => trap_frame.a7 = time_usize,
- 5 => trap_frame.t0 = time_usize,
- 6 => trap_frame.t1 = time_usize,
- 7 => trap_frame.t2 = time_usize,
- 28 => trap_frame.t3 = time_usize,
- 29 => trap_frame.t4 = time_usize,
- 30 => trap_frame.t5 = time_usize,
- 31 => trap_frame.t6 = time_usize,
- _ => panic!("invalid target"),
- }
- mepc::write(mepc::read().wrapping_add(4)); // 跳过指令
- } else {
- panic!("invalid instruction, mepc: {:016x?}, instruction: {:016x?}", mepc::read(), ins);
- }
- }
- cause => panic!(
- "Unhandled exception! mcause: {:?}, mepc: {:016x?}, mtval: {:016x?}",
- cause,
- mepc::read(),
- mtval::read()
- ),
- }
- }
|