diff --git a/runtime/src/ops/misc.rs b/runtime/src/ops/misc.rs index a4c06e3d..ac92b5a8 100644 --- a/runtime/src/ops/misc.rs +++ b/runtime/src/ops/misc.rs @@ -12,6 +12,22 @@ impl Context { .write::(segofs(self.cpu.regs.ss, self.cpu.regs.get_sp()), x); } + /// cpuid, describing a plain Pentium: an FPU and nothing else (no TSC, no + /// MMX), so programs take the paths this runtime implements. + pub fn cpuid(&mut self) { + let (eax, ebx, ecx, edx) = match self.cpu.regs.eax { + // Highest leaf, and "GenuineIntel" in ebx:edx:ecx. + 0 => (1, 0x756e_6547, 0x6c65_746e, 0x4965_6e69), + // Family 5 model 4 stepping 3; feature flags: FPU. + 1 => (0x543, 0, 0, 0x1), + _ => (0, 0, 0, 0), + }; + self.cpu.regs.eax = eax; + self.cpu.regs.ebx = ebx; + self.cpu.regs.ecx = ecx; + self.cpu.regs.edx = edx; + } + pub fn pop32(&mut self) -> u32 { let x = self.memory.read::(self.cpu.regs.esp); self.cpu.regs.esp += 4; diff --git a/tc/src/codegen/misc.rs b/tc/src/codegen/misc.rs index 827dd83d..e1338b00 100644 --- a/tc/src/codegen/misc.rs +++ b/tc/src/codegen/misc.rs @@ -93,7 +93,37 @@ impl<'a> CodeGen<'a> { self.todo(format!("int {:#x}", instr.immediate8())); } } - Int3 | Cmpxchg | Pushfd | Cpuid | Xgetbv | Bt | Div => self.todo(instr_name(instr)), + Int3 | Cmpxchg | Xgetbv | Div => self.todo(instr_name(instr)), + + Cpuid => self.line("ctx.cpuid();"), + + Bt => { + // With a memory operand and a register index the hardware can + // address bits outside the operand; only handle the in-range forms. + if instr.op0_kind() == iced_x86::OpKind::Memory + && instr.op1_kind() == iced_x86::OpKind::Register + { + self.todo(format!("{instr}")); + return true; + } + let size = op_size(instr, 0); + self.line(format!( + "let bit = ({} as u32) % {size};", + self.get_op(instr, 1) + )); + self.line(format!( + "ctx.cpu.flags.set(Flags::CF, ({} >> bit) & 1 != 0);", + self.get_op(instr, 0) + )); + } + + Pushfd => self.line("ctx.push32(ctx.cpu.flags.bits());"), + Popfd => { + // Keep bits we don't model (like ID, bit 21) so that the usual + // "can I toggle ID?" probe for cpuid support sees them again. + self.line("let flags = ctx.pop32();"); + self.line("ctx.cpu.flags = Flags::from_bits_retain(flags);"); + } // CBW/CWDE: sign extend to next larger ax Cbw => self.line("ctx.cpu.regs.set_ax(ctx.cpu.regs.get_al() as i8 as i16 as u16);"),