aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/display.rs40
-rw-r--r--src/lib.rs667
-rw-r--r--test/test.rs88
3 files changed, 764 insertions, 31 deletions
diff --git a/src/display.rs b/src/display.rs
index f6067fb..35cd210 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -281,11 +281,11 @@ impl fmt::Display for Opcode {
&Opcode::RDTSC => write!(f, "{}", "rdtsc"),
&Opcode::RDPMC => write!(f, "{}", "rdpmc"),
&Opcode::FXSAVE => write!(f, "{}", "fxsave"),
- &Opcode::FXRSTOR => write!(f, "{}", "fxstor"),
+ &Opcode::FXRSTOR => write!(f, "{}", "fxrstor"),
&Opcode::LDMXCSR => write!(f, "{}", "ldmxcsr"),
&Opcode::STMXCSR => write!(f, "{}", "stmxcsr"),
&Opcode::XSAVE => write!(f, "{}", "xsave"),
- &Opcode::XSTOR => write!(f, "{}", "xstor"),
+ &Opcode::XRSTOR => write!(f, "{}", "xrstor"),
&Opcode::XSAVEOPT => write!(f, "{}", "xsaveopt"),
&Opcode::LFENCE => write!(f, "{}", "lfence"),
&Opcode::MFENCE => write!(f, "{}", "mfence"),
@@ -544,6 +544,23 @@ impl fmt::Display for Opcode {
&Opcode::BLSI => write!(f, "{}", "blsi"),
&Opcode::BLSMSK => write!(f, "{}", "blsmsk"),
&Opcode::BLSR => write!(f, "{}", "blsr"),
+ &Opcode::VMCALL => write!(f, "{}", "vmcall"),
+ &Opcode::VMLAUNCH => write!(f, "{}", "vmlaunch"),
+ &Opcode::VMRESUME => write!(f, "{}", "vmresume"),
+ &Opcode::VMXOFF => write!(f, "{}", "vmxoff"),
+ &Opcode::MONITOR => write!(f, "{}", "monitor"),
+ &Opcode::MWAIT => write!(f, "{}", "mwait"),
+ &Opcode::CLAC => write!(f, "{}", "clac"),
+ &Opcode::STAC => write!(f, "{}", "stac"),
+ &Opcode::ENCLS => write!(f, "{}", "encls"),
+ &Opcode::XGETBV => write!(f, "{}", "xgetbv"),
+ &Opcode::XSETBV => write!(f, "{}", "xsetbv"),
+ &Opcode::VMFUNC => write!(f, "{}", "vmfunc"),
+ &Opcode::XEND => write!(f, "{}", "xend"),
+ &Opcode::XTEST => write!(f, "{}", "xtest"),
+ &Opcode::ENCLU => write!(f, "{}", "enclu"),
+ &Opcode::RDPKRU => write!(f, "{}", "rdpkru"),
+ &Opcode::WRPKRU => write!(f, "{}", "wrpkru"),
&Opcode::VMOVUPS => write!(f, "{}", "vmovups"),
&Opcode::VADDPD => write!(f, "{}", "vaddpd"),
&Opcode::VADDPS => write!(f, "{}", "vaddps"),
@@ -1510,7 +1527,7 @@ impl <T: std::fmt::Write> Colorize<T> for Opcode {
Opcode::LDMXCSR |
Opcode::STMXCSR |
Opcode::XSAVE |
- Opcode::XSTOR |
+ Opcode::XRSTOR |
Opcode::XSAVEOPT |
Opcode::LFENCE |
Opcode::MFENCE |
@@ -1550,6 +1567,23 @@ impl <T: std::fmt::Write> Colorize<T> for Opcode {
Opcode::UD2E |
Opcode::VMREAD |
Opcode::VMWRITE |
+ Opcode::VMCALL |
+ Opcode::VMLAUNCH |
+ Opcode::VMRESUME |
+ Opcode::VMXOFF |
+ Opcode::MONITOR |
+ Opcode::MWAIT |
+ Opcode::CLAC |
+ Opcode::STAC |
+ Opcode::ENCLS |
+ Opcode::XGETBV |
+ Opcode::XSETBV |
+ Opcode::VMFUNC |
+ Opcode::XEND |
+ Opcode::XTEST |
+ Opcode::ENCLU |
+ Opcode::RDPKRU |
+ Opcode::WRPKRU |
Opcode::LAR => { write!(out, "{}", colors.platform_op(self)) }
Opcode::VAESDEC |
diff --git a/src/lib.rs b/src/lib.rs
index 6b8237b..ab9541d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -406,6 +406,17 @@ const BMI1: [Opcode; 6] = [
Opcode::TZCNT,
];
+// TODO:
+// PTWRITE
+// RDFSBASE
+// RDGSBASE
+// WRFSBASE
+// WRGSBASE
+// TPAUSE
+// UMONITOR
+// UMWAIT
+// CLFLUSHOPT
+// CLWB
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Opcode {
@@ -596,7 +607,7 @@ pub enum Opcode {
LDMXCSR,
STMXCSR,
XSAVE,
- XSTOR,
+ XRSTOR,
XSAVEOPT,
LFENCE,
MFENCE,
@@ -639,6 +650,23 @@ pub enum Opcode {
BLSI,
BLSMSK,
BLSR,
+ VMCALL,
+ VMLAUNCH,
+ VMRESUME,
+ VMXOFF,
+ MONITOR,
+ MWAIT,
+ CLAC,
+ STAC,
+ ENCLS,
+ XGETBV,
+ XSETBV,
+ VMFUNC,
+ XEND,
+ XTEST,
+ ENCLU,
+ RDPKRU,
+ WRPKRU,
ADDPS,
ANDNPS,
@@ -1082,6 +1110,7 @@ pub enum Opcode {
VXORPS,
VZEROUPPER,
}
+
#[derive(Debug)]
pub struct Instruction {
pub prefixes: Prefixes,
@@ -1222,6 +1251,8 @@ pub struct InstDecoder {
// 50. xop
// 51. skinit
// 52. tbm
+ // 53. intel quirks
+ // 54. amd quirks
flags: u64,
}
@@ -1236,15 +1267,503 @@ impl InstDecoder {
}
}
- fn bmi1(&self) -> bool {
+ pub fn sse3(&self) -> bool {
+ self.flags & (1 << 0) != 0
+ }
+
+ pub fn with_sse3(mut self) -> Self {
+ self.flags |= 1 << 0;
+ self
+ }
+
+ pub fn ssse3(&self) -> bool {
+ self.flags & (1 << 1) != 0
+ }
+
+ pub fn with_ssse3(mut self) -> Self {
+ self.flags |= 1 << 1;
+ self
+ }
+
+ pub fn monitor(&self) -> bool {
+ self.flags & (1 << 2) != 0
+ }
+
+ pub fn with_monitor(mut self) -> Self {
+ self.flags |= 1 << 2;
+ self
+ }
+
+ pub fn vmx(&self) -> bool {
+ self.flags & (1 << 3) != 0
+ }
+
+ pub fn with_vmx(mut self) -> Self {
+ self.flags |= 1 << 3;
+ self
+ }
+
+ pub fn fma3(&self) -> bool {
+ self.flags & (1 << 4) != 0
+ }
+
+ pub fn with_fma3(mut self) -> Self {
+ self.flags |= 1 << 4;
+ self
+ }
+
+ pub fn cmpxchg16b(&self) -> bool {
+ self.flags & (1 << 5) != 0
+ }
+
+ pub fn with_cmpxchg16b(mut self) -> Self {
+ self.flags |= 1 << 5;
+ self
+ }
+
+ pub fn sse4_1(&self) -> bool {
+ self.flags & (1 << 6) != 0
+ }
+
+ pub fn with_sse4_1(mut self) -> Self {
+ self.flags |= 1 << 6;
+ self
+ }
+
+ pub fn sse4_2(&self) -> bool {
+ self.flags & (1 << 7) != 0
+ }
+
+ pub fn with_sse4_2(mut self) -> Self {
+ self.flags |= 1 << 7;
+ self
+ }
+
+ pub fn movbe(&self) -> bool {
+ self.flags & (1 << 8) != 0
+ }
+
+ pub fn with_movbe(mut self) -> Self {
+ self.flags |= 1 << 8;
+ self
+ }
+
+ pub fn popcnt(&self) -> bool {
+ self.flags & (1 << 9) != 0
+ }
+
+ pub fn with_popcnt(mut self) -> Self {
+ self.flags |= 1 << 9;
+ self
+ }
+
+ pub fn aesni(&self) -> bool {
+ self.flags & (1 << 10) != 0
+ }
+
+ pub fn with_aesni(mut self) -> Self {
+ self.flags |= 1 << 10;
+ self
+ }
+
+ pub fn xsave(&self) -> bool {
+ self.flags & (1 << 11) != 0
+ }
+
+ pub fn with_xsave(mut self) -> Self {
+ self.flags |= 1 << 11;
+ self
+ }
+
+ pub fn rdrand(&self) -> bool {
+ self.flags & (1 << 12) != 0
+ }
+
+ pub fn with_rdrand(mut self) -> Self {
+ self.flags |= 1 << 12;
+ self
+ }
+
+ pub fn sgx(&self) -> bool {
self.flags & (1 << 13) != 0
}
- pub fn without_bmi1(mut self) -> Self {
- self.flags &= (!(1 << 13));
+ pub fn with_sgx(mut self) -> Self {
+ self.flags |= 1 << 13;
+ self
+ }
+
+ pub fn bmi1(&self) -> bool {
+ self.flags & (1 << 14) != 0
+ }
+
+ pub fn with_bmi1(mut self) -> Self {
+ self.flags |= 1 << 14;
+ self
+ }
+
+ pub fn avx2(&self) -> bool {
+ self.flags & (1 << 15) != 0
+ }
+
+ pub fn with_avx2(mut self) -> Self {
+ self.flags |= 1 << 15;
+ self
+ }
+
+ pub fn bmi2(&self) -> bool {
+ self.flags & (1 << 16) != 0
+ }
+
+ pub fn with_bmi2(mut self) -> Self {
+ self.flags |= 1 << 16;
+ self
+ }
+
+ pub fn invpcid(&self) -> bool {
+ self.flags & (1 << 17) != 0
+ }
+
+ pub fn with_invpcid(mut self) -> Self {
+ self.flags |= 1 << 17;
+ self
+ }
+
+ pub fn mpx(&self) -> bool {
+ self.flags & (1 << 18) != 0
+ }
+
+ pub fn with_mpx(mut self) -> Self {
+ self.flags |= 1 << 18;
+ self
+ }
+
+ pub fn avx512_f(&self) -> bool {
+ self.flags & (1 << 19) != 0
+ }
+
+ pub fn with_avx512_f(mut self) -> Self {
+ self.flags |= 1 << 19;
+ self
+ }
+
+ pub fn avx512_dq(&self) -> bool {
+ self.flags & (1 << 20) != 0
+ }
+
+ pub fn with_avx512_dq(mut self) -> Self {
+ self.flags |= 1 << 20;
+ self
+ }
+
+ pub fn rdseed(&self) -> bool {
+ self.flags & (1 << 21) != 0
+ }
+
+ pub fn with_rdseed(mut self) -> Self {
+ self.flags |= 1 << 21;
+ self
+ }
+
+ pub fn adx(&self) -> bool {
+ self.flags & (1 << 22) != 0
+ }
+
+ pub fn with_adx(mut self) -> Self {
+ self.flags |= 1 << 22;
+ self
+ }
+
+ pub fn avx512_fma(&self) -> bool {
+ self.flags & (1 << 23) != 0
+ }
+
+ pub fn with_avx512_fma(mut self) -> Self {
+ self.flags |= 1 << 23;
+ self
+ }
+
+ pub fn pcommit(&self) -> bool {
+ self.flags & (1 << 24) != 0
+ }
+
+ pub fn with_pcommit(mut self) -> Self {
+ self.flags |= 1 << 24;
+ self
+ }
+
+ pub fn clflushopt(&self) -> bool {
+ self.flags & (1 << 25) != 0
+ }
+
+ pub fn with_clflushopt(mut self) -> Self {
+ self.flags |= 1 << 25;
+ self
+ }
+
+ pub fn clwb(&self) -> bool {
+ self.flags & (1 << 26) != 0
+ }
+
+ pub fn with_clwb(mut self) -> Self {
+ self.flags |= 1 << 26;
+ self
+ }
+
+ pub fn avx512_pf(&self) -> bool {
+ self.flags & (1 << 27) != 0
+ }
+
+ pub fn with_avx512_pf(mut self) -> Self {
+ self.flags |= 1 << 27;
+ self
+ }
+
+ pub fn avx512_er(&self) -> bool {
+ self.flags & (1 << 28) != 0
+ }
+
+ pub fn with_avx512_er(mut self) -> Self {
+ self.flags |= 1 << 28;
+ self
+ }
+
+ pub fn avx512_cd(&self) -> bool {
+ self.flags & (1 << 29) != 0
+ }
+
+ pub fn with_avx512_cd(mut self) -> Self {
+ self.flags |= 1 << 29;
+ self
+ }
+
+ pub fn sha(&self) -> bool {
+ self.flags & (1 << 30) != 0
+ }
+
+ pub fn with_sha(mut self) -> Self {
+ self.flags |= 1 << 30;
+ self
+ }
+
+ pub fn avx512_bw(&self) -> bool {
+ self.flags & (1 << 31) != 0
+ }
+
+ pub fn with_avx512_bw(mut self) -> Self {
+ self.flags |= 1 << 31;
self
}
+ pub fn avx512_vl(&self) -> bool {
+ self.flags & (1 << 32) != 0
+ }
+
+ pub fn with_avx512_vl(mut self) -> Self {
+ self.flags |= 1 << 32;
+ self
+ }
+
+ pub fn prefetchwt1(&self) -> bool {
+ self.flags & (1 << 33) != 0
+ }
+
+ pub fn with_prefetchwt1(mut self) -> Self {
+ self.flags |= 1 << 33;
+ self
+ }
+
+ pub fn avx512_vbmi(&self) -> bool {
+ self.flags & (1 << 34) != 0
+ }
+
+ pub fn with_avx512_vbmi(mut self) -> Self {
+ self.flags |= 1 << 34;
+ self
+ }
+
+ pub fn avx512_vbmi2(&self) -> bool {
+ self.flags & (1 << 35) != 0
+ }
+
+ pub fn with_avx512_vbmi2(mut self) -> Self {
+ self.flags |= 1 << 35;
+ self
+ }
+
+ pub fn gfni(&self) -> bool {
+ self.flags & (1 << 36) != 0
+ }
+
+ pub fn with_gfni(mut self) -> Self {
+ self.flags |= 1 << 36;
+ self
+ }
+
+ pub fn vaes(&self) -> bool {
+ self.flags & (1 << 37) != 0
+ }
+
+ pub fn with_vaes(mut self) -> Self {
+ self.flags |= 1 << 37;
+ self
+ }
+
+ pub fn vpclmulqdq(&self) -> bool {
+ self.flags & (1 << 38) != 0
+ }
+
+ pub fn with_vpclmulqdq(mut self) -> Self {
+ self.flags |= 1 << 38;
+ self
+ }
+
+ pub fn avx_vnni(&self) -> bool {
+ self.flags & (1 << 39) != 0
+ }
+
+ pub fn with_avx_vnni(mut self) -> Self {
+ self.flags |= 1 << 39;
+ self
+ }
+
+ pub fn avx512_bitalg(&self) -> bool {
+ self.flags & (1 << 40) != 0
+ }
+
+ pub fn with_avx512_bitalg(mut self) -> Self {
+ self.flags |= 1 << 40;
+ self
+ }
+
+ pub fn avx512_vpopcntdq(&self) -> bool {
+ self.flags & (1 << 41) != 0
+ }
+
+ pub fn with_avx512_vpopcntdq(mut self) -> Self {
+ self.flags |= 1 << 41;
+ self
+ }
+
+ pub fn avx512_4vnniw(&self) -> bool {
+ self.flags & (1 << 42) != 0
+ }
+
+ pub fn with_avx512_4vnniw(mut self) -> Self {
+ self.flags |= 1 << 42;
+ self
+ }
+
+ pub fn avx512_4fmaps(&self) -> bool {
+ self.flags & (1 << 43) != 0
+ }
+
+ pub fn with_avx512_4fmaps(mut self) -> Self {
+ self.flags |= 1 << 43;
+ self
+ }
+
+ pub fn cx8(&self) -> bool {
+ self.flags & (1 << 44) != 0
+ }
+
+ pub fn with_cx8(mut self) -> Self {
+ self.flags |= 1 << 44;
+ self
+ }
+
+ pub fn syscall(&self) -> bool {
+ self.flags & (1 << 45) != 0
+ }
+
+ pub fn with_syscall(mut self) -> Self {
+ self.flags |= 1 << 45;
+ self
+ }
+
+ pub fn rdtscp(&self) -> bool {
+ self.flags & (1 << 46) != 0
+ }
+
+ pub fn with_rdtscp(mut self) -> Self {
+ self.flags |= 1 << 46;
+ self
+ }
+
+ pub fn abm(&self) -> bool {
+ self.flags & (1 << 47) != 0
+ }
+
+ pub fn with_abm(mut self) -> Self {
+ self.flags |= 1 << 47;
+ self
+ }
+
+ pub fn sse4a(&self) -> bool {
+ self.flags & (1 << 48) != 0
+ }
+
+ pub fn with_sse4a(mut self) -> Self {
+ self.flags |= 1 << 48;
+ self
+ }
+
+ pub fn _3dnowprefetch(&self) -> bool {
+ self.flags & (1 << 49) != 0
+ }
+
+ pub fn with_3dnowprefetch(mut self) -> Self {
+ self.flags |= 1 << 49;
+ self
+ }
+
+ pub fn xop(&self) -> bool {
+ self.flags & (1 << 50) != 0
+ }
+
+ pub fn with_xop(mut self) -> Self {
+ self.flags |= 1 << 50;
+ self
+ }
+
+ pub fn skinit(&self) -> bool {
+ self.flags & (1 << 51) != 0
+ }
+
+ pub fn with_skinit(mut self) -> Self {
+ self.flags |= 1 << 51;
+ self
+ }
+
+ pub fn tbm(&self) -> bool {
+ self.flags & (1 << 52) != 0
+ }
+
+ pub fn with_tbm(mut self) -> Self {
+ self.flags |= 1 << 52;
+ self
+ }
+
+ pub fn intel_quirks(&self) -> bool {
+ self.flags & (1 << 53) != 0
+ }
+
+ pub fn with_intel_quirks(mut self) -> Self {
+ self.flags |= 1 << 53;
+ self
+ }
+
+ pub fn amd_quirks(&self) -> bool {
+ self.flags & (1 << 54) != 0
+ }
+
+ pub fn with_amd_quirks(mut self) -> Self {
+ self.flags |= 1 << 54;
+ self
+ }
+
+ /// Optionally reject or reinterpret instruction according to the decoder's
+ /// declared extensions.
fn revise_instruction(&self, inst: &mut Instruction) -> Result<(), ()> {
match inst.opcode {
Opcode::TZCNT => {
@@ -3564,7 +4083,7 @@ pub fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T
unsafe { unreachable_unchecked(); }
}
instruction.prefixes = prefixes;
- read_operands(bytes_iter, instruction, record.1, &mut length)?;
+ read_operands(decoder, bytes_iter, instruction, record.1, &mut length)?;
instruction.length = length;
if decoder != &InstDecoder::default() {
@@ -3574,7 +4093,7 @@ pub fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T
}
Ok(())
}
-pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, length: &mut u8) -> Result<(), ()> {
+pub fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, length: &mut u8) -> Result<(), ()> {
let mut bytes_read = 0;
if (operand_code as u8) & 0x40 == 0x40 {
instruction.operands[0] = OperandSpec::RegRRR;
@@ -4135,14 +4654,14 @@ pub fn read_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
instruction.operand_count = 0;
}
_ => {
- unlikely_operands(bytes_iter, instruction, operand_code, mem_oper, length)?;
+ unlikely_operands(decoder, bytes_iter, instruction, operand_code, mem_oper, length)?;
}
};
}
Ok(())
}
-fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec, length: &mut u8) -> Result<(), ()> {
+fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec, length: &mut u8) -> Result<(), ()> {
let mut bytes_read = 0;
match operand_code {
OperandCode::ModRM_0x0f71 => {
@@ -4504,7 +5023,7 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
} else if r == 7 {
instruction.opcode = Opcode::Invalid;
instruction.operand_count = 0;
- return Ok(());
+ return Err(());
} else {
unreachable!("r <= 8");
}
@@ -4518,7 +5037,25 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
let mod_bits = modrm >> 6;
let m = modrm & 7;
if mod_bits == 0b11 {
- panic!("Unsupported instruction: 0x0f01 with modrm: 11 000 ___");
+ instruction.operand_count = 0;
+ match m {
+ 0b001 => {
+ instruction.opcode = Opcode::VMCALL;
+ },
+ 0b010 => {
+ instruction.opcode = Opcode::VMLAUNCH;
+ },
+ 0b011 => {
+ instruction.opcode = Opcode::VMRESUME;
+ },
+ 0b100 => {
+ instruction.opcode = Opcode::VMXOFF;
+ },
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }
} else {
instruction.opcode = Opcode::SGDT;
instruction.operand_count = 1;
@@ -4528,9 +5065,28 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
let mod_bits = modrm >> 6;
let m = modrm & 7;
if mod_bits == 0b11 {
- // TOOD: MONITOR
- instruction.opcode = Opcode::NOP;
instruction.operand_count = 0;
+ match m {
+ 0b000 => {
+ instruction.opcode = Opcode::MONITOR;
+ }
+ 0b001 => {
+ instruction.opcode = Opcode::MWAIT;
+ },
+ 0b010 => {
+ instruction.opcode = Opcode::CLAC;
+ }
+ 0b011 => {
+ instruction.opcode = Opcode::STAC;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::ENCLS;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }
} else {
instruction.opcode = Opcode::SIDT;
instruction.operand_count = 1;
@@ -4540,9 +5096,31 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
let mod_bits = modrm >> 6;
let m = modrm & 7;
if mod_bits == 0b11 {
- // TOOD: XGETBV
- instruction.opcode = Opcode::NOP;
instruction.operand_count = 0;
+ match m {
+ 0b000 => {
+ instruction.opcode = Opcode::XGETBV;
+ }
+ 0b001 => {
+ instruction.opcode = Opcode::XSETBV;
+ }
+ 0b100 => {
+ instruction.opcode = Opcode::VMFUNC;
+ }
+ 0b101 => {
+ instruction.opcode = Opcode::XEND;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::XTEST;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::ENCLU;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }
} else {
instruction.opcode = Opcode::LGDT;
instruction.operand_count = 1;
@@ -4552,9 +5130,9 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
let mod_bits = modrm >> 6;
let m = modrm & 7;
if mod_bits == 0b11 {
- // TOOD: VMRUN
- instruction.opcode = Opcode::NOP;
+ instruction.opcode = Opcode::Invalid;
instruction.operand_count = 0;
+ return Err(());
} else {
instruction.opcode = Opcode::LIDT;
instruction.operand_count = 1;
@@ -4567,7 +5145,22 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
instruction.operand_count = 1;
instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?;
} else if r == 5 {
- panic!("Unsupported instruction: 0x0f01 with modrm: __ 101 ___");
+ let m = modrm & 7;
+ match m {
+ 0b110 => {
+ instruction.opcode = Opcode::RDPKRU;
+ instruction.operand_count = 1;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::WRPKRU;
+ instruction.operand_count = 1;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ instruction.operand_count = 0;
+ return Err(());
+ }
+ }
} else if r == 6 {
instruction.opcode = Opcode::LMSW;
instruction.operand_count = 1;
@@ -4583,8 +5176,8 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
instruction.opcode = Opcode::RDTSCP;
instruction.operand_count = 0;
} else {
- // panic!("Unsupported instruction: 0x0f01 with modrm: 11 110 r >= 2");
- return Err(()); // Err("unsupported 0x0f01 variant".to_string())
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
}
} else {
instruction.opcode = Opcode::INVLPG;
@@ -4603,19 +5196,44 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
// all the 0b11 instructions are err or no-operands
if mod_bits == 0b11 {
instruction.operand_count = 0;
+ let m = modrm & 7;
match r {
// invalid rrr for 0x0fae, mod: 11
0 | 1 | 2 | 3 | 4 => {
return Err(());
},
5 => {
- instruction.opcode = Opcode::LFENCE
+ instruction.opcode = Opcode::LFENCE;
+ // TODO: verify on real hardware
+ // AMD's manual suggests their chips reject *FENCE with non-zero r/m
+ if decoder.amd_quirks() && !decoder.intel_quirks() {
+ if m != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }
},
6 => {
- instruction.opcode = Opcode::MFENCE
+ instruction.opcode = Opcode::MFENCE;
+ // TODO: verify on real hardware
+ // AMD's manual suggests their chips reject *FENCE with non-zero r/m
+ if decoder.amd_quirks() && !decoder.intel_quirks() {
+ if m != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }
},
7 => {
- instruction.opcode = Opcode::SFENCE
+ instruction.opcode = Opcode::SFENCE;
+ // TODO: verify on real hardware
+ // AMD's manual suggests their chips reject *FENCE with non-zero r/m
+ if decoder.amd_quirks() && !decoder.intel_quirks() {
+ if m != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }
},
_ => { unsafe { unreachable_unchecked() } /* r <=7 */ }
}
@@ -4627,12 +5245,9 @@ fn unlikely_operands<T: Iterator<Item=u8>>(mut bytes_iter: T, instruction: &mut
Opcode::LDMXCSR,
Opcode::STMXCSR,
Opcode::XSAVE,
- Opcode::XSTOR,
- // TODO: radare reports this, but i'm not sure?
+ Opcode::XRSTOR,
Opcode::XSAVEOPT,
- // TODO: radare reports this, but i'm not sure?
Opcode::CLFLUSH,
- Opcode::Invalid,
][r as usize];
instruction.operands[0] = read_M(&mut bytes_iter, instruction, modrm, length)?;
}
diff --git a/test/test.rs b/test/test.rs
index 3b902dc..5c78c7c 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -97,6 +97,90 @@ fn test_cvt() {
}
#[test]
+fn test_0f01() {
+ // drawn heavily from "Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group
+ // Number"
+ test_display(&[0x0f, 0x01, 0x38], "invlpg [rax]");
+ test_display(&[0x0f, 0x01, 0x3f], "invlpg [rdi]");
+ test_display(&[0x0f, 0x01, 0x40, 0xff], "sgdt [rax - 0x1]");
+ test_display(&[0x0f, 0x01, 0x41, 0xff], "sgdt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x49, 0xff], "sidt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x51, 0xff], "lgdt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x59, 0xff], "lidt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x61, 0xff], "smsw [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0xc0], "enclv");
+ test_display(&[0x0f, 0x01, 0xc1], "vmcall");
+ test_display(&[0x0f, 0x01, 0xc2], "vmlaunch");
+ test_display(&[0x0f, 0x01, 0xc3], "vmresume");
+ test_display(&[0x0f, 0x01, 0xc4], "vmxoff");
+ test_invalid(&[0x0f, 0x01, 0xc5]);
+ test_invalid(&[0x0f, 0x01, 0xc6]);
+ test_invalid(&[0x0f, 0x01, 0xc7]);
+ test_display(&[0x0f, 0x01, 0xc8], "monitor");
+ test_display(&[0x0f, 0x01, 0xc9], "mwait");
+ test_display(&[0x0f, 0x01, 0xca], "clac");
+ test_display(&[0x0f, 0x01, 0xcb], "stac");
+ test_display(&[0x0f, 0x01, 0xcf], "encls");
+ test_display(&[0x0f, 0x01, 0xd0], "xgetbv");
+ test_display(&[0x0f, 0x01, 0xd1], "xsetbv");
+ test_invalid(&[0x0f, 0x01, 0xd2]);
+ test_invalid(&[0x0f, 0x01, 0xd3]);
+ test_display(&[0x0f, 0x01, 0xd4], "vmfunc");
+ test_display(&[0x0f, 0x01, 0xd5], "xend");
+ test_display(&[0x0f, 0x01, 0xd6], "xtest");
+ test_display(&[0x0f, 0x01, 0xd7], "enclu");
+ test_invalid(&[0x0f, 0x01, 0xd8]);
+ test_invalid(&[0x0f, 0x01, 0xd9]);
+ test_invalid(&[0x0f, 0x01, 0xda]);
+ test_invalid(&[0x0f, 0x01, 0xdb]);
+ test_invalid(&[0x0f, 0x01, 0xdc]);
+ test_invalid(&[0x0f, 0x01, 0xdd]);
+ test_invalid(&[0x0f, 0x01, 0xde]);
+ test_invalid(&[0x0f, 0x01, 0xdf]);
+ test_display(&[0x0f, 0x01, 0xee], "rdpkru");
+ test_display(&[0x0f, 0x01, 0xef], "wrpkru");
+ test_display(&[0x0f, 0x01, 0xf8], "swapgs");
+ test_display(&[0x0f, 0x01, 0xf9], "rdtscp");
+}
+
+#[test]
+fn test_0fae() {
+ let intel = InstDecoder::minimal().with_intel_quirks();
+ let amd = InstDecoder::minimal().with_amd_quirks();
+ let default = InstDecoder::default();
+ // drawn heavily from "Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group
+ // Number"
+ test_display(&[0x0f, 0xae, 0x04, 0x4f], "fxsave [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x0c, 0x4f], "fxrstor [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x14, 0x4f], "ldmxcsr [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x1c, 0x4f], "stmxcsr [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x24, 0x4f], "xsave [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x2c, 0x4f], "xrstor [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x34, 0x4f], "xsaveopt [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x3c, 0x4f], "clflush [rdi + rcx * 2]");
+
+ for (modrm, text) in &[(0xe8u8, "lfence"), (0xf0u8, "mfence"), (0xf8u8, "sfence")] {
+ test_display_under(&intel, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&amd, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&default, &[0x0f, 0xae, *modrm], text);
+ // it turns out intel accepts m != 0 for {l,m,s}fence, but amd does not:
+ // from intel:
+ // ```
+ // Specification of the instruction's opcode above indicates a ModR/M byte of F0. For this
+ // instruction, the processor ignores the r/m field of the ModR/M byte. Thus, MFENCE is encoded
+ // by any opcode of the form 0F AE Fx, where x is in the range 0-7.
+ // ```
+ // whereas amd does not discuss the r/m field at all. it is TBD if amd also ignores the r/m
+ // field, but for now assumed to be rejected.
+ for m in 1u8..8u8 {
+ test_display_under(&intel, &[0x0f, 0xae, modrm | m], text);
+ test_invalid_under(&amd, &[0x0f, 0xae, modrm | m]);
+ test_display_under(&default, &[0x0f, 0xae, modrm | m], text);
+ }
+ }
+}
+
+#[test]
fn test_system() {
test_display(&[0x66, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8]");
test_display(&[0x67, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8d]");
@@ -248,8 +332,8 @@ fn test_push_pop() {
#[test]
fn test_bmi1() {
- let bmi1 = InstDecoder::default();
- let no_bmi1 = InstDecoder::default().without_bmi1();
+ let bmi1 = InstDecoder::minimal().with_bmi1();
+ let no_bmi1 = InstDecoder::minimal();
test_display_under(&bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "tzcnt edx, r11d");
test_display_under(&no_bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d");
}