|
@@ -0,0 +1,195 @@
|
|
|
+use core::fmt;
|
|
|
+use core::ops;
|
|
|
+use gimli::{Register, RiscV};
|
|
|
+
|
|
|
+#[repr(C)]
|
|
|
+#[derive(Clone, Default)]
|
|
|
+pub struct Context {
|
|
|
+ pub gp: [usize; 32],
|
|
|
+ pub fp: [usize; 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]);
|
|
|
+ }
|
|
|
+ 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],
|
|
|
+ Register(32..=63) => &self.fp[(reg.0 - 32) as usize],
|
|
|
+ _ => 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],
|
|
|
+ Register(32..=63) => &mut self.fp[(reg.0 - 32) as usize],
|
|
|
+ _ => unimplemented!(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+macro_rules! code {
|
|
|
+ (save_gp) => {
|
|
|
+ "
|
|
|
+ sd x0, 0x00(a0)
|
|
|
+ sd ra, 0x08(a0)
|
|
|
+ sd sp, 0x10(a0)
|
|
|
+ sd gp, 0x18(a0)
|
|
|
+ sd tp, 0x20(a0)
|
|
|
+ sd s0, 0x40(a0)
|
|
|
+ sd s1, 0x48(a0)
|
|
|
+ sd s2, 0x90(a0)
|
|
|
+ sd s3, 0x98(a0)
|
|
|
+ sd s4, 0xA0(a0)
|
|
|
+ sd s5, 0xA8(a0)
|
|
|
+ sd s6, 0xB0(a0)
|
|
|
+ sd s7, 0xB8(a0)
|
|
|
+ sd s8, 0xC0(a0)
|
|
|
+ sd s9, 0xC8(a0)
|
|
|
+ sd s10, 0xD0(a0)
|
|
|
+ sd s11, 0xD8(a0)
|
|
|
+ "
|
|
|
+ };
|
|
|
+ (save_fp) => {
|
|
|
+ "
|
|
|
+ fsd fs0, 0x140(a0)
|
|
|
+ fsd fs1, 0x148(a0)
|
|
|
+ fsd fs2, 0x190(a0)
|
|
|
+ fsd fs3, 0x198(a0)
|
|
|
+ fsd fs4, 0x1A0(a0)
|
|
|
+ fsd fs5, 0x1A8(a0)
|
|
|
+ fsd fs6, 0x1B0(a0)
|
|
|
+ fsd fs7, 0x1B8(a0)
|
|
|
+ fsd fs8, 0x1C0(a0)
|
|
|
+ fsd fs9, 0x1C8(a0)
|
|
|
+ fsd fs10, 0x1D0(a0)
|
|
|
+ fsd fs11, 0x1D8(a0)
|
|
|
+ "
|
|
|
+ };
|
|
|
+ (restore_gp) => {
|
|
|
+ "
|
|
|
+ ld ra, 0x08(a0)
|
|
|
+ ld sp, 0x10(a0)
|
|
|
+ ld gp, 0x18(a0)
|
|
|
+ ld tp, 0x20(a0)
|
|
|
+ ld t0, 0x28(a0)
|
|
|
+ ld t1, 0x30(a0)
|
|
|
+ ld t2, 0x38(a0)
|
|
|
+ ld s0, 0x40(a0)
|
|
|
+ ld s1, 0x48(a0)
|
|
|
+ ld a1, 0x58(a0)
|
|
|
+ ld a2, 0x60(a0)
|
|
|
+ ld a3, 0x68(a0)
|
|
|
+ ld a4, 0x70(a0)
|
|
|
+ ld a5, 0x78(a0)
|
|
|
+ ld a6, 0x80(a0)
|
|
|
+ ld a7, 0x88(a0)
|
|
|
+ ld s2, 0x90(a0)
|
|
|
+ ld s3, 0x98(a0)
|
|
|
+ ld s4, 0xA0(a0)
|
|
|
+ ld s5, 0xA8(a0)
|
|
|
+ ld s6, 0xB0(a0)
|
|
|
+ ld s7, 0xB8(a0)
|
|
|
+ ld s8, 0xC0(a0)
|
|
|
+ ld s9, 0xC8(a0)
|
|
|
+ ld s10, 0xD0(a0)
|
|
|
+ ld s11, 0xD8(a0)
|
|
|
+ ld t3, 0xE0(a0)
|
|
|
+ ld t4, 0xE8(a0)
|
|
|
+ ld t5, 0xF0(a0)
|
|
|
+ ld t6, 0xF8(a0)
|
|
|
+ "
|
|
|
+ };
|
|
|
+ (restore_fp) => {
|
|
|
+ "
|
|
|
+ fld ft0, 0x100(a0)
|
|
|
+ fld ft1, 0x108(a0)
|
|
|
+ fld ft2, 0x110(a0)
|
|
|
+ fld ft3, 0x118(a0)
|
|
|
+ fld ft4, 0x120(a0)
|
|
|
+ fld ft5, 0x128(a0)
|
|
|
+ fld ft6, 0x130(a0)
|
|
|
+ fld ft7, 0x138(a0)
|
|
|
+ fld fs0, 0x140(a0)
|
|
|
+ fld fs1, 0x148(a0)
|
|
|
+ fld fa0, 0x150(a0)
|
|
|
+ fld fa1, 0x158(a0)
|
|
|
+ fld fa2, 0x160(a0)
|
|
|
+ fld fa3, 0x168(a0)
|
|
|
+ fld fa4, 0x170(a0)
|
|
|
+ fld fa5, 0x178(a0)
|
|
|
+ fld fa6, 0x180(a0)
|
|
|
+ fld fa7, 0x188(a0)
|
|
|
+ fld fs2, 0x190(a0)
|
|
|
+ fld fs3, 0x198(a0)
|
|
|
+ fld fs4, 0x1A0(a0)
|
|
|
+ fld fs5, 0x1A8(a0)
|
|
|
+ fld fs6, 0x1B0(a0)
|
|
|
+ fld fs7, 0x1B8(a0)
|
|
|
+ fld fs8, 0x1C0(a0)
|
|
|
+ fld fs9, 0x1C8(a0)
|
|
|
+ fld fs10, 0x1D0(a0)
|
|
|
+ fld fs11, 0x1D8(a0)
|
|
|
+ fld ft8, 0x1E0(a0)
|
|
|
+ fld ft9, 0x1E8(a0)
|
|
|
+ fld ft10, 0x1F0(a0)
|
|
|
+ fld ft11, 0x1F8(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), "ld a0, 0x50(a0)\nret"),
|
|
|
+ options(noreturn)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ #[cfg(not(target_feature = "d"))]
|
|
|
+ unsafe {
|
|
|
+ asm!(
|
|
|
+ concat!(code!(restore_gp), "ld a0, 0x50(a0)\nret"),
|
|
|
+ options(noreturn)
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|