blob: 4629ac3f699d8404beed4543ef241cab636e0b95 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <gtest/gtest.h>
#include <zircon/errors.h>
#include <zircon/syscalls/hypervisor.h>
#include "garnet/bin/guest/vmm/arch/x64/decode.h"
namespace {
TEST(InstDecodeTest, failure) {
zx_vcpu_state_t vcpu_state;
ASSERT_EQ(inst_decode(nullptr, 0, 4, &vcpu_state, nullptr), ZX_ERR_BAD_STATE);
ASSERT_EQ(inst_decode(nullptr, 32, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_rex[] = {0b0100'0000, 0x00, 0b00'000'000}; // rex opcode modrm
ASSERT_EQ(inst_decode(bad_rex, 1, 4, &vcpu_state, nullptr),
ZX_ERR_NOT_SUPPORTED);
ASSERT_EQ(inst_decode(bad_rex, 2, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
ASSERT_EQ(inst_decode(bad_rex, 3, 4, &vcpu_state, nullptr),
ZX_ERR_NOT_SUPPORTED);
uint8_t bad_len[] = {0x00, 0b00'000'000}; // opcode modrm
ASSERT_EQ(inst_decode(bad_len, 2, 4, &vcpu_state, nullptr),
ZX_ERR_NOT_SUPPORTED);
ASSERT_EQ(inst_decode(bad_len, 2, 3, &vcpu_state, nullptr),
ZX_ERR_NOT_SUPPORTED);
}
TEST(InstDecodeTest, mov_89) {
zx_vcpu_state_t vcpu_state;
uint8_t bad_len[] = {0x89, 0, 0}; // opcode modrm ?
ASSERT_EQ(inst_decode(bad_len, 3, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_disp[] = {0x89, 0b01'000'000}; // opcode modrm
ASSERT_EQ(inst_decode(bad_disp, 2, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_h66[] = {0x66, 0b0100'1000, 0x89,
0b00'010'000}; // h66 rex opcode modrm
ASSERT_EQ(inst_decode(bad_h66, 4, 4, &vcpu_state, nullptr),
ZX_ERR_NOT_SUPPORTED);
// mov %ecx, (%rax)
uint8_t mov[] = {0x89, 0b00'001'000}; // opcode modrm
Instruction inst;
ASSERT_EQ(inst_decode(mov, 2, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// movw %cx, (%rax)
uint8_t mov_16bit[] = {0x89, 0b00'001'000}; // opcode modrm
ASSERT_EQ(inst_decode(mov_16bit, 2, 2, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// mov %r10d, (%rax)
uint8_t rex_mov[] = {0b0100'0100, 0x89, 0b00'010'000}; // rex opcode modrm
ASSERT_EQ(inst_decode(rex_mov, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r10);
EXPECT_EQ(inst.flags, nullptr);
// mov %ebx, 0x10(%rax)
uint8_t mov_disp_1[] = {0x89, 0b01'011'000, 0x10}; // opcode modrm disp
ASSERT_EQ(inst_decode(mov_disp_1, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov %ebx, 0x1000000(%rax)
uint8_t mov_disp_4[] = {0x89, 0b10'011'000, 0, 0,
0, 0x1}; // opcode modrm dis4 disp3 disp2 disp1
ASSERT_EQ(inst_decode(mov_disp_4, 6, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov %r12, 0x11(%rax)
uint8_t rex_mov_disp[] = {0b0100'1100, 0x89, 0b01'100'000,
0x11}; // rex opcode modrm disp
ASSERT_EQ(inst_decode(rex_mov_disp, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 8u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r12);
EXPECT_EQ(inst.flags, nullptr);
// mov %r14w, 0x13(%rax)
uint8_t h66_mov_disp[] = {0x66, 0b0100'0100, 0x89, 0b01'110'000,
0x13}; // h66 rex opcode modrm disp
ASSERT_EQ(inst_decode(h66_mov_disp, 5, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r14);
EXPECT_EQ(inst.flags, nullptr);
// mov %ebx, (%rax,%rcx,2)
uint8_t mov_sib[] = {0x89, 0b00'011'100, 0b01'001'000}; // opcode modrm sib
ASSERT_EQ(inst_decode(mov_sib, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov %ebx, 0x04(%rax,%rcx,1)
uint8_t mov_sib_disp[] = {0x89, 0b01'011'100, 0b00'001'000,
0x04}; // opcode modrm sib disp
ASSERT_EQ(inst_decode(mov_sib_disp, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov %eax, 0x00ABCDEF
uint8_t mov_sib_nobase[] = {
0x89, 0b00'000'100, 0b00'100'101, 0xEF,
0xCD, 0xAB, 0x00}; // opcode modrm sib disp4 disp3 disp2 disp1
ASSERT_EQ(inst_decode(mov_sib_nobase, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rax);
EXPECT_EQ(inst.flags, nullptr);
}
// 8-bit tests to compliment decode_mov_89.
TEST(InstDecodeTest, mov_88) {
zx_vcpu_state_t vcpu_state;
Instruction inst;
// movb %ah, (%rsi)
uint8_t mov_ah[] = {0x88, 0b00'100'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_ah, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb %bh, (%rsi)
uint8_t mov_bh[] = {0x88, 0b00'111'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_bh, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb %ch, (%rsi)
uint8_t mov_ch[] = {0x88, 0b00'101'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_ch, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb %dh, (%rsi)
uint8_t mov_dh[] = {0x88, 0b00'110'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_dh, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb %dil,(%rsi)
uint8_t rex_mov[] = {0b0100'0000, 0x88, 0b00'111'110}; // rex opcode modrm
ASSERT_EQ(inst_decode(rex_mov, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rdi);
EXPECT_EQ(inst.flags, nullptr);
}
TEST(InstDecodeTest, mov_8b) {
zx_vcpu_state_t vcpu_state;
uint8_t bad_len[] = {0x8b, 0, 0}; // opcode modrm ?
ASSERT_EQ(inst_decode(bad_len, 3, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_disp[] = {0x8b, 0b01'000'000}; // opcode modrm
ASSERT_EQ(inst_decode(bad_disp, 2, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_h66[] = {0x66, 0b0100'1000, 0x8b,
0b00'010'000}; // h66 rex opcode modrm
ASSERT_EQ(inst_decode(bad_h66, 4, 4, &vcpu_state, nullptr),
ZX_ERR_NOT_SUPPORTED);
// mov (%rax), %ecx
uint8_t mov[] = {0x8b, 0b00'001'000}; // opcode modrm
Instruction inst;
ASSERT_EQ(inst_decode(mov, 2, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// movw (%rax), %cx
uint8_t mov_16bit[] = {0x8b, 0b00'001'000}; // opcode modrm
ASSERT_EQ(inst_decode(mov_16bit, 2, 2, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// mov (%rax), %r10d
uint8_t rex_mov[] = {0b0100'0100, 0x8b, 0b00'010'000}; // rex opcode modrm
ASSERT_EQ(inst_decode(rex_mov, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r10);
EXPECT_EQ(inst.flags, nullptr);
// mov 0x10(%rax), %ebx
uint8_t mov_disp_1[] = {0x8b, 0b01'011'000, 0x10}; // opcode modrm disp
ASSERT_EQ(inst_decode(mov_disp_1, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov 0x10000000(%rax), %ebx
uint8_t mov_disp_4[] = {0x8b, 0b10'011'000, 0, 0,
0, 0x1}; // opcode modrm disp4 disp3 disp2 disp1
ASSERT_EQ(inst_decode(mov_disp_4, 6, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov 0x11(rax), %r12
uint8_t rex_mov_disp[] = {0b0100'1100, 0x8b, 0b01'100'000,
0x11}; // rex opcode modrm disp
ASSERT_EQ(inst_decode(rex_mov_disp, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 8u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r12);
EXPECT_EQ(inst.flags, nullptr);
// mov 0x13(rax), %r14w
uint8_t h66_mov_disp[] = {0x66, 0b0100'0100, 0x8b, 0b01'110'000,
0x13}; // h66 rex opcode modrm disp
ASSERT_EQ(inst_decode(h66_mov_disp, 5, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r14);
EXPECT_EQ(inst.flags, nullptr);
// mov (%rax,%rcx,2), %ebx
uint8_t mov_sib[] = {0x8b, 0b00'011'100, 0b01'001'000}; // opcode modrm sib
ASSERT_EQ(inst_decode(mov_sib, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov 0x04(%rax,%rcx,1), %ebx
uint8_t mov_sib_disp[] = {0x8b, 0b01'011'100, 0b00'001'000,
0x04}; // opcode modrm sib disp
ASSERT_EQ(inst_decode(mov_sib_disp, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// mov 0xABCDEF, %eax
uint8_t mov_sib_nobase[] = {
0x8b, 0b00'000'100, 0b00'100'101, 0xEF,
0xCD, 0xAB, 0x00}; // opcode modrm sib disp4 disp3 disp2 disp1
ASSERT_EQ(inst_decode(mov_sib_nobase, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rax);
EXPECT_EQ(inst.flags, nullptr);
}
// 8-bit tests to compliment decode_mov_8b.
TEST(InstDecodeTest, mov_8a) {
zx_vcpu_state_t vcpu_state;
Instruction inst;
// movb (%rsi), %ah
uint8_t mov_ah[] = {0x8a, 0b00'100'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_ah, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb (%rsi), %bh
uint8_t mov_bh[] = {0x8a, 0b00'111'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_bh, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb (%rsi), %ch
uint8_t mov_ch[] = {0x8a, 0b00'101'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_ch, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb (%rsi), %dh
uint8_t mov_dh[] = {0x8a, 0b00'110'110}; // opcode modrm
ASSERT_EQ(inst_decode(mov_dh, 2, 4, &vcpu_state, &inst),
ZX_ERR_NOT_SUPPORTED);
// movb (%rsi)
uint8_t rex_mov[] = {0b0100'0000, 0x8a, 0b00'111'110}; // rex opcode modrm
ASSERT_EQ(inst_decode(rex_mov, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rdi);
EXPECT_EQ(inst.flags, nullptr);
}
TEST(InstDecodeTest, mov_c7) {
zx_vcpu_state_t vcpu_state;
uint8_t bad_len[] = {0xc7, 0}; // opcode modrm
ASSERT_EQ(inst_decode(bad_len, 2, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_len_16bit[] = {0xc7, 0, 0x1,
0, 0, 0}; // opcode modrm imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(bad_len_16bit, 6, 2, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_disp[] = {0xc7, 0b01'000'000}; // opcode modrm
ASSERT_EQ(inst_decode(bad_disp, 2, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_mod_rm[] = {0xc7, 0b00'111'000, 0x1, 0, 0,
0}; // opcode modrm imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(bad_mod_rm, 6, 4, &vcpu_state, nullptr),
ZX_ERR_INVALID_ARGS);
uint8_t bad_h66[] = {
0x66, 0b0100'1000, 0xc7, 0b00'000'000, 0,
0, 0, 0x1}; // h66 rex opcode modrm imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(bad_h66, 8, 4, &vcpu_state, nullptr),
ZX_ERR_NOT_SUPPORTED);
// movl 0x1, (%rax)
uint8_t mov[] = {0xc7, 0b00'000'000, 0x1, 0, 0,
0}; // opcode modrm imm4 imm3 imm2 imm1
Instruction inst;
ASSERT_EQ(inst_decode(mov, 6, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0x1u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movw 0x1, (%ax)
uint8_t mov_16bit[] = {0xc7, 0b00'000'000, 0x1, 0}; // opcode modrm imm2 imm1
ASSERT_EQ(inst_decode(mov_16bit, 4, 2, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0x1u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movq 0x1000000, (%rax)
uint8_t rex_mov[] = {
0b0100'1000, 0xc7, 0b00'000'000, 0,
0, 0, 0x1}; // rex opcode modrm imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(rex_mov, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 8u);
EXPECT_EQ(inst.imm, 0x1000000u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movl 0x10, -0x1(%rbx)
uint8_t mov_disp_1[] = {0xc7, 0b01'000'011, 0xff, 0x10, 0, 0,
0}; // opcode modrm disp imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(mov_disp_1, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0x10u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movl 0x1000000, -0x1000000(%rbx)
uint8_t mov_disp_4[] = {
0xc7, 0b10'000'011, 0, 0, 0, 0xff, 0, 0,
0, 0x1}; // opcode modrm disp4 disp3 disp2 disp1 imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(mov_disp_4, 10, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0x1000000u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movw 0x100, -0x1(%rax)
uint8_t h66_mov_disp[] = {
0x66, 0b0100'0100, 0xc7, 0b01'000'000,
0xff, 0, 0x1}; // h66 rex opcode modrm disp imm2 imm1
ASSERT_EQ(inst_decode(h66_mov_disp, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0x100u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movl 0x10, (%rax,%rcx,2)
uint8_t mov_sib[] = {0xc7, 0b00'000'100, 0b01'001'000, 0x10, 0, 0,
0}; // opcode modrm sib imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(mov_sib, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0x10u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movl 0x10, 0x04(%rax,%rcx,1)
uint8_t mov_sib_disp[] = {0xc7, 0b01'000'100, 0b00'001'000, 0x04, 0x10, 0, 0,
0}; // opcode modrm sib disp imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(mov_sib_disp, 8, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0x10u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
// movl 0x10, 0x00ABCDEF
uint8_t mov_sib_nobase[] = {
0xc7, 0b00'000'100, 0b00'100'101, 0xEF, 0xCD, 0xAB, 0x00, 0x10, 0, 0,
0}; // opcode modrm sib disp4 disp3 disp2 disp1 imm4 imm3 imm2 imm1
ASSERT_EQ(inst_decode(mov_sib_nobase, 11, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 4u);
EXPECT_EQ(inst.imm, 0x10u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
}
// 8-bit tests to compliment decode_mov_c7.
TEST(InstDecodeTest, mov_c6) {
zx_vcpu_state_t vcpu_state;
Instruction inst;
// movb 0x1, (%rax)
uint8_t mov[] = {0xc6, 0b00'000'000, 0x1}; // opcode modrm imm
ASSERT_EQ(inst_decode(mov, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_WRITE);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0x1u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, nullptr);
}
TEST(InstDecodeTest, movz_0f_b6) {
zx_vcpu_state_t vcpu_state;
uint8_t bad_len[] = {0x0f, 0xb6, 0b00'000'000, 0}; // opcode opcode modrm ?
ASSERT_EQ(inst_decode(bad_len, 4, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_disp[] = {0x0f, 0xb6, 0b01'000'000}; // opcode opcode modrm
ASSERT_EQ(inst_decode(bad_disp, 3, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
// movzb (%rax), %ecx
uint8_t movz[] = {0x0f, 0xb6, 0b00'001'000}; // opcode opcode modrm
Instruction inst;
ASSERT_EQ(inst_decode(movz, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// movzb (%rax), %r10d
uint8_t rex_movz[] = {0b0100'0100, 0x0f, 0xb6,
0b00'010'000}; // rex opcode opcode modrm
ASSERT_EQ(inst_decode(rex_movz, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r10);
EXPECT_EQ(inst.flags, nullptr);
// movzb 0x10(%rax), %ebx
uint8_t movz_disp_1[] = {0x0f, 0xb6, 0b01'011'000,
0x10}; // opcode opcode modrm disp
ASSERT_EQ(inst_decode(movz_disp_1, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzb 0x10000000(%rax), %ebx
uint8_t movz_disp_4[] = {
0x0f, 0xb6, 0b10'011'000, 0,
0, 0, 0x1}; // opcode opcode modrm disp4 disp3 disp2 disp1
ASSERT_EQ(inst_decode(movz_disp_4, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzb 0x11(rax), %r12
uint8_t rex_movz_disp[] = {0b0100'1100, 0x0f, 0xb6, 0b01'100'000,
0x11}; // rex opcode opcode modrm disp
ASSERT_EQ(inst_decode(rex_movz_disp, 5, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r12);
EXPECT_EQ(inst.flags, nullptr);
// movzb (%rax),%cx
uint8_t has_h66[] = {0x66, 0x0f, 0xb6,
0b00'001'000}; // h66 opcode opcode modrm
ASSERT_EQ(inst_decode(has_h66, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// movzb (%rax),%esi
uint8_t mov_to_esi[] = {0x0f, 0xb6, 0b00'110'000}; // opcode opcode modrm
ASSERT_EQ(inst_decode(mov_to_esi, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rsi);
EXPECT_EQ(inst.flags, nullptr);
// movzb (%rax,%rcx,2), %bx
uint8_t mov_sib[] = {0x66, 0x0f, 0xb6, 0b00'011'100,
0b01'001'000}; // h66 opcode opcode modrm sib
ASSERT_EQ(inst_decode(mov_sib, 5, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzb 0x04(%rax,%rcx,1), %bx
uint8_t mov_sib_disp[] = {
0x66, 0x0f, 0xb6,
0b01'011'100, 0b00'001'000, 0x04}; // h66 opcode opcode modrm sib disp
ASSERT_EQ(inst_decode(mov_sib_disp, 6, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzb 0xABCDEF, %ax
uint8_t mov_sib_nobase[] = {
0x66, 0x0f, 0xb6, 0b00'000'100, 0b00'100'101,
0xEF, 0xCD, 0xAB, 0x00}; // h66 opcode opcode modrm sib disp4 disp3 disp2
// disp1
ASSERT_EQ(inst_decode(mov_sib_nobase, 9, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rax);
EXPECT_EQ(inst.flags, nullptr);
}
TEST(InstDecodeTest, movz_0f_b7) {
zx_vcpu_state_t vcpu_state;
uint8_t bad_len[] = {0x0f, 0xb7, 0b00'000'000, 0}; // opcode opcode modrm ?
ASSERT_EQ(inst_decode(bad_len, 4, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_disp[] = {0x0f, 0xb7, 0b01'000'000}; // opcode opcode modrm
ASSERT_EQ(inst_decode(bad_disp, 3, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t has_h66[] = {0x66, 0x0f, 0xb7,
0b00'001'000}; // h66 opcode opcode modrm
ASSERT_EQ(inst_decode(has_h66, 4, 4, &vcpu_state, nullptr), ZX_ERR_BAD_STATE);
// movzw (%rax), %ecx
uint8_t movz[] = {0x0f, 0xb7, 0b00'001'000}; // opcode opcode modrm
Instruction inst;
ASSERT_EQ(inst_decode(movz, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// movzw (%rax), %cx
uint8_t movz_16bit[] = {0x0f, 0xb7, 0b00'001'000}; // opcode opcode modrm
ASSERT_EQ(inst_decode(movz_16bit, 3, 2, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rcx);
EXPECT_EQ(inst.flags, nullptr);
// movzw (%rax), %r10d
uint8_t rex_movz[] = {0b0100'0100, 0x0f, 0xb7,
0b00'010'000}; // rex opcode opcode modrm
ASSERT_EQ(inst_decode(rex_movz, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r10);
EXPECT_EQ(inst.flags, nullptr);
// movzw 0x10(%rax), %ebx
uint8_t movz_disp_1[] = {0x0f, 0xb7, 0b01'011'000,
0x10}; // opcode opcode modrm disp
ASSERT_EQ(inst_decode(movz_disp_1, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzw 0x10000000(%rax), %ebx
uint8_t movz_disp_4[] = {
0x0f, 0xb7, 0b10'011'000, 0,
0, 0, 0x1}; // opcode opcode modrm disp4 disp3 disp2 disp1
ASSERT_EQ(inst_decode(movz_disp_4, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzw 0x11(rax), %r12
uint8_t rex_movz_disp[] = {0b0100'1100, 0x0f, 0xb7, 0b01'100'000,
0x11}; // rex opcode opcode modrm disp
ASSERT_EQ(inst_decode(rex_movz_disp, 5, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.r12);
EXPECT_EQ(inst.flags, nullptr);
// movzw (%rax),%esi
uint8_t mov_to_esi[] = {0x0f, 0xb7, 0b00'110'000}; // opcode opcode modrm
ASSERT_EQ(inst_decode(mov_to_esi, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rsi);
EXPECT_EQ(inst.flags, nullptr);
// movzw (%rax,%rcx,2), %ebx
uint8_t mov_sib[] = {0x0f, 0xb7, 0b00'011'100,
0b01'001'000}; // opcode opcode modrm sib
ASSERT_EQ(inst_decode(mov_sib, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzw 0x04(%rax,%rcx,1), %ebx
uint8_t mov_sib_disp[] = {0x0f, 0xb7, 0b01'011'100, 0b00'001'000,
0x04}; // opcode opcode modrm sib disp
ASSERT_EQ(inst_decode(mov_sib_disp, 5, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rbx);
EXPECT_EQ(inst.flags, nullptr);
// movzw 0x00ABCDEF, %eax
uint8_t mov_sib_nobase[] = {
0x0f, 0xb7, 0b00'000'100, 0b00'100'101, 0xEF,
0xCD, 0xAB, 0x00}; // opcode opcode modrm sib disp4 disp3 disp2 disp1
ASSERT_EQ(inst_decode(mov_sib_nobase, 8, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_MOV_READ);
EXPECT_EQ(inst.access_size, 2u);
EXPECT_EQ(inst.imm, 0u);
EXPECT_EQ(inst.reg, &vcpu_state.rax);
EXPECT_EQ(inst.flags, nullptr);
}
TEST(InstDecodeTest, test_f6) {
zx_vcpu_state_t vcpu_state;
uint8_t bad_len[] = {0xf6, 0b00'000'000}; // opcode modrm
ASSERT_EQ(inst_decode(bad_len, 2, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_disp[] = {0xf6, 0b01'000'000, 0}; // opcode modrm disp
ASSERT_EQ(inst_decode(bad_disp, 3, 4, &vcpu_state, nullptr),
ZX_ERR_OUT_OF_RANGE);
uint8_t bad_mod_rm[] = {0xf6, 0b00'111'000, 0x1}; // opcode modrm imm
ASSERT_EQ(inst_decode(bad_mod_rm, 3, 4, &vcpu_state, nullptr),
ZX_ERR_INVALID_ARGS);
uint8_t has_h66[] = {0x66, 0xf6, 0b00'001'000, 0}; // h66 opcode modrm imm
ASSERT_EQ(inst_decode(has_h66, 4, 4, &vcpu_state, nullptr), ZX_ERR_BAD_STATE);
// test 0x1, (%rax)
uint8_t test[] = {0xf6, 0b00'000'000, 0x1}; // opcode modrm imm
Instruction inst;
ASSERT_EQ(inst_decode(test, 3, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_TEST);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0x1u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, &vcpu_state.rflags);
// test 0x10, -0x1(%rbx)
uint8_t test_disp_1[] = {0xf6, 0b01'000'011, 0xff,
0x10}; // opcode modrm disp imm
ASSERT_EQ(inst_decode(test_disp_1, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_TEST);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0x10u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, &vcpu_state.rflags);
// test 0x11, -0x1000000(%rbx)
uint8_t test_disp_4[] = {
0xf6, 0b10'000'011, 0, 0,
0, 0xff, 0x11}; // opcode modrm disp4 disp3 disp2 disp1 imm
ASSERT_EQ(inst_decode(test_disp_4, 7, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_TEST);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0x11u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, &vcpu_state.rflags);
// test 0x11, (%rax,%rcx,2)
uint8_t test_sib[] = {0xf6, 0b00'000'100, 0b0100'1000,
0x11}; // opcode modrm sib imm
ASSERT_EQ(inst_decode(test_sib, 4, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_TEST);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0x11u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, &vcpu_state.rflags);
// test 0x11, 0x04(%rax,%rcx,1)
uint8_t test_sib_disp[] = {0xf6, 0b01'000'100, 0b00'001'000, 0x04,
0x11}; // opcode modrm sib disp imm
ASSERT_EQ(inst_decode(test_sib_disp, 5, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_TEST);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0x11u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, &vcpu_state.rflags);
// test 0x11, 0x00ABCDEF
uint8_t test_sib_nobase[] = {
0xf6, 0b00'000'100, 0b00'100'101, 0xEF, 0xCD,
0xAB, 0x00, 0x11}; // opcode modrm sib disp4 disp3 disp2 disp1
// imm
ASSERT_EQ(inst_decode(test_sib_nobase, 8, 4, &vcpu_state, &inst), ZX_OK);
EXPECT_EQ(inst.type, INST_TEST);
EXPECT_EQ(inst.access_size, 1u);
EXPECT_EQ(inst.imm, 0x11u);
EXPECT_EQ(inst.reg, nullptr);
EXPECT_EQ(inst.flags, &vcpu_state.rflags);
}
TEST(InstDecodeTest, computing_flags) {
EXPECT_EQ(x86_flags_for_test8(1, 1), 2);
EXPECT_EQ(x86_flags_for_test8(1, -1), 2);
EXPECT_EQ(x86_flags_for_test8(-1, 1), 2);
EXPECT_EQ(x86_flags_for_test8(3, 3), 6);
EXPECT_EQ(x86_flags_for_test8(0, 0), 0x46);
EXPECT_EQ(x86_flags_for_test8(-1, -1), 0x86);
}
} // namespace