#[derive(Debug, Clone, Copy)] #[repr(C)] #[derive(zerocopy::IntoBytes, zerocopy::Immutable, zerocopy::KnownLayout)] pub struct CpuContext { pub(crate) rax: u64, pub(crate) rbx: u64, pub(crate) rcx: u64, pub(crate) rdx: u64, pub(crate) rsi: u64, pub(crate) rdi: u64, pub(crate) rbp: u64, pub(crate) r8: u64, pub(crate) r9: u64, pub(crate) r10: u64, pub(crate) r11: u64, pub(crate) r12: u64, pub(crate) r13: u64, pub(crate) r14: u64, pub(crate) r15: u64, pub(crate) rip: u64, pub(crate) rsp: u64, pub(crate) rflags: u64, pub(crate) cs: u64, pub(crate) ss: u64, } impl CpuContext { pub const fn zero() -> Self { Self { rax: 0, rbx: 0, rcx: 0, rdx: 0, rsi: 0, rdi: 0, rbp: 0, r8: 0, r9: 0, r10: 0, r11: 0, r12: 0, r13: 0, r14: 0, r15: 0, rip: 0, rsp: 0, rflags: 0, cs: 0, ss: 0, } } pub fn checksum(&self) -> u64 { const FNV_OFFSET: u64 = 0xcbf29ce484222325; const FNV_PRIME: u64 = 0x100000001b3; zerocopy::IntoBytes::as_bytes(self) .iter() .fold(FNV_OFFSET, |hash, &b| { (hash ^ b as u64).wrapping_mul(FNV_PRIME) }) } pub fn validate_user(&self, pid: u32) { const USER_ADDR_LIMIT: u64 = 0x0000_8000_0000_0000; const USER_CS: u64 = 0x23; const USER_SS: u64 = 0x1b; assert!( self.rip > 0 && self.rip < USER_ADDR_LIMIT, "[ctx] pid {}: rip={:#x} outside user range", pid, self.rip, ); assert!( self.rsp > 0 && self.rsp < USER_ADDR_LIMIT, "[ctx] pid {}: rsp={:#x} outside user range", pid, self.rsp, ); assert!( self.cs == USER_CS, "[ctx] pid {}: cs={:#x} expected {:#x}", pid, self.cs, USER_CS, ); assert!( self.ss == USER_SS, "[ctx] pid {}: ss={:#x} expected {:#x}", pid, self.ss, USER_SS, ); } } const _: () = { assert!(core::mem::offset_of!(CpuContext, rax) == 0); assert!(core::mem::offset_of!(CpuContext, rbx) == 8); assert!(core::mem::offset_of!(CpuContext, rcx) == 16); assert!(core::mem::offset_of!(CpuContext, rdx) == 24); assert!(core::mem::offset_of!(CpuContext, rsi) == 32); assert!(core::mem::offset_of!(CpuContext, rdi) == 40); assert!(core::mem::offset_of!(CpuContext, rbp) == 48); assert!(core::mem::offset_of!(CpuContext, r8) == 56); assert!(core::mem::offset_of!(CpuContext, r9) == 64); assert!(core::mem::offset_of!(CpuContext, r10) == 72); assert!(core::mem::offset_of!(CpuContext, r11) == 80); assert!(core::mem::offset_of!(CpuContext, r12) == 88); assert!(core::mem::offset_of!(CpuContext, r13) == 96); assert!(core::mem::offset_of!(CpuContext, r14) == 104); assert!(core::mem::offset_of!(CpuContext, r15) == 112); assert!(core::mem::offset_of!(CpuContext, rip) == 120); assert!(core::mem::offset_of!(CpuContext, rsp) == 128); assert!(core::mem::offset_of!(CpuContext, rflags) == 136); assert!(core::mem::offset_of!(CpuContext, cs) == 144); assert!(core::mem::offset_of!(CpuContext, ss) == 152); assert!(core::mem::size_of::() == 160); }; pub const MAX_XSAVE_AREA: usize = 1024; #[derive(Clone, Copy)] #[repr(C, align(64))] pub struct FpuState { pub data: [u8; MAX_XSAVE_AREA], } const FXSAVE_FCW_OFFSET: usize = 0; const FXSAVE_MXCSR_OFFSET: usize = 24; const XSTATE_BV_OFFSET: usize = 512; const DEFAULT_FCW: u16 = 0x037F; const DEFAULT_MXCSR: u32 = 0x1F80; const XSTATE_BV_X87_SSE: u64 = 0b011; impl FpuState { pub const fn default_init() -> Self { let mut data = [0u8; MAX_XSAVE_AREA]; let fcw = DEFAULT_FCW.to_le_bytes(); data[FXSAVE_FCW_OFFSET] = fcw[0]; data[FXSAVE_FCW_OFFSET + 1] = fcw[1]; let mxcsr = DEFAULT_MXCSR.to_le_bytes(); data[FXSAVE_MXCSR_OFFSET] = mxcsr[0]; data[FXSAVE_MXCSR_OFFSET + 1] = mxcsr[1]; data[FXSAVE_MXCSR_OFFSET + 2] = mxcsr[2]; data[FXSAVE_MXCSR_OFFSET + 3] = mxcsr[3]; let xstate = XSTATE_BV_X87_SSE.to_le_bytes(); data[XSTATE_BV_OFFSET] = xstate[0]; data[XSTATE_BV_OFFSET + 1] = xstate[1]; data[XSTATE_BV_OFFSET + 2] = xstate[2]; data[XSTATE_BV_OFFSET + 3] = xstate[3]; data[XSTATE_BV_OFFSET + 4] = xstate[4]; data[XSTATE_BV_OFFSET + 5] = xstate[5]; data[XSTATE_BV_OFFSET + 6] = xstate[6]; data[XSTATE_BV_OFFSET + 7] = xstate[7]; Self { data } } #[allow(dead_code)] pub fn save(&mut self) { match crate::arch::xsave::fpu_mode() { crate::arch::xsave::FpuMode::Xsave { feature_mask, .. } => unsafe { core::arch::asm!( "xsave64 [{}]", in(reg) self.data.as_mut_ptr(), in("eax") feature_mask as u32, in("edx") (feature_mask >> 32) as u32, options(nostack, preserves_flags) ); }, crate::arch::xsave::FpuMode::Fxsave => unsafe { core::arch::asm!( "fxsave64 [{}]", in(reg) self.data.as_mut_ptr(), options(nostack, preserves_flags) ); }, } } pub fn restore(&self) { match crate::arch::xsave::fpu_mode() { crate::arch::xsave::FpuMode::Xsave { feature_mask, .. } => unsafe { core::arch::asm!( "xrstor64 [{}]", in(reg) self.data.as_ptr(), in("eax") feature_mask as u32, in("edx") (feature_mask >> 32) as u32, options(nostack, preserves_flags) ); }, crate::arch::xsave::FpuMode::Fxsave => unsafe { core::arch::asm!( "fxrstor64 [{}]", in(reg) self.data.as_ptr(), options(nostack, preserves_flags) ); }, } } } pub const IPC_MSG_REGS: usize = 6; mod ipc_seal { pub trait Sealed {} } pub trait IpcKind: ipc_seal::Sealed {} #[derive(Debug, Clone, Copy)] pub struct Full; impl ipc_seal::Sealed for Full {} impl IpcKind for Full {} #[derive(Debug, Clone, Copy)] pub struct Reply; impl ipc_seal::Sealed for Reply {} impl IpcKind for Reply {} #[derive(Debug, Clone, Copy)] pub struct IpcMessage { pub regs: [u64; IPC_MSG_REGS], _kind: core::marker::PhantomData, } impl IpcMessage { pub const fn from_regs(regs: [u64; IPC_MSG_REGS]) -> Self { Self { regs, _kind: core::marker::PhantomData, } } pub const fn zero() -> Self { Self { regs: [0u64; IPC_MSG_REGS], _kind: core::marker::PhantomData, } } } const REPLY_REGS: usize = 5; impl IpcMessage { pub const fn from_reply_regs(regs: [u64; REPLY_REGS]) -> Self { Self { regs: [regs[0], regs[1], regs[2], regs[3], regs[4], 0], _kind: core::marker::PhantomData, } } pub(crate) const fn into_full(self) -> IpcMessage { IpcMessage { regs: self.regs, _kind: core::marker::PhantomData, } } }