1use super::HypercallIo;
7use crate::support::AsHandler;
8
9pub struct X64RegisterIo<T> {
11 inner: T,
12 is_64bit: bool,
13}
14
15impl<T: X64RegisterState> X64RegisterIo<T> {
16 pub fn new(t: T, is_64bit: bool) -> Self {
21 Self { inner: t, is_64bit }
22 }
23
24 fn gp_pair(&mut self, high: X64HypercallRegister, low: X64HypercallRegister) -> u64 {
25 (self.inner.gp(high) << 32) | (self.inner.gp(low) & 0xffff_ffff)
26 }
27
28 fn mask(&self, value: u64) -> u64 {
29 value
30 & if self.is_64bit {
31 u64::MAX
32 } else {
33 u32::MAX as u64
34 }
35 }
36
37 fn set_control(&mut self, control: u64) {
38 if self.is_64bit {
39 self.inner.set_gp(X64HypercallRegister::Rcx, control);
40 } else {
41 self.inner.set_gp(X64HypercallRegister::Rdx, control >> 32);
42 self.inner
43 .set_gp(X64HypercallRegister::Rax, control & u32::MAX as u64);
44 }
45 }
46}
47
48impl<T> AsHandler<T> for X64RegisterIo<T> {
49 fn as_handler(&mut self) -> &mut T {
50 &mut self.inner
51 }
52}
53
54impl<T> AsHandler<T> for X64RegisterIo<&mut T> {
55 fn as_handler(&mut self) -> &mut T {
56 &mut *self.inner
57 }
58}
59
60impl<T: X64RegisterState> HypercallIo for X64RegisterIo<T> {
61 fn advance_ip(&mut self) {
62 let rip = self.inner.rip().wrapping_add(3);
63 self.inner.set_rip(self.mask(rip));
64 }
65
66 fn retry(&mut self, control: u64) {
67 self.set_control(control)
69
70 }
72
73 fn control(&mut self) -> u64 {
74 if self.is_64bit {
75 self.inner.gp(X64HypercallRegister::Rcx)
76 } else {
77 self.gp_pair(X64HypercallRegister::Rdx, X64HypercallRegister::Rax)
78 }
79 }
80
81 fn vtl_input(&mut self) -> u64 {
82 let name = if self.is_64bit {
83 X64HypercallRegister::Rax
84 } else {
85 X64HypercallRegister::Rcx
86 };
87
88 let value = self.inner.gp(name);
89 self.mask(value)
90 }
91
92 fn set_result(&mut self, n: u64) {
93 if self.is_64bit {
94 self.inner.set_gp(X64HypercallRegister::Rax, n);
95 } else {
96 self.inner.set_gp(X64HypercallRegister::Rdx, n >> 32);
97 self.inner
98 .set_gp(X64HypercallRegister::Rax, n & u32::MAX as u64);
99 }
100 }
101
102 fn input_gpa(&mut self) -> u64 {
103 if self.is_64bit {
104 self.inner.gp(X64HypercallRegister::Rdx)
105 } else {
106 self.gp_pair(X64HypercallRegister::Rbx, X64HypercallRegister::Rcx)
107 }
108 }
109
110 fn output_gpa(&mut self) -> u64 {
111 if self.is_64bit {
112 self.inner.gp(X64HypercallRegister::R8)
113 } else {
114 self.gp_pair(X64HypercallRegister::Rdi, X64HypercallRegister::Rsi)
115 }
116 }
117
118 fn fast_register_pair_count(&mut self) -> usize {
119 if self.is_64bit { 7 } else { 1 }
120 }
121
122 fn extended_fast_hypercalls_ok(&mut self) -> bool {
123 self.is_64bit
124 }
125
126 fn fast_input(&mut self, buf: &mut [[u64; 2]], _output_register_pairs: usize) -> usize {
127 self.fast_regs(0, buf);
128 buf.len()
129 }
130
131 fn fast_output(&mut self, starting_pair_index: usize, buf: &[[u64; 2]]) {
132 for (i, &[low, high]) in buf.iter().enumerate() {
134 let index = i + starting_pair_index;
135 if index == 0 {
136 self.inner.set_gp(X64HypercallRegister::Rdx, low);
137 self.inner.set_gp(X64HypercallRegister::R8, high);
138 } else {
139 let x = low as u128 | ((high as u128) << 64);
140 self.inner.set_xmm(index - 1, x)
141 }
142 }
143 }
144
145 fn fast_regs(&mut self, starting_pair_index: usize, buf: &mut [[u64; 2]]) {
146 if self.is_64bit {
147 for (i, [low, high]) in buf.iter_mut().enumerate() {
148 let index = i + starting_pair_index;
149 if index == 0 {
150 *low = self.inner.gp(X64HypercallRegister::Rdx);
151 *high = self.inner.gp(X64HypercallRegister::R8);
152 } else {
153 let value = self.inner.xmm(index - 1);
154 *low = value as u64;
155 *high = (value >> 64) as u64;
156 }
157 }
158 } else if let [[low, high], ..] = buf {
159 *low = self.gp_pair(X64HypercallRegister::Rbx, X64HypercallRegister::Rcx);
160 *high = self.gp_pair(X64HypercallRegister::Rdi, X64HypercallRegister::Rsi);
161 }
162 }
163}
164
165pub trait X64RegisterState {
167 fn rip(&mut self) -> u64;
169
170 fn set_rip(&mut self, rip: u64);
172
173 fn gp(&mut self, n: X64HypercallRegister) -> u64;
175
176 fn set_gp(&mut self, n: X64HypercallRegister, value: u64);
178
179 fn xmm(&mut self, n: usize) -> u128;
181
182 fn set_xmm(&mut self, n: usize, value: u128);
184}
185
186impl<T: X64RegisterState> X64RegisterState for &'_ mut T {
187 fn rip(&mut self) -> u64 {
188 (**self).rip()
189 }
190
191 fn set_rip(&mut self, rip: u64) {
192 (**self).set_rip(rip)
193 }
194
195 fn gp(&mut self, n: X64HypercallRegister) -> u64 {
196 (**self).gp(n)
197 }
198
199 fn set_gp(&mut self, n: X64HypercallRegister, value: u64) {
200 (**self).set_gp(n, value)
201 }
202
203 fn xmm(&mut self, n: usize) -> u128 {
204 (**self).xmm(n)
205 }
206
207 fn set_xmm(&mut self, n: usize, value: u128) {
208 (**self).set_xmm(n, value)
209 }
210}
211
212pub enum X64HypercallRegister {
216 Rax = 0,
218 Rcx = 1,
220 Rdx = 2,
222 Rbx = 3,
224 Rsi = 6,
226 Rdi = 7,
228 R8 = 8,
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235 use crate::tests::TestHypercallIo;
236 use crate::tests::TestRegisterState;
237
238 impl<T: X64RegisterState + TestRegisterState> TestHypercallIo for X64RegisterIo<T> {
240 fn get_result(&mut self) -> u64 {
241 if self.is_64bit {
242 self.inner.gp(X64HypercallRegister::Rax)
243 } else {
244 self.gp_pair(X64HypercallRegister::Rdx, X64HypercallRegister::Rax)
245 }
246 }
247
248 fn set_control(&mut self, control: u64) {
249 X64RegisterIo::set_control(self, control);
250 }
251
252 fn set_input_gpa(&mut self, gpa: u64) {
253 if self.is_64bit {
254 self.inner.set_gp(X64HypercallRegister::Rdx, gpa);
255 } else {
256 self.inner.set_gp(X64HypercallRegister::Rbx, gpa >> 32);
257 self.inner
258 .set_gp(X64HypercallRegister::Rcx, gpa & u32::MAX as u64);
259 }
260 }
261
262 fn set_output_gpa(&mut self, gpa: u64) {
263 if self.is_64bit {
264 self.inner.set_gp(X64HypercallRegister::R8, gpa);
265 } else {
266 self.inner.set_gp(X64HypercallRegister::Rdi, gpa >> 32);
267 self.inner
268 .set_gp(X64HypercallRegister::Rsi, gpa & u32::MAX as u64);
269 }
270 }
271
272 fn set_fast_input(&mut self, buf: &[[u64; 2]]) {
273 if self.is_64bit {
274 let (gp, xmm) = buf.split_at(1);
275 let rdx = gp[0][0];
276 let r8 = gp[0][1];
277 self.inner.set_gp(X64HypercallRegister::Rdx, rdx);
278 self.inner.set_gp(X64HypercallRegister::R8, r8);
279 for (i, [low, high]) in xmm.iter().enumerate() {
280 let value = *low as u128 | ((*high as u128) << 64);
281 self.inner.set_xmm(i, value);
282 }
283 } else {
284 let [low, high] = buf[0];
285 self.inner.set_gp(X64HypercallRegister::Rbx, low >> 32);
286 self.inner
287 .set_gp(X64HypercallRegister::Rcx, low & u32::MAX as u64);
288 self.inner.set_gp(X64HypercallRegister::Rdi, high >> 32);
289 self.inner
290 .set_gp(X64HypercallRegister::Rsi, high & u32::MAX as u64);
291 }
292 }
293
294 fn get_fast_output(&mut self, input_register_pairs: usize, buf: &mut [[u64; 2]]) {
295 for (i, [low, high]) in buf.iter_mut().enumerate() {
297 if i + input_register_pairs == 0 {
298 *low = self.inner.gp(X64HypercallRegister::Rdx);
299 *high = self.inner.gp(X64HypercallRegister::R8);
300 } else {
301 let x = self.inner.xmm(i + input_register_pairs - 1);
302 *low = x as u64;
303 *high = (x >> 64) as u64;
304 }
305 }
306 }
307
308 fn get_modified_mask(&self) -> u64 {
309 self.inner.get_modified_mask()
310 }
311
312 fn clear_modified_mask(&mut self) {
313 self.inner.clear_modified_mask()
314 }
315
316 fn get_io_register_mask(&self) -> u64 {
317 if self.is_64bit {
318 1u64 << X64HypercallRegister::Rcx as usize
319 | 1u64 << X64HypercallRegister::Rax as usize
320 } else {
321 1u64 << X64HypercallRegister::Rdx as usize
322 | 1u64 << X64HypercallRegister::Rax as usize
323 }
324 }
325
326 fn get_name(&self) -> String {
327 format!("x86_{}", if self.is_64bit { "64" } else { "32" })
328 }
329
330 fn set_vtl_input(&mut self, vtl_input: u64) {
331 if self.is_64bit {
332 self.inner.set_gp(X64HypercallRegister::Rax, vtl_input);
333 } else {
334 self.inner
335 .set_gp(X64HypercallRegister::Rcx, vtl_input >> 32);
336 }
337 }
338
339 fn auto_advance_ip(&mut self) {}
340 }
341}