1use crate::{HeapRegs, RegisterStorage, RegisterStorageEnum};
6use starnix_uapi::errors::Errno;
7use starnix_uapi::restricted_aspace::RESTRICTED_ASPACE_HIGHEST_ADDRESS;
8use starnix_uapi::{__NR_restart_syscall, error, user_regs_struct};
9
10const SYSCALL_INSTRUCTION_SIZE_BYTES: u64 = 2;
12
13#[derive(Default, Clone, Eq, PartialEq)]
19pub struct RegisterState<T: RegisterStorage> {
20 pub real_registers: T,
21
22 pub orig_rax: u64,
26}
27
28impl<T: RegisterStorage> RegisterState<T> {
29 pub fn to_user_regs_struct(&self) -> user_regs_struct {
30 user_regs_struct {
31 r15: self.r15,
32 r14: self.r14,
33 r13: self.r13,
34 r12: self.r12,
35 rbp: self.rbp,
36 rbx: self.rbx,
37 r11: self.r11,
38 r10: self.r10,
39 r9: self.r9,
40 r8: self.r8,
41 rax: self.rax,
42 rcx: self.rcx,
43 rdx: self.rdx,
44 rsi: self.rsi,
45 rdi: self.rdi,
46 orig_rax: self.orig_rax,
47 rip: self.ip,
48 cs: 0,
49 eflags: self.flags,
50 rsp: self.rsp,
51 ss: 0,
52 fs_base: self.fs_base,
53 gs_base: self.gs_base,
54 ds: 0,
55 es: 0,
56 fs: 0,
57 gs: 0,
58 }
59 }
60
61 pub fn to_user_regs_struct_arch32(&self) -> starnix_uapi::arch32::user_regs_struct {
62 unreachable!("arch32 not supported on x64")
63 }
64
65 pub fn from_user_regs_struct(&mut self, regs: &user_regs_struct) {
66 self.r15 = regs.r15;
67 self.r14 = regs.r14;
68 self.r13 = regs.r13;
69 self.r12 = regs.r12;
70 self.rbp = regs.rbp;
71 self.rbx = regs.rbx;
72 self.r11 = regs.r11;
73 self.r10 = regs.r10;
74 self.r9 = regs.r9;
75 self.r8 = regs.r8;
76 self.rax = regs.rax;
77 self.rcx = regs.rcx;
78 self.rdx = regs.rdx;
79 self.rsi = regs.rsi;
80 self.rdi = regs.rdi;
81 self.orig_rax = regs.orig_rax;
82 self.ip = regs.rip;
83 self.flags = regs.eflags;
84 self.rsp = regs.rsp;
85 self.fs_base = regs.fs_base;
86 self.gs_base = regs.gs_base;
87 }
88
89 pub fn from_user_regs_struct_arch32(&mut self, _regs: &starnix_uapi::arch32::user_regs_struct) {
90 unreachable!("arch32 not supported on x64")
91 }
92
93 pub fn save_registers_for_restart(&mut self) {
97 self.orig_rax = self.rax;
99
100 self.rax = -(starnix_uapi::ENOSYS as i64) as u64;
105 }
106
107 pub fn prepare_for_custom_restart(&mut self) {
109 self.rax = __NR_restart_syscall as u64;
110 }
111
112 pub fn restore_original_return_register(&mut self) {
114 self.rax = self.orig_rax;
115 }
116
117 pub fn instruction_pointer_register(&self) -> u64 {
120 self.ip
121 }
122
123 pub fn set_instruction_pointer_register(&mut self, new_ip: u64) {
126 self.ip = new_ip;
127 }
128
129 pub fn rewind_syscall_instruction(&mut self) {
131 self.ip -= SYSCALL_INSTRUCTION_SIZE_BYTES;
132 }
133
134 pub fn return_register(&self) -> u64 {
137 self.rax
138 }
139
140 pub fn set_return_register(&mut self, return_value: u64) {
143 self.rax = return_value;
144 }
145
146 pub fn stack_pointer_register(&self) -> u64 {
148 self.rsp
149 }
150
151 pub fn set_stack_pointer_register(&mut self, sp: u64) {
153 self.rsp = sp;
154 }
155
156 pub fn set_thread_pointer_register(&mut self, tp: u64) {
158 self.fs_base = tp;
159 }
160
161 pub fn set_arg0_register(&mut self, rdi: u64) {
163 self.rdi = rdi;
164 }
165
166 pub fn set_arg1_register(&mut self, rsi: u64) {
168 self.rsi = rsi;
169 }
170
171 pub fn set_arg2_register(&mut self, rdx: u64) {
173 self.rdx = rdx;
174 }
175
176 pub fn syscall_register(&self) -> u64 {
178 self.orig_rax
179 }
180
181 pub fn reset_flags(&mut self) {
183 self.flags = 0;
184 if self.fs_base as usize >= RESTRICTED_ASPACE_HIGHEST_ADDRESS {
187 self.fs_base = 0;
188 }
189 if self.gs_base as usize >= RESTRICTED_ASPACE_HIGHEST_ADDRESS {
190 self.gs_base = 0;
191 }
192 }
193
194 pub fn apply_user_register(
196 &mut self,
197 offset: usize,
198 f: &mut dyn FnMut(&mut u64),
199 ) -> Result<(), Errno> {
200 if offset == memoffset::offset_of!(user_regs_struct, r15) {
201 f(&mut self.r15);
202 } else if offset == memoffset::offset_of!(user_regs_struct, r14) {
203 f(&mut self.r14);
204 } else if offset == memoffset::offset_of!(user_regs_struct, r13) {
205 f(&mut self.r13);
206 } else if offset == memoffset::offset_of!(user_regs_struct, r12) {
207 f(&mut self.r12);
208 } else if offset == memoffset::offset_of!(user_regs_struct, rbp) {
209 f(&mut self.rbp);
210 } else if offset == memoffset::offset_of!(user_regs_struct, rbx) {
211 f(&mut self.rbx);
212 } else if offset == memoffset::offset_of!(user_regs_struct, r11) {
213 f(&mut self.r11);
214 } else if offset == memoffset::offset_of!(user_regs_struct, r10) {
215 f(&mut self.r10);
216 } else if offset == memoffset::offset_of!(user_regs_struct, r9) {
217 f(&mut self.r9);
218 } else if offset == memoffset::offset_of!(user_regs_struct, r8) {
219 f(&mut self.r8);
220 } else if offset == memoffset::offset_of!(user_regs_struct, rax) {
221 f(&mut self.rax);
222 } else if offset == memoffset::offset_of!(user_regs_struct, rcx) {
223 f(&mut self.rcx);
224 } else if offset == memoffset::offset_of!(user_regs_struct, rdx) {
225 f(&mut self.rdx);
226 } else if offset == memoffset::offset_of!(user_regs_struct, rsi) {
227 f(&mut self.rsi);
228 } else if offset == memoffset::offset_of!(user_regs_struct, rdi) {
229 f(&mut self.rdi);
230 } else if offset == memoffset::offset_of!(user_regs_struct, orig_rax) {
231 f(&mut self.orig_rax);
232 } else if offset == memoffset::offset_of!(user_regs_struct, rip) {
233 f(&mut self.ip);
234 } else if offset == memoffset::offset_of!(user_regs_struct, cs) {
235 let mut val = 0;
236 f(&mut val);
237 } else if offset == memoffset::offset_of!(user_regs_struct, eflags) {
238 f(&mut self.flags);
239 } else if offset == memoffset::offset_of!(user_regs_struct, rsp) {
240 f(&mut self.rsp);
241 } else if offset == memoffset::offset_of!(user_regs_struct, ss) {
242 let mut val = 0;
243 f(&mut val);
244 } else if offset == memoffset::offset_of!(user_regs_struct, fs_base) {
245 f(&mut self.fs_base);
246 } else if offset == memoffset::offset_of!(user_regs_struct, gs_base) {
247 f(&mut self.gs_base);
248 } else if offset == memoffset::offset_of!(user_regs_struct, ds) {
249 let mut val = 0;
250 f(&mut val);
251 } else if offset == memoffset::offset_of!(user_regs_struct, es) {
252 let mut val = 0;
253 f(&mut val);
254 } else if offset == memoffset::offset_of!(user_regs_struct, fs) {
255 let mut val = 0;
256 f(&mut val);
257 } else if offset == memoffset::offset_of!(user_regs_struct, gs) {
258 let mut val = 0;
259 f(&mut val);
260 } else {
261 return error!(EINVAL);
262 };
263 Ok(())
264 }
265
266 pub fn load(&mut self, regs: zx::sys::zx_restricted_state_t) {
267 *self.real_registers = regs;
268 }
269
270 pub fn copy_from<O: RegisterStorage>(&mut self, other: &RegisterState<O>) {
272 self.load(*other.real_registers);
273 self.orig_rax = other.orig_rax;
274 }
275}
276
277impl<T: RegisterStorage> std::fmt::Debug for RegisterState<T> {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 f.debug_struct("RegisterState")
280 .field("real_registers", &self.real_registers)
281 .field("orig_rax", &format_args!("{:#x}", &self.orig_rax))
282 .finish()
283 }
284}
285
286impl<T: RegisterStorage> std::ops::Deref for RegisterState<T> {
287 type Target = zx::sys::zx_restricted_state_t;
288
289 fn deref(&self) -> &Self::Target {
290 &*self.real_registers
291 }
292}
293
294impl<T: RegisterStorage> std::ops::DerefMut for RegisterState<T> {
295 fn deref_mut(&mut self) -> &mut Self::Target {
296 &mut *self.real_registers
297 }
298}
299
300impl From<RegisterState<HeapRegs>> for RegisterState<RegisterStorageEnum> {
301 fn from(regs: RegisterState<HeapRegs>) -> Self {
302 Self { real_registers: regs.real_registers.into(), orig_rax: regs.orig_rax }
303 }
304}
305
306impl From<RegisterState<RegisterStorageEnum>> for RegisterState<HeapRegs> {
307 fn from(regs: RegisterState<RegisterStorageEnum>) -> Self {
308 Self { real_registers: regs.real_registers.into(), orig_rax: regs.orig_rax }
309 }
310}