use crate::syscall::IntRegisters; #[derive(Default)] #[repr(packed)] pub struct ScratchRegisters { pub x0: usize, pub x1: usize, pub x2: usize, pub x3: usize, pub x4: usize, pub x5: usize, pub x6: usize, pub x7: usize, pub x8: usize, pub x9: usize, pub x10: usize, pub x11: usize, pub x12: usize, pub x13: usize, pub x14: usize, pub x15: usize, pub x16: usize, pub x17: usize, pub x18: usize, pub padding: usize, } impl ScratchRegisters { pub fn dump(&self) { println!("X0: {:>016X}", { self.x0 }); println!("X1: {:>016X}", { self.x1 }); println!("X2: {:>016X}", { self.x2 }); println!("X3: {:>016X}", { self.x3 }); println!("X4: {:>016X}", { self.x4 }); println!("X5: {:>016X}", { self.x5 }); println!("X6: {:>016X}", { self.x6 }); println!("X7: {:>016X}", { self.x7 }); println!("X8: {:>016X}", { self.x8 }); println!("X9: {:>016X}", { self.x9 }); println!("X10: {:>016X}", { self.x10 }); println!("X11: {:>016X}", { self.x11 }); println!("X12: {:>016X}", { self.x12 }); println!("X13: {:>016X}", { self.x13 }); println!("X14: {:>016X}", { self.x14 }); println!("X15: {:>016X}", { self.x15 }); println!("X16: {:>016X}", { self.x16 }); println!("X17: {:>016X}", { self.x17 }); println!("X18: {:>016X}", { self.x18 }); } } #[derive(Default)] #[repr(packed)] pub struct PreservedRegisters { //TODO: is X30 a preserved register? pub x19: usize, pub x20: usize, pub x21: usize, pub x22: usize, pub x23: usize, pub x24: usize, pub x25: usize, pub x26: usize, pub x27: usize, pub x28: usize, pub x29: usize, pub x30: usize, } impl PreservedRegisters { pub fn dump(&self) { println!("X19: {:>016X}", { self.x19 }); println!("X20: {:>016X}", { self.x20 }); println!("X21: {:>016X}", { self.x21 }); println!("X22: {:>016X}", { self.x22 }); println!("X23: {:>016X}", { self.x23 }); println!("X24: {:>016X}", { self.x24 }); println!("X25: {:>016X}", { self.x25 }); println!("X26: {:>016X}", { self.x26 }); println!("X27: {:>016X}", { self.x27 }); println!("X28: {:>016X}", { self.x28 }); println!("X29: {:>016X}", { self.x29 }); println!("X30: {:>016X}", { self.x30 }); } } #[derive(Default)] #[repr(packed)] pub struct IretRegisters { // occurred // The exception vector disambiguates at which EL the interrupt pub sp_el0: usize, // Shouldn't be used if interrupt occurred at EL1 pub esr_el1: usize, pub spsr_el1: usize, pub elr_el1: usize, } impl IretRegisters { pub fn dump(&self) { println!("ELR_EL1: {:>016X}", { self.elr_el1 }); println!("SPSR_EL1: {:>016X}", { self.spsr_el1 }); println!("ESR_EL1: {:>016X}", { self.esr_el1 }); println!("SP_EL0: {:>016X}", { self.sp_el0 }); } } #[derive(Default)] #[repr(packed)] pub struct InterruptStack { pub iret: IretRegisters, pub scratch: ScratchRegisters, pub preserved: PreservedRegisters, } impl InterruptStack { pub fn setup_minimal(&mut self, ip: usize, _singlestep: bool) { self.set_instr_pointer(ip); } pub fn set_stack_pointer(&mut self, sp: usize) { self.iret.sp_el0 = sp; } pub fn stack_pointer(&self) -> usize { self.iret.sp_el0 } pub fn set_instr_pointer(&mut self, ip: usize) { self.iret.elr_el1 = ip; } // TODO: This can maybe be done in userspace? pub fn set_syscall_ret_reg(&mut self, ret: usize) { self.scratch.x0 = ret; } pub fn dump(&self) { self.iret.dump(); self.scratch.dump(); self.preserved.dump(); } /// Saves all registers to a struct used by the proc: /// scheme to read/write registers. pub fn save(&self, all: &mut IntRegisters) { /*TODO: aarch64 registers all.elr_el1 = self.iret.elr_el1; all.spsr_el1 = self.iret.spsr_el1; all.esr_el1 = self.iret.esr_el1; all.sp_el0 = self.iret.sp_el0; all.padding = 0; */ all.x30 = self.preserved.x30; all.x29 = self.preserved.x29; all.x28 = self.preserved.x28; all.x27 = self.preserved.x27; all.x26 = self.preserved.x26; all.x25 = self.preserved.x25; all.x24 = self.preserved.x24; all.x23 = self.preserved.x23; all.x22 = self.preserved.x22; all.x21 = self.preserved.x21; all.x20 = self.preserved.x20; all.x19 = self.preserved.x19; all.x18 = self.scratch.x18; all.x17 = self.scratch.x17; all.x16 = self.scratch.x16; all.x15 = self.scratch.x15; all.x14 = self.scratch.x14; all.x13 = self.scratch.x13; all.x12 = self.scratch.x12; all.x11 = self.scratch.x11; all.x10 = self.scratch.x10; all.x9 = self.scratch.x9; all.x8 = self.scratch.x8; all.x7 = self.scratch.x7; all.x6 = self.scratch.x6; all.x5 = self.scratch.x5; all.x4 = self.scratch.x4; all.x3 = self.scratch.x3; all.x2 = self.scratch.x2; all.x1 = self.scratch.x1; all.x0 = self.scratch.x0; } /// Loads all registers from a struct used by the proc: /// scheme to read/write registers. pub fn load(&mut self, all: &IntRegisters) { /*TODO: aarch64 registers self.iret.elr_el1 = all.elr_el1; self.iret.spsr_el1 = all.spsr_el1; self.iret.esr_el1 = all.esr_el1; self.iret.sp_el0 = all.sp_el0; */ self.preserved.x30 = all.x30; self.preserved.x29 = all.x29; self.preserved.x28 = all.x28; self.preserved.x27 = all.x27; self.preserved.x26 = all.x26; self.preserved.x25 = all.x25; self.preserved.x24 = all.x24; self.preserved.x23 = all.x23; self.preserved.x22 = all.x22; self.preserved.x21 = all.x21; self.preserved.x20 = all.x20; self.preserved.x19 = all.x19; self.scratch.x18 = all.x18; self.scratch.x17 = all.x17; self.scratch.x16 = all.x16; self.scratch.x15 = all.x15; self.scratch.x14 = all.x14; self.scratch.x13 = all.x13; self.scratch.x12 = all.x12; self.scratch.x11 = all.x11; self.scratch.x10 = all.x10; self.scratch.x9 = all.x9; self.scratch.x8 = all.x8; self.scratch.x7 = all.x7; self.scratch.x6 = all.x6; self.scratch.x5 = all.x5; self.scratch.x4 = all.x4; self.scratch.x3 = all.x3; self.scratch.x2 = all.x2; self.scratch.x1 = all.x1; self.scratch.x0 = all.x0; } /// Store a specific generic registers pub fn store_reg(&mut self, idx: usize, val: usize) { match idx { 0 => self.scratch.x0 = val, 1 => self.scratch.x1 = val, 2 => self.scratch.x2 = val, 3 => self.scratch.x3 = val, 4 => self.scratch.x4 = val, 5 => self.scratch.x5 = val, 6 => self.scratch.x6 = val, 7 => self.scratch.x7 = val, 8 => self.scratch.x8 = val, 9 => self.scratch.x9 = val, 10 => self.scratch.x10 = val, 11 => self.scratch.x11 = val, 12 => self.scratch.x12 = val, 13 => self.scratch.x13 = val, 14 => self.scratch.x14 = val, 15 => self.scratch.x15 = val, 16 => self.scratch.x16 = val, 17 => self.scratch.x17 = val, 18 => self.scratch.x18 = val, 19 => self.preserved.x19 = val, 20 => self.preserved.x20 = val, 21 => self.preserved.x21 = val, 22 => self.preserved.x22 = val, 23 => self.preserved.x23 = val, 24 => self.preserved.x24 = val, 25 => self.preserved.x25 = val, 26 => self.preserved.x26 = val, 27 => self.preserved.x27 = val, 28 => self.preserved.x28 = val, 29 => self.preserved.x29 = val, 30 => self.preserved.x30 = val, _ => {} } } //TODO pub fn is_singlestep(&self) -> bool { false } pub fn set_singlestep(&mut self, singlestep: bool) {} } #[macro_export] macro_rules! aarch64_asm { ($($strings:expr,)+) => { core::arch::global_asm!(concat!( $($strings),+, )); }; } #[macro_export] macro_rules! push_scratch { () => { " // Push scratch registers str x18, [sp, #-16]! stp x16, x17, [sp, #-16]! stp x14, x15, [sp, #-16]! stp x12, x13, [sp, #-16]! stp x10, x11, [sp, #-16]! stp x8, x9, [sp, #-16]! stp x6, x7, [sp, #-16]! stp x4, x5, [sp, #-16]! stp x2, x3, [sp, #-16]! stp x0, x1, [sp, #-16]! " }; } #[macro_export] macro_rules! pop_scratch { () => { " // Pop scratch registers ldp x0, x1, [sp], #16 ldp x2, x3, [sp], #16 ldp x4, x5, [sp], #16 ldp x6, x7, [sp], #16 ldp x8, x9, [sp], #16 ldp x10, x11, [sp], #16 ldp x12, x13, [sp], #16 ldp x14, x15, [sp], #16 ldp x16, x17, [sp], #16 ldr x18, [sp], #16 " }; } #[macro_export] macro_rules! push_preserved { () => { " // Push preserved registers stp x29, x30, [sp, #-16]! stp x27, x28, [sp, #-16]! stp x25, x26, [sp, #-16]! stp x23, x24, [sp, #-16]! stp x21, x22, [sp, #-16]! stp x19, x20, [sp, #-16]! " }; } #[macro_export] macro_rules! pop_preserved { () => { " // Pop preserved registers ldp x19, x20, [sp], #16 ldp x21, x22, [sp], #16 ldp x23, x24, [sp], #16 ldp x25, x26, [sp], #16 ldp x27, x28, [sp], #16 ldp x29, x30, [sp], #16 " }; } #[macro_export] macro_rules! push_special { () => { " mrs x14, spsr_el1 mrs x15, elr_el1 stp x14, x15, [sp, #-16]! mrs x14, sp_el0 mrs x15, esr_el1 stp x14, x15, [sp, #-16]! " }; } #[macro_export] macro_rules! pop_special { () => { " ldp x14, x15, [sp], 16 msr esr_el1, x15 msr sp_el0, x14 ldp x14, x15, [sp], 16 msr elr_el1, x15 msr spsr_el1, x14 " }; } #[macro_export] macro_rules! exception_stack { ($name:ident, |$stack:ident| $code:block) => { #[naked] #[no_mangle] pub unsafe extern "C" fn $name(stack: &mut $crate::arch::aarch64::interrupt::InterruptStack) { unsafe extern "C" fn inner($stack: &mut $crate::arch::aarch64::interrupt::InterruptStack) { $code } core::arch::asm!(concat!( // Backup all userspace registers to stack push_preserved!(), push_scratch!(), push_special!(), // Call inner function with pointer to stack "mov x29, sp\n", "mov x0, sp\n", "bl {}", // Restore all userspace registers pop_special!(), pop_scratch!(), pop_preserved!(), "eret\n", ), sym inner, options(noreturn)); } }; } #[naked] pub unsafe extern "C" fn enter_usermode() -> ! { core::arch::asm!(concat!( // Restore all userspace registers pop_special!(), pop_scratch!(), pop_preserved!(), "eret\n", ), options(noreturn)); }