1use super::AlignmentMode;
5use super::Emulator;
6use super::InternalError;
7use super::arith::ArithOp;
8use crate::Cpu;
9use crate::Segment;
10use iced_x86::Instruction;
11use iced_x86::OpKind;
12use iced_x86::Register;
13
14pub const MAX_REP_LOOPS: u64 = 1024;
18
19struct RepState {
21 pub count_reg: Register,
22 pub done: u64,
23 pub requested: u64,
24 pub rep: Option<RepPrefix>,
25 pub size: usize,
26 pub delta: u64,
27}
28
29#[derive(Clone, Copy)]
31enum RepPrefix {
32 Rep,
33 Repe(bool),
34 Repne(bool),
35}
36
37impl RepState {
38 fn update_zero(&mut self, new_zero: bool) {
39 self.rep = match self.rep {
40 Some(RepPrefix::Repe(_)) => Some(RepPrefix::Repe(new_zero)),
41 Some(RepPrefix::Repne(_)) => Some(RepPrefix::Repne(new_zero)),
42 Some(RepPrefix::Rep) => unreachable!(),
43 None => None,
44 }
45 }
46
47 fn check_done<E>(&self) -> Result<(), InternalError<E>> {
48 if !self.is_done() {
49 return Err(InternalError::Retry);
50 }
51 Ok(())
52 }
53
54 fn is_done(&self) -> bool {
55 match self.rep {
56 Some(RepPrefix::Repe(zero)) if !zero => return true,
57 Some(RepPrefix::Repne(zero)) if zero => return true,
58 _ => {}
59 }
60
61 self.done == self.requested
62 }
63}
64
65fn sized_rcx(op_kind: OpKind) -> Register {
67 match op_kind {
68 OpKind::MemorySegSI | OpKind::MemorySegDI | OpKind::MemoryESDI => Register::CX,
69 OpKind::MemorySegESI | OpKind::MemorySegEDI | OpKind::MemoryESEDI => Register::ECX,
70 OpKind::MemorySegRSI | OpKind::MemorySegRDI | OpKind::MemoryESRDI => Register::RCX,
71 _ => unreachable!(),
72 }
73}
74
75fn sized_rdi(op_kind: OpKind) -> Register {
77 match op_kind {
78 OpKind::MemorySegDI | OpKind::MemoryESDI => Register::DI,
79 OpKind::MemorySegEDI | OpKind::MemoryESEDI => Register::EDI,
80 OpKind::MemorySegRDI | OpKind::MemoryESRDI => Register::RDI,
81 _ => unreachable!(),
82 }
83}
84
85fn sized_rsi(op_kind: OpKind) -> Register {
87 match op_kind {
88 OpKind::MemorySegSI => Register::SI,
89 OpKind::MemorySegESI => Register::ESI,
90 OpKind::MemorySegRSI => Register::RSI,
91 _ => unreachable!(),
92 }
93}
94
95impl<T: Cpu> Emulator<'_, T> {
96 fn rep_op(
98 &mut self,
99 instr: &Instruction,
100 op_kind: OpKind,
101 is_cmps_scas: bool,
102 ) -> Result<RepState, InternalError<T::Error>> {
103 let rep = match (
106 is_cmps_scas,
107 instr.has_rep_prefix(),
108 instr.has_repne_prefix(),
109 ) {
110 (_, false, false) => None,
111 (false, true, false) => Some(RepPrefix::Rep),
112 (false, false, true) => Some(RepPrefix::Rep),
114 (true, true, false) => Some(RepPrefix::Repe(true)),
115 (true, false, true) => Some(RepPrefix::Repne(false)),
116 (_, true, true) => unreachable!(),
117 };
118
119 let count_reg = sized_rcx(op_kind);
120 let requested = if rep.is_some() {
121 self.cpu.gp(count_reg.into())
122 } else {
123 1
124 };
125 let size = instr.memory_size().size();
126 let delta = if !self.cpu.rflags().direction() {
127 size
128 } else {
129 size.wrapping_neg()
130 };
131
132 Ok(RepState {
133 count_reg,
134 rep,
135 done: 0,
136 requested,
137 size,
138 delta: delta as u64,
139 })
140 }
141
142 fn rep_again(&mut self, rep_state: &mut RepState) -> bool {
143 if rep_state.rep.is_some() {
144 self.cpu.set_gp(
145 rep_state.count_reg.into(),
146 rep_state.requested - rep_state.done,
147 );
148 }
149 if rep_state.is_done() || rep_state.done == MAX_REP_LOOPS {
150 return false;
151 }
152 rep_state.done += 1;
153 true
154 }
155
156 pub(super) async fn outs(
160 &mut self,
161 instr: &Instruction,
162 ) -> Result<(), InternalError<T::Error>> {
163 let mut rep = self.rep_op(instr, instr.op1_kind(), false)?;
164 let rsi = sized_rsi(instr.op1_kind());
165 while self.rep_again(&mut rep) {
166 let data = &mut [0; 4][..rep.size];
167 let offset = self.memory_op_offset(instr, 1);
168 let io_register = self.cpu.gp(instr.op0_register().into()) as u16;
169
170 self.read_memory(
171 instr.memory_segment().into(),
172 offset,
173 AlignmentMode::Standard,
174 data,
175 )
176 .await?;
177 self.write_io(io_register, data).await?;
178
179 self.cpu.set_gp(rsi.into(), offset.wrapping_add(rep.delta));
180 }
181 rep.check_done()?;
182 Ok(())
183 }
184
185 pub(super) async fn ins(&mut self, instr: &Instruction) -> Result<(), InternalError<T::Error>> {
189 let mut rep = self.rep_op(instr, instr.op0_kind(), false)?;
190 let rdi = sized_rdi(instr.op0_kind());
191 while self.rep_again(&mut rep) {
192 let offset = self.memory_op_offset(instr, 0);
193 let io_register = self.cpu.gp(instr.op1_register().into()) as u16;
194
195 let data = &mut [0; 4][..rep.size];
196 self.read_io(io_register, data).await?;
197 self.write_memory(Segment::ES, offset, AlignmentMode::Standard, data)
198 .await?;
199
200 self.cpu.set_gp(rdi.into(), offset.wrapping_add(rep.delta));
201 }
202 rep.check_done()?;
203 Ok(())
204 }
205
206 pub(super) async fn lods(
210 &mut self,
211 instr: &Instruction,
212 ) -> Result<(), InternalError<T::Error>> {
213 let mut rep = self.rep_op(instr, instr.op1_kind(), false)?;
214 let rsi = sized_rsi(instr.op1_kind());
215 while self.rep_again(&mut rep) {
216 let offset = self.memory_op_offset(instr, 1);
217 let mut data = [0; 8];
218 self.read_memory(
219 instr.memory_segment().into(),
220 offset,
221 AlignmentMode::Standard,
222 &mut data[..rep.size],
223 )
224 .await?;
225
226 self.cpu
227 .set_gp(instr.op0_register().into(), u64::from_le_bytes(data));
228 self.cpu.set_gp(rsi.into(), offset.wrapping_add(rep.delta));
229 }
230 rep.check_done()?;
231 Ok(())
232 }
233
234 pub(super) async fn stos(
238 &mut self,
239 instr: &Instruction,
240 ) -> Result<(), InternalError<T::Error>> {
241 let mut rep = self.rep_op(instr, instr.op0_kind(), false)?;
242 let rdi = sized_rdi(instr.op0_kind());
243 while self.rep_again(&mut rep) {
244 let offset = self.memory_op_offset(instr, 0);
245 let data = self.cpu.gp(instr.op1_register().into()).to_le_bytes();
246 self.write_memory(
247 Segment::ES,
248 offset,
249 AlignmentMode::Standard,
250 &data[..rep.size],
251 )
252 .await?;
253
254 self.cpu.set_gp(rdi.into(), offset.wrapping_add(rep.delta));
255 }
256 rep.check_done()?;
257 Ok(())
258 }
259
260 pub(super) async fn movs(
264 &mut self,
265 instr: &Instruction,
266 ) -> Result<(), InternalError<T::Error>> {
267 let mut rep = self.rep_op(instr, instr.op0_kind(), false)?;
268 let rdi = sized_rdi(instr.op0_kind());
269 let rsi = sized_rsi(instr.op1_kind());
270 while self.rep_again(&mut rep) {
271 let data = &mut [0; 8][..rep.size];
272
273 let di_offset = self.memory_op_offset(instr, 0);
274 let si_offset = self.memory_op_offset(instr, 1);
275
276 self.read_memory(
277 instr.memory_segment().into(),
278 si_offset,
279 AlignmentMode::Standard,
280 data,
281 )
282 .await?;
283 self.write_memory(Segment::ES, di_offset, AlignmentMode::Standard, data)
284 .await?;
285
286 self.cpu
287 .set_gp(rsi.into(), si_offset.wrapping_add(rep.delta));
288 self.cpu
289 .set_gp(rdi.into(), di_offset.wrapping_add(rep.delta));
290 }
291 rep.check_done()?;
292 Ok(())
293 }
294
295 pub(super) async fn cmps(
299 &mut self,
300 instr: &Instruction,
301 ) -> Result<(), InternalError<T::Error>> {
302 let mut rep = self.rep_op(instr, instr.op0_kind(), true)?;
303 let rsi = sized_rsi(instr.op0_kind());
304 let rdi = sized_rdi(instr.op1_kind());
305 let mut left = 0;
306 let mut right = 0;
307 while self.rep_again(&mut rep) {
308 let mut data_left = [0; 8];
309 let mut data_right = [0; 8];
310
311 let si_offset = self.memory_op_offset(instr, 0);
312 let di_offset = self.memory_op_offset(instr, 1);
313
314 self.read_memory(
315 instr.memory_segment().into(),
316 si_offset,
317 AlignmentMode::Standard,
318 &mut data_left[..rep.size],
319 )
320 .await?;
321 self.read_memory(
322 Segment::ES,
323 di_offset,
324 AlignmentMode::Standard,
325 &mut data_right[..rep.size],
326 )
327 .await?;
328
329 left = u64::from_le_bytes(data_left);
330 right = u64::from_le_bytes(data_right);
331 rep.update_zero(left == right);
332
333 self.cpu
334 .set_gp(rsi.into(), si_offset.wrapping_add(rep.delta));
335 self.cpu
336 .set_gp(rdi.into(), di_offset.wrapping_add(rep.delta));
337 }
338
339 rep.check_done()?;
340 if rep.requested != 0 {
341 let mut rflags = self.cpu.rflags();
342 let result = super::arith::CmpOp::op(left, right, rflags);
343 super::arith::CmpOp::update_flags(&mut rflags, rep.size, result, left, right);
344 self.cpu.set_rflags(rflags);
345 }
346 Ok(())
347 }
348
349 pub(super) async fn scas(
353 &mut self,
354 instr: &Instruction,
355 ) -> Result<(), InternalError<T::Error>> {
356 let mut rep = self.rep_op(instr, instr.op1_kind(), true)?;
357 let rax = self.cpu.gp(instr.op0_register().into());
358 let rdi = sized_rdi(instr.op1_kind());
359 let mut memval = 0;
360 while self.rep_again(&mut rep) {
361 let mut data = [0; 8];
362 let di_offset = self.memory_op_offset(instr, 1);
363
364 self.read_memory(
365 Segment::ES,
366 di_offset,
367 AlignmentMode::Standard,
368 &mut data[..rep.size],
369 )
370 .await?;
371
372 memval = u64::from_le_bytes(data);
373 rep.update_zero(memval == rax);
374
375 self.cpu
376 .set_gp(rdi.into(), di_offset.wrapping_add(rep.delta));
377 }
378
379 rep.check_done()?;
380 if rep.requested != 0 {
381 let mut rflags = self.cpu.rflags();
382 let result = super::arith::CmpOp::op(rax, memval, rflags);
383 super::arith::CmpOp::update_flags(&mut rflags, rep.size, result, rax, memval);
384 self.cpu.set_rflags(rflags);
385 }
386 Ok(())
387 }
388}