1use super::HypercallIo;
7use crate::support::AsHandler;
8
9pub trait Arm64RegisterState {
11 fn pc(&mut self) -> u64;
13 fn set_pc(&mut self, pc: u64);
15 fn x(&mut self, n: u8) -> u64;
17 fn set_x(&mut self, n: u8, v: u64);
19}
20
21impl<T: Arm64RegisterState> Arm64RegisterState for &'_ mut T {
22 fn pc(&mut self) -> u64 {
23 (**self).pc()
24 }
25
26 fn set_pc(&mut self, pc: u64) {
27 (**self).set_pc(pc)
28 }
29
30 fn x(&mut self, n: u8) -> u64 {
31 (**self).x(n)
32 }
33
34 fn set_x(&mut self, n: u8, v: u64) {
35 (**self).set_x(n, v)
36 }
37}
38
39pub struct Arm64RegisterIo<T> {
41 inner: T,
42 pre_advanced: bool,
43 smccc: bool,
44}
45
46impl<T> AsHandler<T> for Arm64RegisterIo<T> {
47 fn as_handler(&mut self) -> &mut T {
48 &mut self.inner
49 }
50}
51
52impl<T> AsHandler<T> for Arm64RegisterIo<&mut T> {
53 fn as_handler(&mut self) -> &mut T {
54 &mut *self.inner
55 }
56}
57
58impl<T: Arm64RegisterState> Arm64RegisterIo<T> {
59 pub fn new(t: T, pre_advanced: bool, smccc: bool) -> Self {
67 Self {
68 inner: t,
69 pre_advanced,
70 smccc,
71 }
72 }
73
74 fn set_control(&mut self, control: u64) {
75 self.inner.set_x(self.smccc as u8, control);
77 }
78}
79
80impl<T: Arm64RegisterState> HypercallIo for Arm64RegisterIo<T> {
81 fn advance_ip(&mut self) {
82 if !self.pre_advanced {
83 let pc = self.inner.pc().wrapping_add(4);
84 self.inner.set_pc(pc);
85 }
86 }
87
88 fn retry(&mut self, control: u64) {
89 self.set_control(control);
90 if self.pre_advanced {
91 let pc = self.inner.pc().wrapping_sub(4);
92 self.inner.set_pc(pc);
93 }
94 }
95
96 fn control(&mut self) -> u64 {
97 self.inner.x(self.smccc as u8)
99 }
100
101 fn input_gpa(&mut self) -> u64 {
102 self.inner.x(1 + self.smccc as u8)
104 }
105
106 fn output_gpa(&mut self) -> u64 {
107 self.inner.x(2 + self.smccc as u8)
109 }
110
111 fn fast_register_pair_count(&mut self) -> usize {
112 8
113 }
114
115 fn extended_fast_hypercalls_ok(&mut self) -> bool {
116 true
117 }
118
119 fn fast_input(&mut self, buf: &mut [[u64; 2]], output_register_pairs: usize) -> usize {
120 self.fast_regs(0, buf);
121
122 if self.smccc {
123 buf.len()
125 } else {
126 self.fast_register_pair_count() - output_register_pairs
128 }
129 }
130
131 fn fast_output(&mut self, starting_pair_index: usize, buf: &[[u64; 2]]) {
132 let start = starting_pair_index * 2 + 1 + self.smccc as usize;
134
135 for (i, &[low, high]) in buf.iter().enumerate() {
136 self.inner.set_x((start + i * 2) as u8, low);
137 self.inner.set_x((start + i * 2 + 1) as u8, high);
138 }
139 }
140
141 fn vtl_input(&mut self) -> u64 {
142 0
143 }
144
145 fn set_result(&mut self, n: u64) {
146 self.inner.set_x(0, n)
148 }
149
150 fn fast_regs(&mut self, starting_pair_index: usize, buf: &mut [[u64; 2]]) {
151 let start = starting_pair_index * 2 + 1 + self.smccc as usize;
153 for (i, [low, high]) in buf.iter_mut().enumerate() {
154 *low = self.inner.x((start + i * 2) as u8);
155 *high = self.inner.x((start + i * 2 + 1) as u8);
156 }
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use crate::tests::TestHypercallIo;
164 use crate::tests::TestRegisterState;
165
166 impl<T: Arm64RegisterState + TestRegisterState> TestHypercallIo for Arm64RegisterIo<T> {
168 fn get_result(&mut self) -> u64 {
169 self.inner.x(0)
171 }
172
173 fn set_control(&mut self, control: u64) {
174 Arm64RegisterIo::set_control(self, control);
175 }
176
177 fn set_input_gpa(&mut self, gpa: u64) {
178 self.inner.set_x(1 + self.smccc as u8, gpa)
180 }
181
182 fn set_output_gpa(&mut self, gpa: u64) {
183 self.inner.set_x(2 + self.smccc as u8, gpa);
185 }
186
187 fn set_fast_input(&mut self, buf: &[[u64; 2]]) {
188 for (i, [low, high]) in buf.iter().enumerate() {
190 self.inner.set_x(i as u8 * 2 + 1 + self.smccc as u8, *low);
191 self.inner.set_x(i as u8 * 2 + 2 + self.smccc as u8, *high);
192 }
193 }
194
195 fn get_fast_output(&mut self, input_register_pairs: usize, buf: &mut [[u64; 2]]) {
196 let start = if self.smccc {
197 2 + input_register_pairs * 2
199 } else {
200 17 - buf.len() * 2
202 };
203 for (i, [low, high]) in buf.iter_mut().enumerate() {
204 *low = self.inner.x((start + i * 2) as u8);
205 *high = self.inner.x((start + i * 2 + 1) as u8);
206 }
207 }
208
209 fn get_modified_mask(&self) -> u64 {
210 self.inner.get_modified_mask()
211 }
212
213 fn clear_modified_mask(&mut self) {
214 self.inner.clear_modified_mask()
215 }
216
217 fn get_io_register_mask(&self) -> u64 {
218 1u64 << (self.smccc as u8) | 1
220 }
221
222 fn get_name(&self) -> String {
223 format!(
224 "Arm64RegisterIo<pre_advanced={}, smccc={}>",
225 self.pre_advanced, self.smccc
226 )
227 }
228
229 fn set_vtl_input(&mut self, vtl_input: u64) {
230 assert_eq!(vtl_input, 0);
232 }
233
234 fn auto_advance_ip(&mut self) {
235 if self.pre_advanced {
236 let pc = self.inner.pc().wrapping_add(4);
237 self.inner.set_pc(pc);
238 }
239 }
240 }
241}