Nothing to see here, move along
1#[derive(Debug, Clone, Copy)]
2#[repr(C)]
3#[derive(zerocopy::IntoBytes, zerocopy::Immutable, zerocopy::KnownLayout)]
4pub struct CpuContext {
5 pub(crate) rax: u64,
6 pub(crate) rbx: u64,
7 pub(crate) rcx: u64,
8 pub(crate) rdx: u64,
9 pub(crate) rsi: u64,
10 pub(crate) rdi: u64,
11 pub(crate) rbp: u64,
12 pub(crate) r8: u64,
13 pub(crate) r9: u64,
14 pub(crate) r10: u64,
15 pub(crate) r11: u64,
16 pub(crate) r12: u64,
17 pub(crate) r13: u64,
18 pub(crate) r14: u64,
19 pub(crate) r15: u64,
20 pub(crate) rip: u64,
21 pub(crate) rsp: u64,
22 pub(crate) rflags: u64,
23 pub(crate) cs: u64,
24 pub(crate) ss: u64,
25}
26
27impl CpuContext {
28 pub const fn zero() -> Self {
29 Self {
30 rax: 0,
31 rbx: 0,
32 rcx: 0,
33 rdx: 0,
34 rsi: 0,
35 rdi: 0,
36 rbp: 0,
37 r8: 0,
38 r9: 0,
39 r10: 0,
40 r11: 0,
41 r12: 0,
42 r13: 0,
43 r14: 0,
44 r15: 0,
45 rip: 0,
46 rsp: 0,
47 rflags: 0,
48 cs: 0,
49 ss: 0,
50 }
51 }
52
53 pub fn checksum(&self) -> u64 {
54 const FNV_OFFSET: u64 = 0xcbf29ce484222325;
55 const FNV_PRIME: u64 = 0x100000001b3;
56 zerocopy::IntoBytes::as_bytes(self)
57 .iter()
58 .fold(FNV_OFFSET, |hash, &b| {
59 (hash ^ b as u64).wrapping_mul(FNV_PRIME)
60 })
61 }
62
63 pub fn validate_user(&self, pid: u16) {
64 const USER_ADDR_LIMIT: u64 = 0x0000_8000_0000_0000;
65 const USER_CS: u64 = 0x23;
66 const USER_SS: u64 = 0x1b;
67
68 assert!(
69 self.rip > 0 && self.rip < USER_ADDR_LIMIT,
70 "[ctx] pid {}: rip={:#x} outside user range",
71 pid,
72 self.rip,
73 );
74
75 assert!(
76 self.rsp > 0 && self.rsp < USER_ADDR_LIMIT,
77 "[ctx] pid {}: rsp={:#x} outside user range",
78 pid,
79 self.rsp,
80 );
81
82 assert!(
83 self.cs == USER_CS,
84 "[ctx] pid {}: cs={:#x} expected {:#x}",
85 pid,
86 self.cs,
87 USER_CS,
88 );
89
90 assert!(
91 self.ss == USER_SS,
92 "[ctx] pid {}: ss={:#x} expected {:#x}",
93 pid,
94 self.ss,
95 USER_SS,
96 );
97 }
98}
99
100const _: () = {
101 assert!(core::mem::offset_of!(CpuContext, rax) == 0);
102 assert!(core::mem::offset_of!(CpuContext, rbx) == 8);
103 assert!(core::mem::offset_of!(CpuContext, rcx) == 16);
104 assert!(core::mem::offset_of!(CpuContext, rdx) == 24);
105 assert!(core::mem::offset_of!(CpuContext, rsi) == 32);
106 assert!(core::mem::offset_of!(CpuContext, rdi) == 40);
107 assert!(core::mem::offset_of!(CpuContext, rbp) == 48);
108 assert!(core::mem::offset_of!(CpuContext, r8) == 56);
109 assert!(core::mem::offset_of!(CpuContext, r9) == 64);
110 assert!(core::mem::offset_of!(CpuContext, r10) == 72);
111 assert!(core::mem::offset_of!(CpuContext, r11) == 80);
112 assert!(core::mem::offset_of!(CpuContext, r12) == 88);
113 assert!(core::mem::offset_of!(CpuContext, r13) == 96);
114 assert!(core::mem::offset_of!(CpuContext, r14) == 104);
115 assert!(core::mem::offset_of!(CpuContext, r15) == 112);
116 assert!(core::mem::offset_of!(CpuContext, rip) == 120);
117 assert!(core::mem::offset_of!(CpuContext, rsp) == 128);
118 assert!(core::mem::offset_of!(CpuContext, rflags) == 136);
119 assert!(core::mem::offset_of!(CpuContext, cs) == 144);
120 assert!(core::mem::offset_of!(CpuContext, ss) == 152);
121 assert!(core::mem::size_of::<CpuContext>() == 160);
122};
123
124pub const MAX_XSAVE_AREA: usize = 1024;
125
126#[derive(Clone, Copy)]
127#[repr(C, align(64))]
128pub struct FpuState {
129 pub data: [u8; MAX_XSAVE_AREA],
130}
131
132const FXSAVE_FCW_OFFSET: usize = 0;
133const FXSAVE_MXCSR_OFFSET: usize = 24;
134const XSTATE_BV_OFFSET: usize = 512;
135const DEFAULT_FCW: u16 = 0x037F;
136const DEFAULT_MXCSR: u32 = 0x1F80;
137const XSTATE_BV_X87_SSE: u64 = 0b011;
138
139impl FpuState {
140 pub const fn default_init() -> Self {
141 let mut data = [0u8; MAX_XSAVE_AREA];
142 let fcw = DEFAULT_FCW.to_le_bytes();
143 data[FXSAVE_FCW_OFFSET] = fcw[0];
144 data[FXSAVE_FCW_OFFSET + 1] = fcw[1];
145 let mxcsr = DEFAULT_MXCSR.to_le_bytes();
146 data[FXSAVE_MXCSR_OFFSET] = mxcsr[0];
147 data[FXSAVE_MXCSR_OFFSET + 1] = mxcsr[1];
148 data[FXSAVE_MXCSR_OFFSET + 2] = mxcsr[2];
149 data[FXSAVE_MXCSR_OFFSET + 3] = mxcsr[3];
150 let xstate = XSTATE_BV_X87_SSE.to_le_bytes();
151 data[XSTATE_BV_OFFSET] = xstate[0];
152 data[XSTATE_BV_OFFSET + 1] = xstate[1];
153 data[XSTATE_BV_OFFSET + 2] = xstate[2];
154 data[XSTATE_BV_OFFSET + 3] = xstate[3];
155 data[XSTATE_BV_OFFSET + 4] = xstate[4];
156 data[XSTATE_BV_OFFSET + 5] = xstate[5];
157 data[XSTATE_BV_OFFSET + 6] = xstate[6];
158 data[XSTATE_BV_OFFSET + 7] = xstate[7];
159 Self { data }
160 }
161
162 #[allow(dead_code)]
163 pub fn save(&mut self) {
164 match crate::arch::xsave::fpu_mode() {
165 crate::arch::xsave::FpuMode::Xsave { feature_mask, .. } => unsafe {
166 core::arch::asm!(
167 "xsave64 [{}]",
168 in(reg) self.data.as_mut_ptr(),
169 in("eax") feature_mask as u32,
170 in("edx") (feature_mask >> 32) as u32,
171 options(nostack, preserves_flags)
172 );
173 },
174 crate::arch::xsave::FpuMode::Fxsave => unsafe {
175 core::arch::asm!(
176 "fxsave64 [{}]",
177 in(reg) self.data.as_mut_ptr(),
178 options(nostack, preserves_flags)
179 );
180 },
181 }
182 }
183
184 pub fn restore(&self) {
185 match crate::arch::xsave::fpu_mode() {
186 crate::arch::xsave::FpuMode::Xsave { feature_mask, .. } => unsafe {
187 core::arch::asm!(
188 "xrstor64 [{}]",
189 in(reg) self.data.as_ptr(),
190 in("eax") feature_mask as u32,
191 in("edx") (feature_mask >> 32) as u32,
192 options(nostack, preserves_flags)
193 );
194 },
195 crate::arch::xsave::FpuMode::Fxsave => unsafe {
196 core::arch::asm!(
197 "fxrstor64 [{}]",
198 in(reg) self.data.as_ptr(),
199 options(nostack, preserves_flags)
200 );
201 },
202 }
203 }
204}
205
206pub const IPC_MSG_REGS: usize = 6;
207
208mod ipc_seal {
209 pub trait Sealed {}
210}
211
212pub trait IpcKind: ipc_seal::Sealed {}
213
214#[derive(Debug, Clone, Copy)]
215pub struct Full;
216impl ipc_seal::Sealed for Full {}
217impl IpcKind for Full {}
218
219#[derive(Debug, Clone, Copy)]
220pub struct Reply;
221impl ipc_seal::Sealed for Reply {}
222impl IpcKind for Reply {}
223
224#[derive(Debug, Clone, Copy)]
225pub struct IpcMessage<K: IpcKind = Full> {
226 pub regs: [u64; IPC_MSG_REGS],
227 _kind: core::marker::PhantomData<K>,
228}
229
230impl IpcMessage<Full> {
231 pub const fn from_regs(regs: [u64; IPC_MSG_REGS]) -> Self {
232 Self {
233 regs,
234 _kind: core::marker::PhantomData,
235 }
236 }
237
238 pub const fn zero() -> Self {
239 Self {
240 regs: [0u64; IPC_MSG_REGS],
241 _kind: core::marker::PhantomData,
242 }
243 }
244}
245
246const REPLY_REGS: usize = 5;
247
248impl IpcMessage<Reply> {
249 pub const fn from_reply_regs(regs: [u64; REPLY_REGS]) -> Self {
250 Self {
251 regs: [regs[0], regs[1], regs[2], regs[3], regs[4], 0],
252 _kind: core::marker::PhantomData,
253 }
254 }
255
256 pub(crate) const fn into_full(self) -> IpcMessage<Full> {
257 IpcMessage {
258 regs: self.regs,
259 _kind: core::marker::PhantomData,
260 }
261 }
262}