1use crate::Cpu;
7use crate::opcodes::Aarch64DecodeGroup;
8use crate::opcodes::Aarch64DecodeLoadStoreGroup;
9use crate::opcodes::LoadRegisterLiteral;
10use crate::opcodes::LoadStoreAtomic;
11use crate::opcodes::LoadStoreRegister;
12use crate::opcodes::LoadStoreRegisterPair;
13use crate::opcodes::decode_group;
14use aarch64defs::EsrEl2;
15use inspect::Inspect;
16use thiserror::Error;
17
18#[derive(Debug, Error)]
19pub enum Error<E> {
20 #[error("unknown instruction: {0:#x?}")]
21 UnsupportedInstruction(u32),
22 #[error("unsupported instruction group: {0:?} {1:#x?}")]
23 UnsupportedInstructionGroup(Aarch64DecodeGroup, u32),
24 #[error("unsupported load/store instruction: {0:?} {1:#x?}")]
25 UnsupportedLoadStoreInstruction(Aarch64DecodeLoadStoreGroup, u32),
26 #[error("unsupported instruction set (thumb)")]
27 UnsupportedInstructionSet,
28 #[error("memory access error - {1:?} @ {0:#x}")]
29 MemoryAccess(u64, OperationKind, #[source] E),
30}
31
32#[derive(Debug, Default, Inspect)]
33pub struct InterceptState {
34 pub instruction_bytes: [u8; 4],
35 pub instruction_byte_count: u8,
36 pub gpa: Option<u64>,
37 #[inspect(hex, with = "|&x| u64::from(x)")]
38 pub syndrome: EsrEl2,
39 pub interruption_pending: bool,
40}
41
42enum InternalError<E> {
43 Error(Box<Error<E>>),
45}
46
47impl<E> From<Error<E>> for InternalError<E> {
48 fn from(err: Error<E>) -> Self {
49 InternalError::Error(Box::new(err))
50 }
51}
52
53impl<E> From<Box<Error<E>>> for InternalError<E> {
54 fn from(err: Box<Error<E>>) -> Self {
55 InternalError::Error(err)
56 }
57}
58
59#[derive(Debug)]
60pub(crate) struct EmulatorOperations<T: Cpu> {
61 pub cpu: T,
62}
63
64impl<T: Cpu> EmulatorOperations<T> {
65 pub async fn read_instruction(
67 &mut self,
68 gva: u64,
69 data: &mut [u8],
70 ) -> Result<(), Box<Error<T::Error>>> {
71 self.cpu
72 .read_instruction(gva, data)
73 .await
74 .map_err(|err| Error::MemoryAccess(gva, OperationKind::Read, err))?;
75 Ok(())
76 }
77
78 pub async fn read_memory(
80 &mut self,
81 gva: u64,
82 data: &mut [u8],
83 ) -> Result<(), Box<Error<T::Error>>> {
84 self.cpu
85 .read_memory(gva, data)
86 .await
87 .map_err(|err| Error::MemoryAccess(gva, OperationKind::Read, err))?;
88 Ok(())
89 }
90
91 pub async fn read_physical_memory(
93 &mut self,
94 gpa: u64,
95 data: &mut [u8],
96 exec: bool,
97 ) -> Result<(), Box<Error<T::Error>>> {
98 self.cpu
99 .read_physical_memory(gpa, data, exec)
100 .await
101 .map_err(|err| Error::MemoryAccess(gpa, OperationKind::Read, err))?;
102 Ok(())
103 }
104
105 pub async fn write_memory(
107 &mut self,
108 gva: u64,
109 data: &[u8],
110 ) -> Result<(), Box<Error<T::Error>>> {
111 self.cpu
112 .write_memory(gva, data)
113 .await
114 .map_err(|err| Error::MemoryAccess(gva, OperationKind::Write, err))?;
115 Ok(())
116 }
117
118 pub async fn write_physical_memory(
120 &mut self,
121 gpa: u64,
122 data: &[u8],
123 ) -> Result<(), Box<Error<T::Error>>> {
124 self.cpu
125 .write_physical_memory(gpa, data)
126 .await
127 .map_err(|err| Error::MemoryAccess(gpa, OperationKind::Write, err))?;
128 Ok(())
129 }
130
131 pub async fn compare_and_write_memory(
133 &mut self,
134 gva: u64,
135 current: &[u8],
136 new: &[u8],
137 ) -> Result<bool, Box<Error<T::Error>>> {
138 let mut success = false;
139 self.cpu
140 .compare_and_write_memory(gva, current, new, &mut success)
141 .await
142 .map_err(|err| Error::MemoryAccess(gva, OperationKind::Write, err))?;
143 Ok(success)
144 }
145}
146
147#[derive(Debug)]
149pub struct Emulator<'a, T: Cpu> {
150 inner: EmulatorOperations<T>,
151 intercept_state: &'a InterceptState,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq)]
155pub enum OperationKind {
156 Read,
157 Write,
158 AddressComputation,
159}
160
161impl<'a, T: Cpu> Emulator<'a, T> {
162 pub fn new(cpu: T, intercept_state: &'a InterceptState) -> Self {
164 Emulator {
165 inner: EmulatorOperations { cpu },
166 intercept_state,
167 }
168 }
169
170 fn advance_pc(&mut self, count: u64) {
171 let new_pc = self.inner.cpu.pc().wrapping_add(count);
172 self.inner.cpu.update_pc(new_pc);
173 }
174
175 async fn decode_with_syndrome(&mut self) -> Result<bool, InternalError<T::Error>> {
176 let Some(gpa) = self.intercept_state.gpa else {
177 return Ok(false);
178 };
179 let syndrome = self.intercept_state.syndrome;
180 if !matches!(
181 aarch64defs::ExceptionClass(syndrome.ec()),
182 aarch64defs::ExceptionClass::DATA_ABORT | aarch64defs::ExceptionClass::DATA_ABORT_LOWER
183 ) {
184 return Ok(false);
185 }
186
187 let iss: u32 = (syndrome.lower_iss() as u32)
188 | ((syndrome.wnr() as u32) << 6)
189 | ((syndrome.mid_iss() as u32) << 7)
190 | ((syndrome.b_srt() as u32) << 16)
191 | ((syndrome.a() as u32) << 21)
192 | ((syndrome.b() as u32) << 22)
193 | ((syndrome.c() as u32) << 23)
194 | ((syndrome.d() as u32) << 24);
195 let iss = aarch64defs::IssDataAbort::from(iss);
196 if !iss.isv() {
197 return Ok(false);
198 }
199 let len = 1 << iss.sas();
200 let sign_extend = iss.sse();
201
202 let reg_index = iss.srt();
215 if iss.wnr() {
216 let data = match reg_index {
217 0..=30 => self.inner.cpu.x(reg_index),
218 31 => 0_u64,
219 _ => unreachable!(),
220 }
221 .to_ne_bytes();
222 self.inner.write_physical_memory(gpa, &data[..len]).await?;
223 } else if reg_index != 31 {
224 let mut data = [0; 8];
225 self.inner
227 .read_physical_memory(gpa, &mut data[..len], false)
228 .await?;
229 let mut data = u64::from_ne_bytes(data);
230 if sign_extend {
231 let shift = 64 - len * 8;
232 data = ((data as i64) << shift >> shift) as u64;
233 if !iss.sf() {
234 data &= 0xffffffff;
235 }
236 }
237 self.inner.cpu.update_x(reg_index, data);
238 }
239 self.advance_pc(if syndrome.il() { 4 } else { 2 });
240 Ok(true)
241 }
242
243 pub async fn run(&mut self) -> Result<(), Box<Error<T::Error>>> {
244 match self.decode_with_syndrome().await {
245 Ok(false) => (),
246 Ok(true) => return Ok(()),
247 Err(InternalError::Error(err)) => {
248 tracing::error!(%err, "Error decoding access via syndrome");
249 }
250 };
251
252 let instruction = if self.intercept_state.instruction_byte_count > 0 {
254 if self.intercept_state.instruction_byte_count != 4 {
255 return Err(Box::new(Error::UnsupportedInstructionSet));
256 }
257 u32::from_ne_bytes(self.intercept_state.instruction_bytes)
258 } else {
259 let mut bytes = [0_u8; 4];
260 let pc = self.inner.cpu.pc();
261 self.inner.read_instruction(pc, &mut bytes[..]).await?;
262 u32::from_ne_bytes(bytes)
263 };
264 let instruction_type = decode_group(instruction)?;
265 match self.emulate(instruction, instruction_type).await {
266 Ok(()) => {
267 self.advance_pc(4);
268 Ok(())
269 }
270 Err(InternalError::Error(err)) => Err(err),
271 }
272 }
273
274 async fn emulate(
278 &mut self,
279 opcode: u32,
280 instruction_type: Aarch64DecodeGroup,
281 ) -> Result<(), InternalError<T::Error>> {
282 let result = match instruction_type {
285 Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::UnscaledImmediate)
286 | Aarch64DecodeGroup::LoadStore(
287 Aarch64DecodeLoadStoreGroup::RegisterUnscaledImmediate,
288 )
289 | Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::RegisterUnprivileged)
290 | Aarch64DecodeGroup::LoadStore(
291 Aarch64DecodeLoadStoreGroup::RegisterImmediatePostIndex,
292 )
293 | Aarch64DecodeGroup::LoadStore(
294 Aarch64DecodeLoadStoreGroup::RegisterImmediatePreIndex,
295 )
296 | Aarch64DecodeGroup::LoadStore(
297 Aarch64DecodeLoadStoreGroup::RegisterUnsignedImmediate,
298 )
299 | Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::RegisterOffset) => {
300 LoadStoreRegister(opcode).emulate(&mut self.inner).await
301 }
302 Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::RegisterLiteral) => {
303 LoadRegisterLiteral(opcode).emulate(&mut self.inner).await
304 }
305 Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::NoAllocatePair)
306 | Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::RegisterPairPostIndex)
307 | Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::RegisterPairOffset)
308 | Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::RegisterPairPreIndex) => {
309 LoadStoreRegisterPair(opcode).emulate(&mut self.inner).await
310 }
311 Aarch64DecodeGroup::LoadStore(Aarch64DecodeLoadStoreGroup::Atomic) => {
312 LoadStoreAtomic(opcode).emulate(&mut self.inner).await
313 }
314 Aarch64DecodeGroup::LoadStore(typ) => {
315 return Err(InternalError::Error(Box::new(
316 Error::UnsupportedLoadStoreInstruction(typ, opcode),
317 )));
318 }
319 group => {
320 return Err(InternalError::Error(Box::new(
321 Error::UnsupportedInstructionGroup(group, opcode),
322 )));
323 }
324 };
325 result.map_err(InternalError::Error)
326 }
327}