aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/long_mode/behavior.rs122
-rw-r--r--test/long_mode/behavior.rs113
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,
];
}