Quellcode durchsuchen

Add RISC-V RV32 support

Taiki Endo vor 2 Jahren
Ursprung
Commit
c88a9016fc
4 geänderte Dateien mit 213 neuen und 1 gelöschten Zeilen
  1. 1 1
      README.md
  2. 6 0
      src/unwinder/arch/mod.rs
  3. 203 0
      src/unwinder/arch/riscv32.rs
  4. 3 0
      src/unwinder/arch/riscv64.rs

+ 1 - 1
README.md

@@ -9,7 +9,7 @@ This library serves two purposes:
 1. Provide a pure Rust alternative to libgcc_eh or libunwind.
 2. Provide easier unwinding support for `#![no_std]` targets.
 
-Currently supports x86_64, x86, RV64 and AArch64.
+Currently supports x86_64, x86, RV64, RV32 and AArch64.
 
 ## Unwinder
 

+ 6 - 0
src/unwinder/arch/mod.rs

@@ -13,6 +13,11 @@ mod riscv64;
 #[cfg(target_arch = "riscv64")]
 pub use riscv64::*;
 
+#[cfg(target_arch = "riscv32")]
+mod riscv32;
+#[cfg(target_arch = "riscv32")]
+pub use riscv32::*;
+
 #[cfg(target_arch = "aarch64")]
 mod aarch64;
 #[cfg(target_arch = "aarch64")]
@@ -22,6 +27,7 @@ pub use aarch64::*;
     target_arch = "x86_64",
     target_arch = "x86",
     target_arch = "riscv64",
+    target_arch = "riscv32",
     target_arch = "aarch64"
 )))]
 compile_error!("Current architecture is not supported");

+ 203 - 0
src/unwinder/arch/riscv32.rs

@@ -0,0 +1,203 @@
+use core::arch::asm;
+use core::fmt;
+use core::ops;
+use gimli::{Register, RiscV};
+
+// Match DWARF_FRAME_REGISTERS in libgcc
+pub const MAX_REG_RULES: usize = 65;
+
+#[cfg(all(target_feature = "f", not(target_feature = "d")))]
+compile_error!("RISC-V with only F extension is not supported");
+
+#[repr(C)]
+#[derive(Clone, Default)]
+pub struct Context {
+    pub gp: [usize; 32],
+    #[cfg(target_feature = "d")]
+    pub fp: [u64; 32],
+}
+
+impl fmt::Debug for Context {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut fmt = fmt.debug_struct("Context");
+        for i in 0..=31 {
+            fmt.field(RiscV::register_name(Register(i as _)).unwrap(), &self.gp[i]);
+        }
+        #[cfg(target_feature = "d")]
+        for i in 0..=31 {
+            fmt.field(
+                RiscV::register_name(Register((i + 32) as _)).unwrap(),
+                &self.fp[i],
+            );
+        }
+        fmt.finish()
+    }
+}
+
+impl ops::Index<Register> for Context {
+    type Output = usize;
+
+    fn index(&self, reg: Register) -> &usize {
+        match reg {
+            Register(0..=31) => &self.gp[reg.0 as usize],
+            // We cannot support indexing fp here. It is 64-bit if D extension is implemented,
+            // and 32-bit if only F extension is implemented.
+            _ => unimplemented!(),
+        }
+    }
+}
+
+impl ops::IndexMut<gimli::Register> for Context {
+    fn index_mut(&mut self, reg: Register) -> &mut usize {
+        match reg {
+            Register(0..=31) => &mut self.gp[reg.0 as usize],
+            // We cannot support indexing fp here. It is 64-bit if D extension is implemented,
+            // and 32-bit if only F extension is implemented.
+            _ => unimplemented!(),
+        }
+    }
+}
+
+macro_rules! code {
+    (save_gp) => {
+        "
+        sw x0, 0x00(a0)
+        sw ra, 0x04(a0)
+        sw sp, 0x08(a0)
+        sw gp, 0x0C(a0)
+        sw tp, 0x10(a0)
+        sw s0, 0x20(a0)
+        sw s1, 0x24(a0)
+        sw s2, 0x48(a0)
+        sw s3, 0x4C(a0)
+        sw s4, 0x50(a0)
+        sw s5, 0x54(a0)
+        sw s6, 0x58(a0)
+        sw s7, 0x5C(a0)
+        sw s8, 0x60(a0)
+        sw s9, 0x64(a0)
+        sw s10, 0x68(a0)
+        sw s11, 0x6C(a0)
+        "
+    };
+    (save_fp) => {
+        "
+        fsd fs0, 0xC0(a0)
+        fsd fs1, 0xC8(a0)
+        fsd fs2, 0x110(a0)
+        fsd fs3, 0x118(a0)
+        fsd fs4, 0x120(a0)
+        fsd fs5, 0x128(a0)
+        fsd fs6, 0x130(a0)
+        fsd fs7, 0x138(a0)
+        fsd fs8, 0x140(a0)
+        fsd fs9, 0x148(a0)
+        fsd fs10, 0x150(a0)
+        fsd fs11, 0x158(a0)
+        "
+    };
+    (restore_gp) => {
+        "
+        lw ra, 0x04(a0)
+        lw sp, 0x08(a0)
+        lw gp, 0x0C(a0)
+        lw tp, 0x10(a0)
+        lw t0, 0x14(a0)
+        lw t1, 0x18(a0)
+        lw t2, 0x1C(a0)
+        lw s0, 0x20(a0)
+        lw s1, 0x24(a0)
+        lw a1, 0x2C(a0)
+        lw a2, 0x30(a0)
+        lw a3, 0x34(a0)
+        lw a4, 0x38(a0)
+        lw a5, 0x3C(a0)
+        lw a6, 0x40(a0)
+        lw a7, 0x44(a0)
+        lw s2, 0x48(a0)
+        lw s3, 0x4C(a0)
+        lw s4, 0x50(a0)
+        lw s5, 0x54(a0)
+        lw s6, 0x58(a0)
+        lw s7, 0x5C(a0)
+        lw s8, 0x60(a0)
+        lw s9, 0x64(a0)
+        lw s10, 0x68(a0)
+        lw s11, 0x6C(a0)
+        lw t3, 0x70(a0)
+        lw t4, 0x74(a0)
+        lw t5, 0x78(a0)
+        lw t6, 0x7C(a0)
+        "
+    };
+    (restore_fp) => {
+        "
+        fld ft0, 0x80(a0)
+        fld ft1, 0x88(a0)
+        fld ft2, 0x90(a0)
+        fld ft3, 0x98(a0)
+        fld ft4, 0xA0(a0)
+        fld ft5, 0xA8(a0)
+        fld ft6, 0xB0(a0)
+        fld ft7, 0xB8(a0)
+        fld fs0, 0xC0(a0)
+        fld fs1, 0xC8(a0)
+        fld fa0, 0xD0(a0)
+        fld fa1, 0xD8(a0)
+        fld fa2, 0xE0(a0)
+        fld fa3, 0xE8(a0)
+        fld fa4, 0xF0(a0)
+        fld fa5, 0xF8(a0)
+        fld fa6, 0x100(a0)
+        fld fa7, 0x108(a0)
+        fld fs2, 0x110(a0)
+        fld fs3, 0x118(a0)
+        fld fs4, 0x120(a0)
+        fld fs5, 0x128(a0)
+        fld fs6, 0x130(a0)
+        fld fs7, 0x138(a0)
+        fld fs8, 0x140(a0)
+        fld fs9, 0x148(a0)
+        fld fs10, 0x150(a0)
+        fld fs11, 0x158(a0)
+        fld ft8, 0x160(a0)
+        fld ft9, 0x168(a0)
+        fld ft10, 0x170(a0)
+        fld ft11, 0x178(a0)
+        "
+    };
+}
+
+#[naked]
+pub extern "C-unwind" fn save_context() -> Context {
+    // No need to save caller-saved registers here.
+    #[cfg(target_feature = "d")]
+    unsafe {
+        asm!(
+            concat!(code!(save_gp), code!(save_fp), "ret"),
+            options(noreturn)
+        );
+    }
+    #[cfg(not(target_feature = "d"))]
+    unsafe {
+        asm!(concat!(code!(save_gp), "ret"), options(noreturn));
+    }
+}
+
+#[naked]
+pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
+    #[cfg(target_feature = "d")]
+    unsafe {
+        asm!(
+            concat!(code!(restore_fp), code!(restore_gp), "lw a0, 0x28(a0)\nret"),
+            options(noreturn)
+        );
+    }
+    #[cfg(not(target_feature = "d"))]
+    unsafe {
+        asm!(
+            concat!(code!(restore_gp), "lw a0, 0x28(a0)\nret"),
+            options(noreturn)
+        );
+    }
+}

+ 3 - 0
src/unwinder/arch/riscv64.rs

@@ -6,6 +6,9 @@ use gimli::{Register, RiscV};
 // Match DWARF_FRAME_REGISTERS in libgcc
 pub const MAX_REG_RULES: usize = 65;
 
+#[cfg(all(target_feature = "f", not(target_feature = "d")))]
+compile_error!("RISC-V with only F extension is not supported");
+
 #[repr(C)]
 #[derive(Clone, Default)]
 pub struct Context {