From f86b061470d41f0e804eedeb101b68a52313c3d8 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sat, 23 Sep 2023 20:30:01 +0800 Subject: [PATCH] feat: add trampoline definition --- Cargo.lock | 17 ++++ Cargo.toml | 7 +- build.rs | 3 +- src/arch/riscv/asm/trap32.S | 123 ++++++++++++++++++++++++++ src/arch/riscv/asm/trap64.S | 123 ++++++++++++++++++++++++++ src/arch/riscv/layout.rs | 2 + src/arch/riscv/{boot => }/linker64.ld | 9 ++ src/arch/riscv/mod.rs | 3 + src/arch/riscv/trap.rs | 37 ++++++++ src/lib.rs | 2 + 10 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 src/arch/riscv/asm/trap32.S create mode 100644 src/arch/riscv/asm/trap64.S create mode 100644 src/arch/riscv/layout.rs rename src/arch/riscv/{boot => }/linker64.ld (77%) create mode 100644 src/arch/riscv/trap.rs diff --git a/Cargo.lock b/Cargo.lock index f00a32b..e8fc13c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + [[package]] name = "log" version = "0.4.20" @@ -53,6 +62,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "static_assertions" version = "1.1.0" @@ -63,8 +78,10 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" name = "tiny_os" version = "0.1.0" dependencies = [ + "lazy_static", "log", "sbi-rt", + "static_assertions", "uart_16550", ] diff --git a/Cargo.toml b/Cargo.toml index 1cad101..bac56e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [features] default = ["arch_riscv64", "board_virt"] arch_riscv64 = [] +arch_riscv32 = [] arch_arm = [] arch_x86 = [] board_default = [] @@ -21,6 +22,8 @@ panic = "abort" panic = "abort" [dependencies] -sbi-rt = { version = "0.0.2", features = ["legacy"] } -uart_16550 = "0.3" +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } log = "0.4" +sbi-rt = { version = "0.0.2", features = ["legacy"] } +static_assertions = "1.1.0" +uart_16550 = "0.3" diff --git a/build.rs b/build.rs index 85e7a04..e8fd160 100644 --- a/build.rs +++ b/build.rs @@ -8,12 +8,13 @@ fn main() { const TARGET_CONFIGURATIONS: &[TargetConfiguration] = &[TargetConfiguration { target: "riscv64", - lds: "src/arch/riscv/boot/linker64.ld", + lds: "src/arch/riscv/linker64.ld", }]; let target = std::env::var("TARGET").unwrap(); for cfg in TARGET_CONFIGURATIONS { if target.starts_with(cfg.target) { + println!("cargo:rerun-if-changed={}", cfg.lds); println!("cargo:rustc-link-arg=-T{}", cfg.lds); return; } diff --git a/src/arch/riscv/asm/trap32.S b/src/arch/riscv/asm/trap32.S new file mode 100644 index 0000000..628fdad --- /dev/null +++ b/src/arch/riscv/asm/trap32.S @@ -0,0 +1,123 @@ +.section .trampoline_section + +.global trampoline +trampoline: + +.align 4 + +.global __user2kernel +__user2kernel: + # load trapframe + csrw sscratch, a0 # save a0, will be saved later + li a0, {TRAPFRAME} # TRAPFRAME will be mapped to the same virtual address + + # save GPRs + sd ra, 0(a0) + sd sp, 4(a0) + sd gp, 8(a0) + sd tp, 12(a0) + sd t0, 16(a0) + sd t1, 20(a0) + sd t2, 24(a0) + sd s0, 28(a0) + sd s1, 32(a0) + #sd a0, 36(a0) + sd a1, 40(a0) + sd a2, 44(a0) + sd a3, 48(a0) + sd a4, 52(a0) + sd a5, 56(a0) + sd a6, 60(a0) + sd a7, 64(a0) + sd s2, 68(a0) + sd s3, 72(a0) + sd s4, 76(a0) + sd s5, 80(a0) + sd s6, 84(a0) + sd s7, 88(a0) + sd s8, 92(a0) + sd s9, 96(a0) + sd s10, 100(a0) + sd s11, 104(a0) + sd t3, 108(a0) + sd t4, 112(a0) + sd t5, 116(a0) + sd t6, 120(a0) + + # save a0 + csrr t0, sscratch + sd t0, 36(a0) + + # save user epc / sstatus + csrr t0, sepc + csrr t1, sstatus + sd t0, 124(a0) + sd t1, 128(a0) + + # restore kernel env + ld sp, 132(a0) # kernel sp + ld tp, 136(a0) # kernel tp + ld t0, 140(a0) # trap handler + ld t1, 144(a0) # page table + + # load kernel page table + sfence.vma zero, zero + csrw satp, t1 + sfence.vma zero, zero + + # jump to trap handler + jr t0 + +.global __kernel2user +__kernel2user: + # restore user page table (a0) + sfence.vma zero, zero + csrw satp, a0 + sfence.vma zero, zero + + li a0, {TRAPFRAME} + + # restore user epc / sstatus + ld t0, 124(a0) + ld t1, 128(a0) + csrw sepc, t0 + csrw sstatus, t1 + + # restore GPRs + ld ra, 0(a0) + ld sp, 4(a0) + ld gp, 8(a0) + ld tp, 12(a0) + ld t0, 16(a0) + ld t1, 20(a0) + ld t2, 24(a0) + ld s0, 28(a0) + ld s1, 32(a0) + #ld a0, 36(a0) + ld a1, 40(a0) + ld a2, 44(a0) + ld a3, 48(a0) + ld a4, 52(a0) + ld a5, 56(a0) + ld a6, 60(a0) + ld a7, 64(a0) + ld s2, 68(a0) + ld s3, 72(a0) + ld s4, 76(a0) + ld s5, 80(a0) + ld s6, 84(a0) + ld s7, 88(a0) + ld s8, 92(a0) + ld s9, 96(a0) + ld s10, 100(a0) + ld s11, 104(a0) + ld t3, 108(a0) + ld t4, 112(a0) + ld t5, 116(a0) + ld t6, 120(a0) + ld a0, 36(a0) + + # go back to usermode + sret + +# vim:set ts=8 noexpandtab: diff --git a/src/arch/riscv/asm/trap64.S b/src/arch/riscv/asm/trap64.S new file mode 100644 index 0000000..ab368b0 --- /dev/null +++ b/src/arch/riscv/asm/trap64.S @@ -0,0 +1,123 @@ +.section .trampoline_section + +.global trampoline +trampoline: + +.align 4 + +.global __user2kernel +__user2kernel: + # load trapframe + csrw sscratch, a0 # save a0, will be saved later + li a0, {TRAPFRAME} # TRAPFRAME will be mapped to the same virtual address + + # save GPRs + sd ra, 0(a0) + sd sp, 8(a0) + sd gp, 16(a0) + sd tp, 24(a0) + sd t0, 32(a0) + sd t1, 40(a0) + sd t2, 48(a0) + sd s0, 56(a0) + sd s1, 64(a0) + #sd a0, 72(a0) + sd a1, 80(a0) + sd a2, 88(a0) + sd a3, 96(a0) + sd a4, 104(a0) + sd a5, 112(a0) + sd a6, 120(a0) + sd a7, 128(a0) + sd s2, 136(a0) + sd s3, 144(a0) + sd s4, 152(a0) + sd s5, 160(a0) + sd s6, 168(a0) + sd s7, 176(a0) + sd s8, 184(a0) + sd s9, 192(a0) + sd s10, 200(a0) + sd s11, 208(a0) + sd t3, 216(a0) + sd t4, 224(a0) + sd t5, 232(a0) + sd t6, 240(a0) + + # save a0 + csrr t0, sscratch + sd t0, 72(a0) + + # save user epc / sstatus + csrr t0, sepc + csrr t1, sstatus + sd t0, 248(a0) + sd t1, 256(a0) + + # restore kernel env + ld sp, 264(a0) # kernel sp + ld tp, 272(a0) # kernel tp + ld t0, 280(a0) # trap handler + ld t1, 288(a0) # page table + + # load kernel page table + sfence.vma zero, zero + csrw satp, t1 + sfence.vma zero, zero + + # jump to trap handler + jr t0 + +.global __kernel2user +__kernel2user: + # restore user page table (a0) + sfence.vma zero, zero + csrw satp, a0 + sfence.vma zero, zero + + li a0, {TRAPFRAME} + + # restore user epc / sstatus + ld t0, 248(a0) + ld t1, 256(a0) + csrw sepc, t0 + csrw sstatus, t1 + + # restore GPRs + ld ra, 0(a0) + ld sp, 8(a0) + ld gp, 16(a0) + ld tp, 24(a0) + ld t0, 32(a0) + ld t1, 40(a0) + ld t2, 48(a0) + ld s0, 56(a0) + ld s1, 64(a0) + #ld a0, 72(a0) + ld a1, 80(a0) + ld a2, 88(a0) + ld a3, 96(a0) + ld a4, 104(a0) + ld a5, 112(a0) + ld a6, 120(a0) + ld a7, 128(a0) + ld s2, 136(a0) + ld s3, 144(a0) + ld s4, 152(a0) + ld s5, 160(a0) + ld s6, 168(a0) + ld s7, 176(a0) + ld s8, 184(a0) + ld s9, 192(a0) + ld s10, 200(a0) + ld s11, 208(a0) + ld t3, 216(a0) + ld t4, 224(a0) + ld t5, 232(a0) + ld t6, 240(a0) + ld a0, 72(a0) + + # go back to usermode + sret + +# vim:set ts=8 noexpandtab: diff --git a/src/arch/riscv/layout.rs b/src/arch/riscv/layout.rs new file mode 100644 index 0000000..906b187 --- /dev/null +++ b/src/arch/riscv/layout.rs @@ -0,0 +1,2 @@ +// TODO: currently a dummy value, figure out our memory layout +pub const TRAPFRAME: usize = 0x8000_0000; diff --git a/src/arch/riscv/boot/linker64.ld b/src/arch/riscv/linker64.ld similarity index 77% rename from src/arch/riscv/boot/linker64.ld rename to src/arch/riscv/linker64.ld index 1c24a78..fee37f6 100644 --- a/src/arch/riscv/boot/linker64.ld +++ b/src/arch/riscv/linker64.ld @@ -14,6 +14,15 @@ SECTIONS { __text_start = .; *(.text.entry) *(.text .text.*) + + . = ALIGN(0x1000); + __trampoline_start = .; + *(.trampoline_section) + . = ALIGN(0x1000); + __trampoline_end = .; + + ASSERT(__trampoline_end - __trampoline_start == 0x1000, "trampoline larger than one page"); + __text_end = .; } > DRAM diff --git a/src/arch/riscv/mod.rs b/src/arch/riscv/mod.rs index ed61d40..a2b9f71 100644 --- a/src/arch/riscv/mod.rs +++ b/src/arch/riscv/mod.rs @@ -2,6 +2,9 @@ #[path = "board/virt/mod.rs"] mod board; +mod layout; + pub mod entry; pub mod io; pub mod lowlevel; +pub mod trap; diff --git a/src/arch/riscv/trap.rs b/src/arch/riscv/trap.rs new file mode 100644 index 0000000..7107d7e --- /dev/null +++ b/src/arch/riscv/trap.rs @@ -0,0 +1,37 @@ +use lazy_static::lazy_static; +#[cfg(feature = "arch_riscv64")] +core::arch::global_asm!( + include_str!("./asm/trap64.S"), + TRAPFRAME = const super::layout::TRAPFRAME +); + +#[cfg(feature = "arch_riscv32")] +core::arch::global_asm!( + include_str!("./asm/trap32.S"), + TRAPFRAME = const super::layout::TRAPFRAME +); + +extern "C" { + pub fn __user2kernel(); + pub fn __kernel2user(ctx: *mut TrapContext); +} + +// TODO: remove this when we have a real context switch +lazy_static! { + pub static ref __DUMMY: usize = unsafe { + __user2kernel(); + __kernel2user(core::ptr::null_mut()); + 42 + }; +} + +#[repr(C)] +pub struct TrapContext { + pub gprs: [usize; 31], // GPRs exclude zero + pub user_sepc: usize, // 248/124 user program counter + pub user_sstatus: usize, // 256/128 user status register + pub kernel_sp: usize, // 264/132 kernel stack pointer + pub kernel_tp: usize, // 272/136 kernel tp + pub kernel_trap: usize, // 280/140 kernel trap handler + pub kernel_satp: usize, // 288/144 kernel page table +} diff --git a/src/lib.rs b/src/lib.rs index c3ae463..3df8733 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ #![feature(fmt_internals)] #![feature(stmt_expr_attributes)] +extern crate static_assertions; + // arch pub mod arch;