|
@@ -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)
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|