Bläddra i källkod

Test kernel; illegal exception dispatch

luojia65 4 år sedan
förälder
incheckning
ef28118403

+ 7 - 0
Cargo.toml

@@ -5,3 +5,10 @@ members = [
     "platform/*",
     "test-kernel",
 ]
+
+# these profiles are required for test kernel, not RustSBI library itself
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"

+ 19 - 9
platform/qemu/justfile

@@ -1,8 +1,10 @@
 target := "riscv64imac-unknown-none-elf"
 mode := "debug"
 build-path := "../../target/" + target + "/" + mode + "/"
-m-firmware-file := build-path + "rustsbi-qemu"
-m-bin-file := build-path + "rustsbi-qemu.bin"
+rustsbi-elf := build-path + "rustsbi-qemu"
+rustsbi-bin := build-path + "rustsbi-qemu.bin"
+test-kernel-elf := build-path + "rustsbi-test-kernel"
+test-kernel-bin := build-path + "rustsbi-test-kernel.bin"
 
 objdump := "riscv64-unknown-elf-objdump"
 objcopy := "rust-objcopy --binary-architecture=riscv64"
@@ -10,33 +12,41 @@ gdb := "riscv64-unknown-elf-gdb"
 
 threads := "2"
 
-build: firmware
-    @{{objcopy}} {{m-firmware-file}} --strip-all -O binary {{m-bin-file}}
+build: rustsbi test-kernel
+    @{{objcopy}} {{rustsbi-elf}} --strip-all -O binary {{rustsbi-bin}}
 
-firmware:
+rustsbi:
     @cargo build --target={{target}}
 
+test-kernel:
+    @just -f "../../test-kernel/justfile" build
+
 qemu: build
     @qemu-system-riscv64 \
             -machine virt \
             -nographic \
             -bios none \
-            -device loader,file={{m-bin-file}},addr=0x80000000 \
+            -device loader,file={{rustsbi-bin}},addr=0x80000000 \
+            -device loader,file={{test-kernel-bin}},addr=0x80200000 \
             -smp threads={{threads}}
 
 run: build qemu
 
 asm: build
-    @{{objdump}} -D {{m-firmware-file}} | less
+    @{{objdump}} -D {{rustsbi-elf}} | less
 
 debug: build
     @qemu-system-riscv64 \
             -machine virt \
             -nographic \
             -bios none \
-            -device loader,file={{m-bin-file}},addr=0x80000000 \
+            -device loader,file={{rustsbi-bin}},addr=0x80000000 \
+            -device loader,file={{test-kernel-bin}},addr=0x80200000 \
             -smp threads={{threads}} \
             -gdb tcp::1234 -S
 
 gdb: 
-    @{{gdb}} --eval-command="file {{m-firmware-file}}" --eval-command="target remote localhost:1234"
+    @{{gdb}} --eval-command="file {{rustsbi-elf}}" --eval-command="target remote localhost:1234"
+
+gdb-kernel: 
+    @{{gdb}} --eval-command="file {{test-kernel-elf}}" --eval-command="target remote localhost:1234"

+ 18 - 5
platform/qemu/src/main.rs

@@ -19,9 +19,10 @@ use rustsbi::{print, println};
 use riscv::register::{
     mcause::{self, Exception, Interrupt, Trap},
     medeleg, mepc, mhartid, mideleg, mie, mip, misa::{self, MXL},
-    mstatus::{self, MPP},
+    mstatus::{self, MPP, SPP},
     mtval,
     mtvec::{self, TrapMode},
+    stvec,
 };
 
 #[global_allocator]
@@ -453,8 +454,8 @@ extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
                     _ => panic!("invalid target"),
                 }
                 mepc::write(mepc::read().wrapping_add(4)); // 跳过指令
-            } else { // can't emulate, raise invalid instruction to supervisor
-                // 出现非法指令异常,转发到特权层
+            } else if mstatus::read().mpp() != MPP::Machine { // can't emulate, raise invalid instruction to supervisor
+                // 出现非法指令异常,转发到S特权层
                 let cause: usize = 2; // Interrupt = 0, Exception Code = 2 (Illegal Exception)
                 let val: usize = mtval::read();
                 let epc: usize = mepc::read();
@@ -463,8 +464,20 @@ extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
                     csrw    stval, {val}
                     csrw    sepc, {epc}
                 ", cause = in(reg) cause, val = in(reg) val, epc = in(reg) epc) };
-                // todo: remove these following lines
-                // 先把“test-kernel”写完,功能完整后,删除下面几行
+                // 设置中断位
+                unsafe { 
+                    mstatus::set_mpp(MPP::Supervisor);
+                    mstatus::set_spp(SPP::Supervisor);
+                    if mstatus::read().sie() {
+                        mstatus::set_spie()
+                    }
+                    mstatus::clear_sie();
+                };
+                // 设置返回地址,返回到S层
+                // 注意,无论是Direct还是Vectored模式,非法指令异常永远属于异常,不需要处理中断向量,跳转到入口地址即可
+                mepc::write(stvec::read().address());
+            } else {
+                // 真·非法指令异常,是M层出现的
                 #[cfg(target_pointer_width = "64")]
                 panic!("invalid instruction, mepc: {:016x?}, instruction: {:016x?}", mepc::read(), ins);
                 #[cfg(target_pointer_width = "32")]

+ 4 - 0
test-kernel/.cargo/config.toml

@@ -0,0 +1,4 @@
+[target.riscv64imac-unknown-none-elf]
+rustflags = [
+    "-C", "link-arg=-Tlinker64.ld",
+]

+ 1 - 0
test-kernel/Cargo.toml

@@ -7,3 +7,4 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+riscv = "0.6"

+ 18 - 0
test-kernel/build.rs

@@ -0,0 +1,18 @@
+use std::env;
+use std::fs;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+
+    // Put the linker script somewhere the linker can find it
+    fs::File::create(out_dir.join("linker64.ld"))
+        .unwrap()
+        .write_all(include_bytes!("src/linker64.ld"))
+        .unwrap();
+    println!("cargo:rustc-link-search={}", out_dir.display());
+
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-changed=src/linker64.ld");
+}

+ 21 - 0
test-kernel/justfile

@@ -0,0 +1,21 @@
+target := "riscv64imac-unknown-none-elf"
+mode := "debug"
+build-path := "../target/" + target + "/" + mode + "/"
+test-kernel-elf := build-path + "rustsbi-test-kernel"
+test-kernel-bin := build-path + "rustsbi-test-kernel.bin"
+
+objdump := "riscv64-unknown-elf-objdump"
+objcopy := "rust-objcopy --binary-architecture=riscv64"
+size := "rust-size"
+
+build: firmware
+    @{{objcopy}} {{test-kernel-elf}} --strip-all -O binary {{test-kernel-bin}}
+
+firmware:
+    @cargo build --target={{target}}
+
+asm: build
+    @{{objdump}} -D {{test-kernel-elf}} | less
+
+size: build
+    @{{size}} -A -x {{test-kernel-elf}} 

+ 35 - 0
test-kernel/src/console.rs

@@ -0,0 +1,35 @@
+use crate::sbi::*;
+use core::fmt::{self, Write};
+
+struct Stdout;
+
+impl Write for Stdout {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        let mut buffer = [0u8; 4];
+        for c in s.chars() {
+            for code_point in c.encode_utf8(&mut buffer).as_bytes().iter() {
+                console_putchar(*code_point as usize);
+            }
+        }
+        Ok(())
+    }
+}
+
+#[allow(unused)]
+pub fn print(args: fmt::Arguments) {
+    Stdout.write_fmt(args).unwrap();
+}
+
+#[macro_export]
+macro_rules! print {
+    ($fmt: literal $(, $($arg: tt)+)?) => {
+        $crate::console::print(format_args!($fmt $(, $($arg)+)?));
+    }
+}
+
+#[macro_export]
+macro_rules! println {
+    ($fmt: literal $(, $($arg: tt)+)?) => {
+        $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
+    }
+}

+ 43 - 0
test-kernel/src/linker64.ld

@@ -0,0 +1,43 @@
+/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore      */
+
+/* Simple linker script for the ucore kernel.
+   See the GNU ld 'info' manual ("info ld") to learn the syntax. */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+BASE_ADDRESS = 0x80200000;
+
+SECTIONS
+{
+    /* Load the kernel at this address: "." means the current address */
+    . = BASE_ADDRESS;
+    start = .;
+
+    .text : ALIGN(4K) {
+        _stext = .;
+        *(.text.entry)
+        *(.text .text.*)
+        _etext = .;
+    }
+
+    .rodata : ALIGN(4K) {
+        _srodata = .;
+        *(.rodata .rodata.*)
+        _erodata = .;
+    }
+
+    .data : ALIGN(4K) {
+        _sdata = .;
+        *(.data .data.*)
+        _edata = .;
+    }
+
+    .bss (NOLOAD) : ALIGN(4K)  {
+        _sbss = .;
+        *(.sbss .bss .bss.*)
+        _ebss = .;
+    }
+
+    PROVIDE(end = .);
+}

+ 110 - 4
test-kernel/src/main.rs

@@ -1,6 +1,112 @@
-fn main() {
-    println!("Hello, world!");
+// A test kernel to test RustSBI function on all platforms
+#![feature(naked_functions, global_asm, asm, llvm_asm)]
+#![no_std]
+#![no_main]
+
+#[macro_use]
+mod console;
+mod sbi;
+
+use riscv::register::{sepc, stvec::{self, TrapMode}};
+use core::panic::PanicInfo;
+
+#[cfg_attr(not(test), panic_handler)]
+#[allow(unused)]
+fn panic(_info: &PanicInfo) -> ! {
+    loop {}
 }
 
-// A test kernel to test RustSBI function on all platforms
-// todo: make a list of functions we need to test
+const BOOT_STACK_SIZE: usize = 4096 * 4 * 8;
+
+static mut BOOT_STACK: [u8; BOOT_STACK_SIZE] = [0; BOOT_STACK_SIZE];
+
+#[naked]
+#[link_section = ".text.entry"] 
+#[export_name = "_start"]
+unsafe extern "C" fn entry() -> ! {
+    asm!("
+    # 1. set sp
+    # sp = bootstack + (hartid + 1) * 0x10000
+    add     t0, a0, 1
+    slli    t0, t0, 14
+1:  auipc   sp, %pcrel_hi({boot_stack})
+    addi    sp, sp, %pcrel_lo(1b)
+    add     sp, sp, t0
+
+    # 2. jump to rust_main (absolute address)
+1:  auipc   t0, %pcrel_hi({rust_main})
+    addi    t0, t0, %pcrel_lo(1b)
+    jr      t0
+    ", 
+    boot_stack = sym BOOT_STACK, 
+    rust_main = sym rust_main,
+    options(noreturn))
+}
+
+pub extern "C" fn rust_main(hartid: usize, dtb_pa: usize) -> ! {
+    println!("<< Test-kernel: Hart id = {}, DTB physical address = {:#x}", hartid, dtb_pa);
+    unsafe { stvec::write(start_trap as usize, TrapMode::Direct) };
+    println!(">> Test-kernel: Trigger illegal exception");
+    unsafe { asm!("unimp") };
+    println!("<< Test-kernel: SBI test success, shutdown");
+    sbi::shutdown()
+}
+
+#[naked]
+#[link_section = ".text"]
+unsafe extern "C" fn start_trap() {
+    asm!("
+.altmacro
+.macro STORE reg, offset
+    sd  \\reg, \\offset* {REGBYTES} (sp)
+.endm
+.macro LOAD reg, offset
+    ld  \\reg, \\offset* {REGBYTES} (sp)
+.endm
+    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    {rust_trap_exception}
+    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}
+    sret
+    ",
+    REGBYTES = const core::mem::size_of::<usize>(),
+    rust_trap_exception = sym rust_trap_exception,
+    options(noreturn))
+}
+
+pub extern "C" fn rust_trap_exception() {
+    println!("<< Test-kernel: Illegal exception");
+    sepc::write(sepc::read().wrapping_add(4));
+}

+ 41 - 0
test-kernel/src/sbi.rs

@@ -0,0 +1,41 @@
+#![allow(unused)]
+
+#[inline(always)]
+fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
+    let ret;
+    unsafe {
+        llvm_asm!("ecall"
+            : "={x10}" (ret)
+            : "{x10}" (arg0), "{x11}" (arg1), "{x12}" (arg2), "{x17}" (which)
+            : "memory"
+            : "volatile"); 
+    }
+    ret
+}
+
+const SBI_SET_TIMER: usize = 0;
+const SBI_CONSOLE_PUTCHAR: usize = 1;
+const SBI_CONSOLE_GETCHAR: usize = 2;
+const SBI_CLEAR_IPI: usize = 3;
+const SBI_SEND_IPI: usize = 4;
+const SBI_REMOTE_FENCE_I: usize = 5;
+const SBI_REMOTE_SFENCE_VMA: usize = 6;
+const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7;
+const SBI_SHUTDOWN: usize = 8;
+
+pub fn console_putchar(c: usize) {
+    sbi_call(SBI_CONSOLE_PUTCHAR, c, 0, 0);
+}
+
+pub fn console_getchar() -> usize {
+    sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
+}
+
+pub fn shutdown() -> ! {
+    sbi_call(SBI_SHUTDOWN, 0, 0, 0);
+    unreachable!()
+}
+
+pub fn set_timer(time: usize) {
+    sbi_call(SBI_SET_TIMER, time, 0, 0);
+}