|
@@ -0,0 +1,129 @@
|
|
|
+use core::fmt;
|
|
|
+use core::ops;
|
|
|
+use gimli::{AArch64, Register};
|
|
|
+
|
|
|
+#[repr(C)]
|
|
|
+#[derive(Clone, Default)]
|
|
|
+pub struct Context {
|
|
|
+ pub gp: [usize; 31],
|
|
|
+ pub sp: usize,
|
|
|
+ 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..=30 {
|
|
|
+ fmt.field(
|
|
|
+ AArch64::register_name(Register(i as _)).unwrap(),
|
|
|
+ &self.gp[i],
|
|
|
+ );
|
|
|
+ }
|
|
|
+ fmt.field("sp", &self.sp);
|
|
|
+ for i in 0..=31 {
|
|
|
+ fmt.field(
|
|
|
+ AArch64::register_name(Register((i + 64) 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..=30) => &self.gp[reg.0 as usize],
|
|
|
+ AArch64::SP => &self.sp,
|
|
|
+ Register(64..=95) => &self.fp[(reg.0 - 64) as usize],
|
|
|
+ _ => unimplemented!(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl ops::IndexMut<gimli::Register> for Context {
|
|
|
+ fn index_mut(&mut self, reg: Register) -> &mut usize {
|
|
|
+ match reg {
|
|
|
+ Register(0..=30) => &mut self.gp[reg.0 as usize],
|
|
|
+ AArch64::SP => &mut self.sp,
|
|
|
+ Register(64..=95) => &mut self.fp[(reg.0 - 64) as usize],
|
|
|
+ _ => unimplemented!(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[naked]
|
|
|
+pub extern "C-unwind" fn save_context() -> Context {
|
|
|
+ // No need to save caller-saved registers here.
|
|
|
+ unsafe {
|
|
|
+ asm!(
|
|
|
+ "
|
|
|
+ stp d8, d9, [x8, 0x140]
|
|
|
+ stp d10, d11, [x8, 0x150]
|
|
|
+ stp d12, d13, [x8, 0x160]
|
|
|
+ stp d14, d15, [x8, 0x170]
|
|
|
+
|
|
|
+ str x19, [x8, 0x98]
|
|
|
+ stp x20, x21, [x8, 0xA0]
|
|
|
+ stp x22, x23, [x8, 0xB0]
|
|
|
+ stp x24, x25, [x8, 0xC0]
|
|
|
+ stp x26, x27, [x8, 0xD0]
|
|
|
+ stp x28, x29, [x8, 0xE0]
|
|
|
+ mov x0, sp
|
|
|
+ stp x30, x0, [x8, 0xF0]
|
|
|
+
|
|
|
+ ret
|
|
|
+ ",
|
|
|
+ options(noreturn)
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[naked]
|
|
|
+pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
|
|
+ unsafe {
|
|
|
+ asm!(
|
|
|
+ "
|
|
|
+ ldp d0, d1, [x0, 0x100]
|
|
|
+ ldp d2, d3, [x0, 0x110]
|
|
|
+ ldp d4, d5, [x0, 0x120]
|
|
|
+ ldp d6, d7, [x0, 0x130]
|
|
|
+ ldp d8, d9, [x0, 0x140]
|
|
|
+ ldp d10, d11, [x0, 0x150]
|
|
|
+ ldp d12, d13, [x0, 0x160]
|
|
|
+ ldp d14, d15, [x0, 0x170]
|
|
|
+ ldp d16, d17, [x0, 0x180]
|
|
|
+ ldp d18, d19, [x0, 0x190]
|
|
|
+ ldp d20, d21, [x0, 0x1A0]
|
|
|
+ ldp d22, d23, [x0, 0x1B0]
|
|
|
+ ldp d24, d25, [x0, 0x1C0]
|
|
|
+ ldp d26, d27, [x0, 0x1D0]
|
|
|
+ ldp d28, d29, [x0, 0x1E0]
|
|
|
+ ldp d30, d31, [x0, 0x1F0]
|
|
|
+
|
|
|
+ ldp x2, x3, [x0, 0x10]
|
|
|
+ ldp x4, x5, [x0, 0x20]
|
|
|
+ ldp x6, x7, [x0, 0x30]
|
|
|
+ ldp x8, x9, [x0, 0x40]
|
|
|
+ ldp x10, x11, [x0, 0x50]
|
|
|
+ ldp x12, x13, [x0, 0x60]
|
|
|
+ ldp x14, x15, [x0, 0x70]
|
|
|
+ ldp x16, x17, [x0, 0x80]
|
|
|
+ ldp x18, x19, [x0, 0x90]
|
|
|
+ ldp x20, x21, [x0, 0xA0]
|
|
|
+ ldp x22, x23, [x0, 0xB0]
|
|
|
+ ldp x24, x25, [x0, 0xC0]
|
|
|
+ ldp x26, x27, [x0, 0xD0]
|
|
|
+ ldp x28, x29, [x0, 0xE0]
|
|
|
+ ldp x30, x1, [x0, 0xF0]
|
|
|
+ mov sp, x1
|
|
|
+
|
|
|
+ ldp x0, x1, [x0, 0x00]
|
|
|
+ ret
|
|
|
+ ",
|
|
|
+ options(noreturn)
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|