aboutsummaryrefslogtreecommitdiff
path: root/test/long_mode/behavior.rs
diff options
context:
space:
mode:
Diffstat (limited to 'test/long_mode/behavior.rs')
-rw-r--r--test/long_mode/behavior.rs282
1 files changed, 188 insertions, 94 deletions
diff --git a/test/long_mode/behavior.rs b/test/long_mode/behavior.rs
index 18894d2..8c643c4 100644
--- a/test/long_mode/behavior.rs
+++ b/test/long_mode/behavior.rs
@@ -1346,7 +1346,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;
@@ -1358,103 +1358,90 @@ mod kvm {
let mut buf = Instruction::default();
let initial_regs = vm.get_regs().unwrap();
- for word in 0x0000..u16::MAX {
- let inst = word.to_le_bytes();
- let bytes = [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 == 2 {
- continue;
- }
-
- if not_generic(&buf) {
- continue;
+ for opc in 0xf0..=u8::MAX {
+ for bits in 0..=0x7f {
+ let mut instlen = 0;
+ let suffix = bits & 3;
+ let prefix = (bits >> 2) & 3;
+ let imm = (bits >> 4) & 3;
+ let opers = (bits >> 6) & 1;
+
+ let mut bytes = [0; 6]; // 0x66, 0x0f, inst[0], inst[1]];
+
+ match prefix {
+ 0b00 => { },
+ 0b01 => {
+ bytes[instlen] = 0x66;
+ instlen += 1;
+ }
+ 0b10 => {
+ bytes[instlen] = 0xf2;
+ instlen += 1;
+ }
+ 0b11 => {
+ bytes[instlen] = 0xf3;
+ instlen += 1;
+ }
+ _ => {}
}
- eprintln!("checking behavior of 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_66_0f__() {
- use yaxpeax_arch::{Decoder, U8Reader};
- use yaxpeax_x86::long_mode::Instruction;
+ bytes[instlen] = 0x0f;
+ instlen += 1;
- 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 0x0000..u16::MAX {
- let inst = word.to_le_bytes();
- let bytes = [0x66, 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;
+ match suffix {
+ 0b00 => { },
+ 0b01 => {
+ bytes[instlen] = 0x38;
+ instlen += 1;
+ }
+ 0b10 => {
+ bytes[instlen] = 0x3a;
+ instlen += 1;
+ }
+ _ => {}
}
- if not_generic(&buf) {
- continue;
+ bytes[instlen] = opc;
+ bytes[instlen + 1] = if opers == 0 {
+ 0x01
+ } else {
+ 0xc1
+ };
+ instlen += 2;
+
+ match imm {
+ 0b00 => { },
+ 0b01 => {
+ bytes[instlen] = 0x00;
+ instlen += 1;
+ },
+ 0b10 => {
+ bytes[instlen] = 0x01;
+ instlen += 1;
+ },
+ _ => {
+ bytes[instlen] = 0xff;
+ instlen += 1;
+ },
}
- eprintln!("checking behavior of 66 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_f3_0f__() {
- use yaxpeax_arch::{Decoder, U8Reader};
- use yaxpeax_x86::long_mode::Instruction;
-
- 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();
+ 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 decoded_len = 0.wrapping_offset(buf.len()) as usize;
+ if decoded_len != instlen {
+ continue;
+ }
- 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;
+ }
- if not_generic(&buf) {
- continue;
+ vm.set_regs(&initial_regs).unwrap();
+ check_behavior(&mut vm, &bytes[..instlen]).expect("behavior check is ok");
}
-
- 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");
}
}
}
@@ -1606,7 +1593,7 @@ mod kvm {
let initial_regs = vm.get_regs().unwrap();
#[allow(non_snake_case)]
- for opcode in 0x90..=u8::MAX {
+ for opcode in 0x00..=u8::MAX {
for prefix_bits in 0x00..0x400u16 {
let mmmmm = prefix_bits & 0b11111;
let prefix_1 = (0xe0 | mmmmm) as u8;
@@ -1711,7 +1698,7 @@ mod kvm {
}
#[test]
- fn behavior_verify_kvm_evex() {
+ fn behavior_verify_kvm_evex_noimm() {
use yaxpeax_arch::{Decoder, U8Reader};
use yaxpeax_x86::long_mode::Instruction;
@@ -1740,8 +1727,8 @@ mod kvm {
let initial_regs = vm.get_regs().unwrap();
#[allow(non_snake_case)]
- for opcode in 0x7d..=u8::MAX {
- for prefix_bits in 0x00..0x800u16 {
+ for opcode in 0x00..=u8::MAX {
+ for prefix_bits in 0x00..0x1000u16 {
let mmm = prefix_bits & 0b111;
let prefix_1 = (0xf0 | mmm) as u8;
@@ -1750,11 +1737,11 @@ mod kvm {
let b = (prefix_bits >> 6) & 1;
let W = (prefix_bits >> 7) & 1;
let LL = (prefix_bits >> 8) & 0b11;
- let k = (prefix_bits >> 10) & 1 != 0;
+ let k = (prefix_bits >> 10) & 11;
let prefix_2 = (0x7c | (W << 7) | pp) as u8;
- let aaa = if k { 0b001 } else { 0b111 };
+ let aaa = [0b000, 0b001, 0b010, 0b111][k as usize];
let prefix_3 = (0x08 | aaa | b << 4 | LL << 5 | z << 7) as u8;
let operands = (prefix_bits >> 9) & 0b1;
@@ -1791,6 +1778,89 @@ mod kvm {
}
}
+ #[test]
+ fn behavior_verify_kvm_evex_imm() {
+ use yaxpeax_arch::{Decoder, U8Reader};
+ use yaxpeax_x86::long_mode::Instruction;
+
+ 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()
+// .with_avx512(); // TODO: need to refine isa_settings.rs/revise_instruction().
+ .with_avx512_f()
+ .with_avx512_dq()
+ .with_avx512_fma()
+ .with_avx512_cd()
+ .with_avx512_bw()
+ .with_avx512_vl()
+ .with_avx512_vbmi()
+ .with_avx512_vbmi2()
+ .with_avx512_vnni()
+ .with_avx512_bitalg()
+ .with_avx512_vpopcntdq();
+ /*
+ .with_avx512_vpopcntdq() // TODO: VP2INTERSECT
+ .with_avx512_bf16() // TODO: BF16
+ */
+ let mut buf = Instruction::default();
+ let initial_regs = vm.get_regs().unwrap();
+
+ #[allow(non_snake_case)]
+ for opcode in 0x00..=u8::MAX {
+ for imm in [0x00, 0x01, 0x80, 0xff] {
+ for prefix_bits in 0x00..0x1000u16 {
+ let mmm = prefix_bits & 0b111;
+ let prefix_1 = (0xf0 | mmm) as u8;
+
+ let pp = (prefix_bits >> 3) & 0b11;
+ let z = (prefix_bits >> 5) & 1;
+ let b = (prefix_bits >> 6) & 1;
+ let W = (prefix_bits >> 7) & 1;
+ let LL = (prefix_bits >> 8) & 0b11;
+ let k = (prefix_bits >> 10) & 11;
+
+ let prefix_2 = (0x7c | (W << 7) | pp) as u8;
+
+ let aaa = [0b000, 0b001, 0b010, 0b111][k as usize];
+ let prefix_3 = (0x08 | aaa | b << 4 | LL << 5 | z << 7) as u8;
+
+ let operands = (prefix_bits >> 9) & 0b1;
+ static OPC_BYTE_TABLE: [u8; 2] = [0xc1, 0x01];
+
+ let bytes: [u8; 7] = [0x62, prefix_1, prefix_2, prefix_3, opcode, OPC_BYTE_TABLE[operands as usize], imm];
+ 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 != bytes.len() {
+ continue;
+ }
+
+ if not_generic(&buf) {
+ continue;
+ }
+
+ vm.set_regs(&initial_regs).unwrap();
+ let res = check_behavior(&mut vm, &bytes[..inst_len]);
+ match res {
+ Ok(()) => {}
+ Err(CheckErr::ComplexOp(op)) => {
+ // uncheckable but not a failure
+ }
+ Err(e) => {
+ panic!("check error: {:?}", e);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
// use the generic test harness for a handful of instructions that don't get covered in the
// general enumeration above
#[test]
@@ -1842,6 +1912,11 @@ mod kvm {
use yaxpeax_x86::long_mode::Opcode;
use yaxpeax_x86::long_mode::Operand;
fn not_generic(instr: &Instruction) -> bool {
+ if sse_gpr::OPCODES.contains(&instr.opcode()) {
+ // not having reads for xmm registers yet, these don't fit well with the test harness..
+ return true;
+ }
+
if table_instrs::OPCODES.contains(&instr.opcode()) {
// tested under `mod table_instrs`.
return true;
@@ -2203,6 +2278,25 @@ mod kvm {
];
}
+ mod sse_gpr {
+ use super::create_test_vm;
+ use super::test_prelude;
+ use super::MemPatch;
+ use super::check_behavior;
+ use super::check_behavior_with_regs;
+
+ use yaxpeax_arch::{Decoder, U8Reader};
+ use yaxpeax_x86::long_mode::{Instruction, Opcode};
+ use yaxpeax_x86::long_mode;
+
+ pub static OPCODES: &'static [Opcode] = &[
+ Opcode::PEXTRB,
+ Opcode::PEXTRW,
+ Opcode::PEXTRD,
+ Opcode::EXTRACTPS,
+ ];
+ }
+
// check the collection of {l,s}{g,i,l}dt. these instructions are at the combination of
// "interesting memory size" and "interesting [non]interaction with prefixes"
//