diff options
| author | iximeow <me@iximeow.net> | 2026-04-19 15:54:48 +0000 |
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2026-04-19 15:54:48 +0000 |
| commit | d4999e6bb0cb4ea4d8530b1c3ece1143c6bf9740 (patch) | |
| tree | 4eb10aa7060115b76780a05242e1a071d575a743 | |
| parent | a605fb0ade2e215bdafd9034d986be71774db13f (diff) | |
the rest of sse?
| -rw-r--r-- | src/long_mode/behavior.rs | 122 | ||||
| -rw-r--r-- | test/long_mode/behavior.rs | 113 |
2 files changed, 179 insertions, 56 deletions
diff --git a/src/long_mode/behavior.rs b/src/long_mode/behavior.rs index cec8d1b..aaf3f8a 100644 --- a/src/long_mode/behavior.rs +++ b/src/long_mode/behavior.rs @@ -976,6 +976,10 @@ pub enum ComplexOp { /// TODO: document SWAPGS, + RDFSBASE, + WRFSBASE, + RDGSBASE, + WRGSBASE, } /// a visitor for collecting architectural accesses for an `Instruction`. used with @@ -2234,6 +2238,15 @@ static MONITOR_OPS: &'static [ImplicitOperand] = &[ }, ]; +static SHA256RNDS2_OPS: &'static [ImplicitOperand] = &[ + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::xmm0(), + disp: 0i32, + write: false, + }, +]; + const PUSH_OPS_IDX: u16 = 1; const POP_OPS_IDX: u16 = 2; const JCC_OPS_IDX: u16 = 3; @@ -2282,8 +2295,9 @@ const CMPXCHG16B_IDX: u16 = 45; const RDTSCP_IDX: u16 = 46; const MASKMOVQ_IDX: u16 = 47; const MONITOR_IDX: u16 = 48; +const SHA256RNDS2_IDX: u16 = 49; -static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 49] = [ +static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 50] = [ &[], // implicit ops list 0 is not used PUSH_OPS, POP_OPS, @@ -2333,6 +2347,7 @@ static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 49] = [ RDTSCP_OPS, MASKMOVQ_OPS, MONITOR_OPS, + SHA256RNDS2_OPS, ]; #[inline(never)] @@ -2408,9 +2423,9 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { DIVSD => GENERAL_RW_R, MINSD => GENERAL_RW_R, MAXSD => GENERAL_RW_R, - MOVSLDUP => { panic!("todo: movsldup"); }, - MOVSHDUP => { panic!("todo: movshdup"); }, - MOVDDUP => { panic!("todo: movddup"); }, + MOVSLDUP => GENERAL_W_R, + MOVSHDUP => GENERAL_W_R, + MOVDDUP => GENERAL_W_R, HADDPS => GENERAL_RW_R, HSUBPS => GENERAL_RW_R, ADDSUBPD => GENERAL_RW_R, @@ -2671,19 +2686,21 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { MOVDQU => GENERAL_W_R, MOVDQA => GENERAL_W_R, MOVQ => GENERAL_W_R, - CMPSS => { panic!("todo: cmpss"); }, - CMPSD => { panic!("todo: cmpsd"); }, + CMPSS => GENERAL_RW_R + .set_operand(2, Access::Read), + CMPSD => GENERAL_RW_R + .set_operand(2, Access::Read), UNPCKLPS => GENERAL_RW_R, UNPCKLPD => GENERAL_RW_R, UNPCKHPS => GENERAL_RW_R, UNPCKHPD => GENERAL_RW_R, - PSHUFHW => { panic!("todo: pshufhw"); }, - PSHUFLW => { panic!("todo: pshuflw"); }, + PSHUFHW => GENERAL_W_R, + PSHUFLW => GENERAL_W_R, MOVUPS => GENERAL_W_R, - MOVQ2DQ => { panic!("todo: movq2dq"); }, - MOVDQ2Q => { panic!("todo: movdq2q"); }, + MOVQ2DQ => GENERAL_W_R, + MOVDQ2Q => GENERAL_W_R, RSQRTSS => GENERAL_RW_R, - RCPSS => { panic!("todo: rcpss"); }, + RCPSS => GENERAL_RW_R, ANDN => { panic!("todo: andn"); }, BEXTR => { panic!("todo: bextr"); }, @@ -2917,8 +2934,10 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VBROADCASTSD => { panic!("todo: vbroadcastsd"); }, VBROADCASTSS => { panic!("todo: vbroadcastss"); }, VCMPSD => { panic!("todo: vcmpsd"); }, - VCMPSS => { panic!("todo: vcmpss"); }, - VCMPPD => { panic!("todo: vcmppd"); }, + VCMPSS => GENERAL_W_R_R + .set_operand(3, Access::Read), + VCMPPD => GENERAL_W_R_R + .set_operand(3, Access::Read), VCMPPS => { panic!("todo: vcmpps"); }, VCVTDQ2PD => { panic!("todo: vcvtdq2pd"); }, VCVTDQ2PS => GENERAL_W_R, @@ -3046,8 +3065,8 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VMOVQ => GENERAL_W_R, VMOVSS => { panic!("todo: vmovss"); }, VMOVSD => { panic!("todo: vmovsd"); }, - VMOVSHDUP => { panic!("todo: vmovshdup"); }, - VMOVSLDUP => { panic!("todo: vmovsldup"); }, + VMOVSHDUP => GENERAL_W_R, + VMOVSLDUP => GENERAL_W_R, VMOVUPD => { panic!("todo: vmovupd"); }, VMOVUPS => { panic!("todo: vmovups"); }, VMPSADBW => { panic!("todo: vmpsadbw"); }, @@ -3120,7 +3139,7 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPHADDD => { panic!("todo: vphaddd"); }, VPHADDSW => { panic!("todo: vphaddsw"); }, VPHADDW => { panic!("todo: vphaddw"); }, - VPMADDUBSW => { panic!("todo: vpmaddubsw"); }, + VPMADDUBSW => GENERAL_W_R_R, VPHMINPOSUW => { panic!("todo: vphminposuw"); }, VPHSUBD => { panic!("todo: vphsubd"); }, VPHSUBSW => { panic!("todo: vphsubsw"); }, @@ -3158,7 +3177,7 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPMOVZXWD => { panic!("todo: vpmovzxwd"); }, VPMOVZXWQ => { panic!("todo: vpmovzxwq"); }, VPMULDQ => { panic!("todo: vpmuldq"); }, - VPMULHRSW => { panic!("todo: vpmulhrsw"); }, + VPMULHRSW => GENERAL_W_R_R, VPMULHUW => GENERAL_W_R_R, VPMULHW => { panic!("todo: vpmulhw"); }, VPMULLQ => GENERAL_W_R_R, @@ -3167,11 +3186,11 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPMULUDQ => { panic!("todo: vpmuludq"); }, VPOR => { panic!("todo: vpor"); }, VPSADBW => { panic!("todo: vpsadbw"); }, - VPSHUFB => { panic!("todo: vpshufb"); }, - VPSHUFD => { panic!("todo: vpshufd"); }, - VPSIGNB => { panic!("todo: vpsignb"); }, - VPSIGND => { panic!("todo: vpsignd"); }, - VPSIGNW => { panic!("todo: vpsignw"); }, + VPSHUFB => GENERAL_W_R_R, + VPSHUFD => GENERAL_W_R_R, + VPSIGNB => GENERAL_W_R_R, + VPSIGND => GENERAL_W_R_R, + VPSIGNW => GENERAL_W_R_R, VPSLLD => { panic!("todo: vpslld"); }, VPSLLDQ => { panic!("todo: vpslldq"); }, VPSLLQ => { panic!("todo: vpsllq"); }, @@ -3280,12 +3299,12 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { ROUNDSD => { panic!("todo: roundsd"); }, ROUNDPS => { panic!("todo: roundps"); }, ROUNDPD => { panic!("todo: roundpd"); }, - PMAXSB => { panic!("todo: pmaxsb"); }, - PMAXSD => { panic!("todo: pmaxsd"); }, + PMAXSB => GENERAL_RW_R, + PMAXSD => GENERAL_RW_R, PMAXUW => GENERAL_RW_R, PMAXUD => GENERAL_RW_R, - PMINSD => { panic!("todo: pminsd"); }, - PMINSB => { panic!("todo: pminsb"); }, + PMINSD => GENERAL_RW_R, + PMINSB => GENERAL_RW_R, PMINUD => GENERAL_RW_R, PMINUW => GENERAL_RW_R, BLENDW => { panic!("todo: blendw"); }, @@ -3299,31 +3318,32 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { MOVNTDQA => { panic!("todo: movntdqa"); }, PMULLD => GENERAL_RW_R, PALIGNR => { panic!("todo: palignr"); }, - PSIGNW => { panic!("todo: psignw"); }, - PSIGND => { panic!("todo: psignd"); }, - PSIGNB => { panic!("todo: psignb"); }, - PSHUFB => { panic!("todo: pshufb"); }, - PMULHRSW => { panic!("todo: pmulhrsw"); }, - PMADDUBSW => { panic!("todo: pmaddubsw"); }, - PABSD => { panic!("todo: pabsd"); }, - PABSW => { panic!("todo: pabsw"); }, - PABSB => { panic!("todo: pabsb"); }, - PHSUBSW => { panic!("todo: phsubsw"); }, - PHSUBW => { panic!("todo: phsubw"); }, - PHSUBD => { panic!("todo: phsubd"); }, - PHADDD => { panic!("todo: phaddd"); }, - PHADDSW => { panic!("todo: phaddsw"); }, - PHADDW => { panic!("todo: phaddw"); }, + PSIGNW => GENERAL_RW_R, + PSIGND => GENERAL_RW_R, + PSIGNB => GENERAL_RW_R, + PSHUFB => GENERAL_RW_R, + PMULHRSW => GENERAL_RW_R, + PMADDUBSW => GENERAL_RW_R, + PABSD => GENERAL_W_R, + PABSW => GENERAL_W_R, + PABSB => GENERAL_W_R, + PHSUBSW => GENERAL_RW_R, + PHSUBW => GENERAL_RW_R, + PHSUBD => GENERAL_RW_R, + PHADDD => GENERAL_RW_R, + PHADDSW => GENERAL_RW_R, + PHADDW => GENERAL_RW_R, HSUBPD => GENERAL_RW_R, HADDPD => GENERAL_RW_R, - SHA1RNDS4 => { panic!("todo: sha1rnds4"); }, - SHA1NEXTE => { panic!("todo: sha1nexte"); }, - SHA1MSG1 => { panic!("todo: sha1msg1"); }, - SHA1MSG2 => { panic!("todo: sha1msg2"); }, - SHA256RNDS2 => { panic!("todo: sha256rnds2"); }, - SHA256MSG1 => { panic!("todo: sha256msg1"); }, - SHA256MSG2 => { panic!("todo: sha256msg2"); }, + SHA1RNDS4 => GENERAL_RW_R_R, + SHA1NEXTE => GENERAL_RW_R, + SHA1MSG1 => GENERAL_RW_R, + SHA1MSG2 => GENERAL_RW_R, + SHA256RNDS2 => GENERAL_RW_R + .set_implicit_ops(SHA256RNDS2_IDX), + SHA256MSG1 => GENERAL_RW_R, + SHA256MSG2 => GENERAL_RW_R, LZCNT => { panic!("todo: lzcnt"); }, CLGI => { panic!("todo: clgi"); }, @@ -3344,7 +3364,7 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { .set_operand(2, Access::Read), TLBSYNC => { panic!("todo: tlbsync"); }, - MOVBE => { panic!("todo: movbe"); }, + MOVBE => GENERAL_W_R, ADCX => { panic!("todo: adcx"); }, ADOX => { panic!("todo: adox"); }, @@ -3553,8 +3573,8 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { JRCXZ => { panic!("todo: jrcxz"); }, // started shipping in Tremont, 2020 sept 23 - MOVDIR64B => { panic!("todo: movdir64b"); }, - MOVDIRI => { panic!("todo: movdiri"); }, + MOVDIR64B => GENERAL_W_R, + MOVDIRI => GENERAL_W_R, // started shipping in Tiger Lake, 2020 sept 2 AESDEC128KL => { panic!("todo: aesdec128kl"); }, diff --git a/test/long_mode/behavior.rs b/test/long_mode/behavior.rs index 72021f7..dd3d270 100644 --- a/test/long_mode/behavior.rs +++ b/test/long_mode/behavior.rs @@ -1259,6 +1259,11 @@ mod kvm { continue; } + if buf.opcode() == Opcode::RDPID { + // rdpid is a specialized rdmsr + continue; + } + if buf.opcode() == Opcode::RDTSC { // the TSC keeps ticking so eax will change across runs and trip the // "cared about dontcares" check. @@ -1364,7 +1369,7 @@ mod kvm { } #[test] - fn behavior_verify_kvm_0f_() { + fn behavior_verify_kvm_0f__() { use yaxpeax_arch::{Decoder, U8Reader}; use yaxpeax_x86::long_mode::{Instruction, Opcode}; @@ -1402,7 +1407,7 @@ mod kvm { } #[test] - fn behavior_verify_kvm_66_0f_() { + fn behavior_verify_kvm_66_0f__() { use yaxpeax_arch::{Decoder, U8Reader}; use yaxpeax_x86::long_mode::{Instruction, Opcode}; @@ -1414,7 +1419,7 @@ mod kvm { let mut buf = Instruction::default(); let initial_regs = vm.get_regs().unwrap(); - for word in 0xf001..u16::MAX { + for word in 0x0000..u16::MAX { let inst = word.to_le_bytes(); let bytes = [0x66, 0x0f, inst[0], inst[1]]; let mut reader = U8Reader::new(&bytes); @@ -1440,6 +1445,44 @@ mod kvm { } #[test] + fn behavior_verify_kvm_f3_0f__() { + use yaxpeax_arch::{Decoder, U8Reader}; + use yaxpeax_x86::long_mode::{Instruction, Opcode}; + + let mut vm = create_test_vm(); + vm.set_single_step(true).expect("can enable single-step"); + + // TODO: happen to be testing on a zen 5 system, so i picked a zen 5 decoder. + let decoder = long_mode::uarch::amd::zen5(); + let mut buf = Instruction::default(); + let initial_regs = vm.get_regs().unwrap(); + + for word in 0xec00..u16::MAX { + let inst = word.to_le_bytes(); + let bytes = [0xf3, 0x0f, inst[0], inst[1]]; + let mut reader = U8Reader::new(&bytes); + if decoder.decode_into(&mut buf, &mut reader).is_ok() { + // two byte instructions were covered by `verify_kvm`, novel instructions are three + // bytes (or longer..?) + use yaxpeax_arch::LengthedInstruction; + let inst_len = 0.wrapping_offset(buf.len()) as usize; + if inst_len != 4 { + continue; + } + + if not_generic(&buf) { + continue; + } + + eprintln!("checking behavior of f3 0f {:02x} {:02x}: {}", inst[0], inst[1], buf); + + vm.set_regs(&initial_regs).unwrap(); + check_behavior(&mut vm, &bytes[..inst_len]).expect("behavior check is ok"); + } + } + } + + #[test] fn behavior_verify_kvm_0f_38_() { use yaxpeax_arch::{Decoder, U8Reader}; use yaxpeax_x86::long_mode::{Instruction, Opcode}; @@ -1452,7 +1495,7 @@ mod kvm { let mut buf = Instruction::default(); let initial_regs = vm.get_regs().unwrap(); - for word in 0xf001..u16::MAX { + for word in 0x0000..u16::MAX { let inst = word.to_le_bytes(); let bytes = [0x0f, 0x38, inst[0], inst[1]]; let mut reader = U8Reader::new(&bytes); @@ -1469,7 +1512,7 @@ mod kvm { continue; } - eprintln!("checking behavior of 66 0f {:02x} {:02x}: {}", inst[0], inst[1], buf); + eprintln!("checking behavior of 0f 38 {:02x} {:02x}: {}", inst[0], inst[1], buf); vm.set_regs(&initial_regs).unwrap(); check_behavior(&mut vm, &bytes[..inst_len]).expect("behavior check is ok"); @@ -1485,6 +1528,10 @@ mod kvm { return true; } + if ptwrite::OPCODES.contains(&instr.opcode()) { + return true; + } + if vm_instrs::OPCODES.contains(&instr.opcode()) { // this generic testing facility is not appropriate for VM instructions. return true; @@ -1510,6 +1557,11 @@ mod kvm { return true; } + if instr.opcode() == Opcode::RDPID { + // rdpid is a specialized rdmsr + return true; + } + if instr.opcode() == Opcode::RDTSCP { // raises #UD without CPUID leaf 80000001 edx.rdtscp (bit 27) return true; @@ -1525,6 +1577,10 @@ mod kvm { return true; } + if cet::OPCODES.contains(&instr.opcode()) { + return true; + } + if rands::OPCODES.contains(&instr.opcode()) { return true; } @@ -1561,6 +1617,10 @@ mod kvm { return true; } + if uintr::OPCODES.contains(&instr.opcode()) { + return true; + } + if Opcode::MONITOR == instr.opcode() { return true; } @@ -1598,6 +1658,22 @@ mod kvm { return false; } + mod cet { + use yaxpeax_x86::long_mode::{Instruction, Opcode}; + + pub static OPCODES: &'static [Opcode] = &[ + Opcode::WRUSS, + Opcode::WRSS, + Opcode::INCSSP, + Opcode::SAVEPREVSSP, + Opcode::SETSSBSY, + Opcode::CLRSSBSY, + Opcode::RSTORSSP, + Opcode::ENDBR64, + Opcode::ENDBR32, + ]; + } + // TODO: these don't fit in the generic harness because the destination register is scrombled // and checking permutations will assume the instruction depends on some missed read (which // *is* kinda true...) @@ -1657,6 +1733,19 @@ mod kvm { } + mod uintr { + use yaxpeax_x86::long_mode::{Instruction, Opcode}; + + pub static OPCODES: &'static [Opcode] = &[ + Opcode::UIRET, + Opcode::SENDUIPI, + Opcode::TESTUI, + Opcode::CLUI, + Opcode::STUI, + ]; + + } + mod undef { use yaxpeax_x86::long_mode::{Instruction, Opcode}; @@ -1710,6 +1799,15 @@ mod kvm { } + mod ptwrite { + use yaxpeax_x86::long_mode::{Instruction, Opcode}; + + pub static OPCODES: &'static [Opcode] = &[ + Opcode::PTWRITE, + ]; + + } + mod mpk { use yaxpeax_x86::long_mode::{Instruction, Opcode}; @@ -1731,6 +1829,11 @@ mod kvm { Opcode::STMXCSR, Opcode::LMSW, Opcode::SMSW, + Opcode::SWAPGS, + Opcode::RDFSBASE, + Opcode::WRFSBASE, + Opcode::RDGSBASE, + Opcode::WRGSBASE, ]; } |
