|
@@ -125,8 +125,9 @@
|
|
|
#define Lock (1<<26) /* lock prefix is allowed for the instruction */
|
|
|
#define Priv (1<<27) /* instruction generates #GP if current CPL != 0 */
|
|
|
#define No64 (1<<28)
|
|
|
+#define PageTable (1 << 29) /* instruction used to write page table */
|
|
|
/* Source 2 operand type */
|
|
|
-#define Src2Shift (29)
|
|
|
+#define Src2Shift (30)
|
|
|
#define Src2None (OpNone << Src2Shift)
|
|
|
#define Src2CL (OpCL << Src2Shift)
|
|
|
#define Src2ImmByte (OpImmByte << Src2Shift)
|
|
@@ -1674,11 +1675,6 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
|
|
|
return X86EMUL_CONTINUE;
|
|
|
}
|
|
|
|
|
|
-static int em_grp1a(struct x86_emulate_ctxt *ctxt)
|
|
|
-{
|
|
|
- return emulate_pop(ctxt, &ctxt->dst.val, ctxt->dst.bytes);
|
|
|
-}
|
|
|
-
|
|
|
static int em_grp2(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
switch (ctxt->modrm_reg) {
|
|
@@ -1788,7 +1784,7 @@ static int em_grp45(struct x86_emulate_ctxt *ctxt)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static int em_grp9(struct x86_emulate_ctxt *ctxt)
|
|
|
+static int em_cmpxchg8b(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
u64 old = ctxt->dst.orig_val64;
|
|
|
|
|
@@ -1831,6 +1827,24 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int em_cmpxchg(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ /* Save real source value, then compare EAX against destination. */
|
|
|
+ ctxt->src.orig_val = ctxt->src.val;
|
|
|
+ ctxt->src.val = ctxt->regs[VCPU_REGS_RAX];
|
|
|
+ emulate_2op_SrcV(ctxt, "cmp");
|
|
|
+
|
|
|
+ if (ctxt->eflags & EFLG_ZF) {
|
|
|
+ /* Success: write back to memory. */
|
|
|
+ ctxt->dst.val = ctxt->src.orig_val;
|
|
|
+ } else {
|
|
|
+ /* Failure: write the value we saw to EAX. */
|
|
|
+ ctxt->dst.type = OP_REG;
|
|
|
+ ctxt->dst.addr.reg = (unsigned long *)&ctxt->regs[VCPU_REGS_RAX];
|
|
|
+ }
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
static int em_lseg(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
int seg = ctxt->src2.val;
|
|
@@ -2481,6 +2495,15 @@ static int em_das(struct x86_emulate_ctxt *ctxt)
|
|
|
return X86EMUL_CONTINUE;
|
|
|
}
|
|
|
|
|
|
+static int em_call(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ long rel = ctxt->src.val;
|
|
|
+
|
|
|
+ ctxt->src.val = (unsigned long)ctxt->_eip;
|
|
|
+ jmp_rel(ctxt, rel);
|
|
|
+ return em_push(ctxt);
|
|
|
+}
|
|
|
+
|
|
|
static int em_call_far(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
u16 sel, old_cs;
|
|
@@ -2622,12 +2645,75 @@ static int em_rdtsc(struct x86_emulate_ctxt *ctxt)
|
|
|
return X86EMUL_CONTINUE;
|
|
|
}
|
|
|
|
|
|
+static int em_rdpmc(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ u64 pmc;
|
|
|
+
|
|
|
+ if (ctxt->ops->read_pmc(ctxt, ctxt->regs[VCPU_REGS_RCX], &pmc))
|
|
|
+ return emulate_gp(ctxt, 0);
|
|
|
+ ctxt->regs[VCPU_REGS_RAX] = (u32)pmc;
|
|
|
+ ctxt->regs[VCPU_REGS_RDX] = pmc >> 32;
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
static int em_mov(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
ctxt->dst.val = ctxt->src.val;
|
|
|
return X86EMUL_CONTINUE;
|
|
|
}
|
|
|
|
|
|
+static int em_cr_write(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ if (ctxt->ops->set_cr(ctxt, ctxt->modrm_reg, ctxt->src.val))
|
|
|
+ return emulate_gp(ctxt, 0);
|
|
|
+
|
|
|
+ /* Disable writeback. */
|
|
|
+ ctxt->dst.type = OP_NONE;
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_dr_write(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ unsigned long val;
|
|
|
+
|
|
|
+ if (ctxt->mode == X86EMUL_MODE_PROT64)
|
|
|
+ val = ctxt->src.val & ~0ULL;
|
|
|
+ else
|
|
|
+ val = ctxt->src.val & ~0U;
|
|
|
+
|
|
|
+ /* #UD condition is already handled. */
|
|
|
+ if (ctxt->ops->set_dr(ctxt, ctxt->modrm_reg, val) < 0)
|
|
|
+ return emulate_gp(ctxt, 0);
|
|
|
+
|
|
|
+ /* Disable writeback. */
|
|
|
+ ctxt->dst.type = OP_NONE;
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_wrmsr(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ u64 msr_data;
|
|
|
+
|
|
|
+ msr_data = (u32)ctxt->regs[VCPU_REGS_RAX]
|
|
|
+ | ((u64)ctxt->regs[VCPU_REGS_RDX] << 32);
|
|
|
+ if (ctxt->ops->set_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], msr_data))
|
|
|
+ return emulate_gp(ctxt, 0);
|
|
|
+
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_rdmsr(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ u64 msr_data;
|
|
|
+
|
|
|
+ if (ctxt->ops->get_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], &msr_data))
|
|
|
+ return emulate_gp(ctxt, 0);
|
|
|
+
|
|
|
+ ctxt->regs[VCPU_REGS_RAX] = (u32)msr_data;
|
|
|
+ ctxt->regs[VCPU_REGS_RDX] = msr_data >> 32;
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
static int em_mov_rm_sreg(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
if (ctxt->modrm_reg > VCPU_SREG_GS)
|
|
@@ -2775,6 +2861,24 @@ static int em_jcxz(struct x86_emulate_ctxt *ctxt)
|
|
|
return X86EMUL_CONTINUE;
|
|
|
}
|
|
|
|
|
|
+static int em_in(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ if (!pio_in_emulated(ctxt, ctxt->dst.bytes, ctxt->src.val,
|
|
|
+ &ctxt->dst.val))
|
|
|
+ return X86EMUL_IO_NEEDED;
|
|
|
+
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_out(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ ctxt->ops->pio_out_emulated(ctxt, ctxt->src.bytes, ctxt->dst.val,
|
|
|
+ &ctxt->src.val, 1);
|
|
|
+ /* Disable writeback. */
|
|
|
+ ctxt->dst.type = OP_NONE;
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
static int em_cli(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
if (emulator_bad_iopl(ctxt))
|
|
@@ -2794,6 +2898,69 @@ static int em_sti(struct x86_emulate_ctxt *ctxt)
|
|
|
return X86EMUL_CONTINUE;
|
|
|
}
|
|
|
|
|
|
+static int em_bt(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ /* Disable writeback. */
|
|
|
+ ctxt->dst.type = OP_NONE;
|
|
|
+ /* only subword offset */
|
|
|
+ ctxt->src.val &= (ctxt->dst.bytes << 3) - 1;
|
|
|
+
|
|
|
+ emulate_2op_SrcV_nobyte(ctxt, "bt");
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_bts(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ emulate_2op_SrcV_nobyte(ctxt, "bts");
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_btr(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ emulate_2op_SrcV_nobyte(ctxt, "btr");
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_btc(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ emulate_2op_SrcV_nobyte(ctxt, "btc");
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_bsf(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ u8 zf;
|
|
|
+
|
|
|
+ __asm__ ("bsf %2, %0; setz %1"
|
|
|
+ : "=r"(ctxt->dst.val), "=q"(zf)
|
|
|
+ : "r"(ctxt->src.val));
|
|
|
+
|
|
|
+ ctxt->eflags &= ~X86_EFLAGS_ZF;
|
|
|
+ if (zf) {
|
|
|
+ ctxt->eflags |= X86_EFLAGS_ZF;
|
|
|
+ /* Disable writeback. */
|
|
|
+ ctxt->dst.type = OP_NONE;
|
|
|
+ }
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+static int em_bsr(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ u8 zf;
|
|
|
+
|
|
|
+ __asm__ ("bsr %2, %0; setz %1"
|
|
|
+ : "=r"(ctxt->dst.val), "=q"(zf)
|
|
|
+ : "r"(ctxt->src.val));
|
|
|
+
|
|
|
+ ctxt->eflags &= ~X86_EFLAGS_ZF;
|
|
|
+ if (zf) {
|
|
|
+ ctxt->eflags |= X86_EFLAGS_ZF;
|
|
|
+ /* Disable writeback. */
|
|
|
+ ctxt->dst.type = OP_NONE;
|
|
|
+ }
|
|
|
+ return X86EMUL_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
static bool valid_cr(int nr)
|
|
|
{
|
|
|
switch (nr) {
|
|
@@ -2867,9 +3034,6 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt)
|
|
|
break;
|
|
|
}
|
|
|
case 4: {
|
|
|
- u64 cr4;
|
|
|
-
|
|
|
- cr4 = ctxt->ops->get_cr(ctxt, 4);
|
|
|
ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
|
|
|
|
|
|
if ((efer & EFER_LMA) && !(new_val & X86_CR4_PAE))
|
|
@@ -3003,6 +3167,8 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt)
|
|
|
#define D2bv(_f) D((_f) | ByteOp), D(_f)
|
|
|
#define D2bvIP(_f, _i, _p) DIP((_f) | ByteOp, _i, _p), DIP(_f, _i, _p)
|
|
|
#define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e)
|
|
|
+#define I2bvIP(_f, _e, _i, _p) \
|
|
|
+ IIP((_f) | ByteOp, _e, _i, _p), IIP(_f, _e, _i, _p)
|
|
|
|
|
|
#define I6ALU(_f, _e) I2bv((_f) | DstMem | SrcReg | ModRM, _e), \
|
|
|
I2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \
|
|
@@ -3033,17 +3199,17 @@ static struct opcode group7_rm7[] = {
|
|
|
|
|
|
static struct opcode group1[] = {
|
|
|
I(Lock, em_add),
|
|
|
- I(Lock, em_or),
|
|
|
+ I(Lock | PageTable, em_or),
|
|
|
I(Lock, em_adc),
|
|
|
I(Lock, em_sbb),
|
|
|
- I(Lock, em_and),
|
|
|
+ I(Lock | PageTable, em_and),
|
|
|
I(Lock, em_sub),
|
|
|
I(Lock, em_xor),
|
|
|
I(0, em_cmp),
|
|
|
};
|
|
|
|
|
|
static struct opcode group1A[] = {
|
|
|
- D(DstMem | SrcNone | ModRM | Mov | Stack), N, N, N, N, N, N, N,
|
|
|
+ I(DstMem | SrcNone | ModRM | Mov | Stack, em_pop), N, N, N, N, N, N, N,
|
|
|
};
|
|
|
|
|
|
static struct opcode group3[] = {
|
|
@@ -3058,16 +3224,19 @@ static struct opcode group3[] = {
|
|
|
};
|
|
|
|
|
|
static struct opcode group4[] = {
|
|
|
- D(ByteOp | DstMem | SrcNone | ModRM | Lock), D(ByteOp | DstMem | SrcNone | ModRM | Lock),
|
|
|
+ I(ByteOp | DstMem | SrcNone | ModRM | Lock, em_grp45),
|
|
|
+ I(ByteOp | DstMem | SrcNone | ModRM | Lock, em_grp45),
|
|
|
N, N, N, N, N, N,
|
|
|
};
|
|
|
|
|
|
static struct opcode group5[] = {
|
|
|
- D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock),
|
|
|
- D(SrcMem | ModRM | Stack),
|
|
|
+ I(DstMem | SrcNone | ModRM | Lock, em_grp45),
|
|
|
+ I(DstMem | SrcNone | ModRM | Lock, em_grp45),
|
|
|
+ I(SrcMem | ModRM | Stack, em_grp45),
|
|
|
I(SrcMemFAddr | ModRM | ImplicitOps | Stack, em_call_far),
|
|
|
- D(SrcMem | ModRM | Stack), D(SrcMemFAddr | ModRM | ImplicitOps),
|
|
|
- D(SrcMem | ModRM | Stack), N,
|
|
|
+ I(SrcMem | ModRM | Stack, em_grp45),
|
|
|
+ I(SrcMemFAddr | ModRM | ImplicitOps, em_grp45),
|
|
|
+ I(SrcMem | ModRM | Stack, em_grp45), N,
|
|
|
};
|
|
|
|
|
|
static struct opcode group6[] = {
|
|
@@ -3096,18 +3265,21 @@ static struct group_dual group7 = { {
|
|
|
|
|
|
static struct opcode group8[] = {
|
|
|
N, N, N, N,
|
|
|
- D(DstMem | SrcImmByte | ModRM), D(DstMem | SrcImmByte | ModRM | Lock),
|
|
|
- D(DstMem | SrcImmByte | ModRM | Lock), D(DstMem | SrcImmByte | ModRM | Lock),
|
|
|
+ I(DstMem | SrcImmByte | ModRM, em_bt),
|
|
|
+ I(DstMem | SrcImmByte | ModRM | Lock | PageTable, em_bts),
|
|
|
+ I(DstMem | SrcImmByte | ModRM | Lock, em_btr),
|
|
|
+ I(DstMem | SrcImmByte | ModRM | Lock | PageTable, em_btc),
|
|
|
};
|
|
|
|
|
|
static struct group_dual group9 = { {
|
|
|
- N, D(DstMem64 | ModRM | Lock), N, N, N, N, N, N,
|
|
|
+ N, I(DstMem64 | ModRM | Lock | PageTable, em_cmpxchg8b), N, N, N, N, N, N,
|
|
|
}, {
|
|
|
N, N, N, N, N, N, N, N,
|
|
|
} };
|
|
|
|
|
|
static struct opcode group11[] = {
|
|
|
- I(DstMem | SrcImm | ModRM | Mov, em_mov), X7(D(Undefined)),
|
|
|
+ I(DstMem | SrcImm | ModRM | Mov | PageTable, em_mov),
|
|
|
+ X7(D(Undefined)),
|
|
|
};
|
|
|
|
|
|
static struct gprefix pfx_0f_6f_0f_7f = {
|
|
@@ -3120,7 +3292,7 @@ static struct opcode opcode_table[256] = {
|
|
|
I(ImplicitOps | Stack | No64 | Src2ES, em_push_sreg),
|
|
|
I(ImplicitOps | Stack | No64 | Src2ES, em_pop_sreg),
|
|
|
/* 0x08 - 0x0F */
|
|
|
- I6ALU(Lock, em_or),
|
|
|
+ I6ALU(Lock | PageTable, em_or),
|
|
|
I(ImplicitOps | Stack | No64 | Src2CS, em_push_sreg),
|
|
|
N,
|
|
|
/* 0x10 - 0x17 */
|
|
@@ -3132,7 +3304,7 @@ static struct opcode opcode_table[256] = {
|
|
|
I(ImplicitOps | Stack | No64 | Src2DS, em_push_sreg),
|
|
|
I(ImplicitOps | Stack | No64 | Src2DS, em_pop_sreg),
|
|
|
/* 0x20 - 0x27 */
|
|
|
- I6ALU(Lock, em_and), N, N,
|
|
|
+ I6ALU(Lock | PageTable, em_and), N, N,
|
|
|
/* 0x28 - 0x2F */
|
|
|
I6ALU(Lock, em_sub), N, I(ByteOp | DstAcc | No64, em_das),
|
|
|
/* 0x30 - 0x37 */
|
|
@@ -3155,8 +3327,8 @@ static struct opcode opcode_table[256] = {
|
|
|
I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
|
|
|
I(SrcImmByte | Mov | Stack, em_push),
|
|
|
I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
|
|
|
- D2bvIP(DstDI | SrcDX | Mov | String, ins, check_perm_in), /* insb, insw/insd */
|
|
|
- D2bvIP(SrcSI | DstDX | String, outs, check_perm_out), /* outsb, outsw/outsd */
|
|
|
+ I2bvIP(DstDI | SrcDX | Mov | String, em_in, ins, check_perm_in), /* insb, insw/insd */
|
|
|
+ I2bvIP(SrcSI | DstDX | String, em_out, outs, check_perm_out), /* outsb, outsw/outsd */
|
|
|
/* 0x70 - 0x7F */
|
|
|
X16(D(SrcImmByte)),
|
|
|
/* 0x80 - 0x87 */
|
|
@@ -3165,11 +3337,11 @@ static struct opcode opcode_table[256] = {
|
|
|
G(ByteOp | DstMem | SrcImm | ModRM | No64 | Group, group1),
|
|
|
G(DstMem | SrcImmByte | ModRM | Group, group1),
|
|
|
I2bv(DstMem | SrcReg | ModRM, em_test),
|
|
|
- I2bv(DstMem | SrcReg | ModRM | Lock, em_xchg),
|
|
|
+ I2bv(DstMem | SrcReg | ModRM | Lock | PageTable, em_xchg),
|
|
|
/* 0x88 - 0x8F */
|
|
|
- I2bv(DstMem | SrcReg | ModRM | Mov, em_mov),
|
|
|
+ I2bv(DstMem | SrcReg | ModRM | Mov | PageTable, em_mov),
|
|
|
I2bv(DstReg | SrcMem | ModRM | Mov, em_mov),
|
|
|
- I(DstMem | SrcNone | ModRM | Mov, em_mov_rm_sreg),
|
|
|
+ I(DstMem | SrcNone | ModRM | Mov | PageTable, em_mov_rm_sreg),
|
|
|
D(ModRM | SrcMem | NoAccess | DstReg),
|
|
|
I(ImplicitOps | SrcMem16 | ModRM, em_mov_sreg_rm),
|
|
|
G(0, group1A),
|
|
@@ -3182,7 +3354,7 @@ static struct opcode opcode_table[256] = {
|
|
|
II(ImplicitOps | Stack, em_popf, popf), N, N,
|
|
|
/* 0xA0 - 0xA7 */
|
|
|
I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov),
|
|
|
- I2bv(DstMem | SrcAcc | Mov | MemAbs, em_mov),
|
|
|
+ I2bv(DstMem | SrcAcc | Mov | MemAbs | PageTable, em_mov),
|
|
|
I2bv(SrcSI | DstDI | Mov | String, em_mov),
|
|
|
I2bv(SrcSI | DstDI | String, em_cmp),
|
|
|
/* 0xA8 - 0xAF */
|
|
@@ -3213,13 +3385,13 @@ static struct opcode opcode_table[256] = {
|
|
|
/* 0xE0 - 0xE7 */
|
|
|
X3(I(SrcImmByte, em_loop)),
|
|
|
I(SrcImmByte, em_jcxz),
|
|
|
- D2bvIP(SrcImmUByte | DstAcc, in, check_perm_in),
|
|
|
- D2bvIP(SrcAcc | DstImmUByte, out, check_perm_out),
|
|
|
+ I2bvIP(SrcImmUByte | DstAcc, em_in, in, check_perm_in),
|
|
|
+ I2bvIP(SrcAcc | DstImmUByte, em_out, out, check_perm_out),
|
|
|
/* 0xE8 - 0xEF */
|
|
|
- D(SrcImm | Stack), D(SrcImm | ImplicitOps),
|
|
|
+ I(SrcImm | Stack, em_call), D(SrcImm | ImplicitOps),
|
|
|
I(SrcImmFAddr | No64, em_jmp_far), D(SrcImmByte | ImplicitOps),
|
|
|
- D2bvIP(SrcDX | DstAcc, in, check_perm_in),
|
|
|
- D2bvIP(SrcAcc | DstDX, out, check_perm_out),
|
|
|
+ I2bvIP(SrcDX | DstAcc, em_in, in, check_perm_in),
|
|
|
+ I2bvIP(SrcAcc | DstDX, em_out, out, check_perm_out),
|
|
|
/* 0xF0 - 0xF7 */
|
|
|
N, DI(ImplicitOps, icebp), N, N,
|
|
|
DI(ImplicitOps | Priv, hlt), D(ImplicitOps),
|
|
@@ -3242,15 +3414,15 @@ static struct opcode twobyte_table[256] = {
|
|
|
/* 0x20 - 0x2F */
|
|
|
DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
|
|
|
DIP(ModRM | DstMem | Priv | Op3264, dr_read, check_dr_read),
|
|
|
- DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write),
|
|
|
- DIP(ModRM | SrcMem | Priv | Op3264, dr_write, check_dr_write),
|
|
|
+ IIP(ModRM | SrcMem | Priv | Op3264, em_cr_write, cr_write, check_cr_write),
|
|
|
+ IIP(ModRM | SrcMem | Priv | Op3264, em_dr_write, dr_write, check_dr_write),
|
|
|
N, N, N, N,
|
|
|
N, N, N, N, N, N, N, N,
|
|
|
/* 0x30 - 0x3F */
|
|
|
- DI(ImplicitOps | Priv, wrmsr),
|
|
|
+ II(ImplicitOps | Priv, em_wrmsr, wrmsr),
|
|
|
IIP(ImplicitOps, em_rdtsc, rdtsc, check_rdtsc),
|
|
|
- DI(ImplicitOps | Priv, rdmsr),
|
|
|
- DIP(ImplicitOps | Priv, rdpmc, check_rdpmc),
|
|
|
+ II(ImplicitOps | Priv, em_rdmsr, rdmsr),
|
|
|
+ IIP(ImplicitOps, em_rdpmc, rdpmc, check_rdpmc),
|
|
|
I(ImplicitOps | VendorSpecific, em_sysenter),
|
|
|
I(ImplicitOps | Priv | VendorSpecific, em_sysexit),
|
|
|
N, N,
|
|
@@ -3275,26 +3447,28 @@ static struct opcode twobyte_table[256] = {
|
|
|
X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
|
|
|
/* 0xA0 - 0xA7 */
|
|
|
I(Stack | Src2FS, em_push_sreg), I(Stack | Src2FS, em_pop_sreg),
|
|
|
- DI(ImplicitOps, cpuid), D(DstMem | SrcReg | ModRM | BitOp),
|
|
|
+ DI(ImplicitOps, cpuid), I(DstMem | SrcReg | ModRM | BitOp, em_bt),
|
|
|
D(DstMem | SrcReg | Src2ImmByte | ModRM),
|
|
|
D(DstMem | SrcReg | Src2CL | ModRM), N, N,
|
|
|
/* 0xA8 - 0xAF */
|
|
|
I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg),
|
|
|
- DI(ImplicitOps, rsm), D(DstMem | SrcReg | ModRM | BitOp | Lock),
|
|
|
+ DI(ImplicitOps, rsm),
|
|
|
+ I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts),
|
|
|
D(DstMem | SrcReg | Src2ImmByte | ModRM),
|
|
|
D(DstMem | SrcReg | Src2CL | ModRM),
|
|
|
D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
|
|
|
/* 0xB0 - 0xB7 */
|
|
|
- D2bv(DstMem | SrcReg | ModRM | Lock),
|
|
|
+ I2bv(DstMem | SrcReg | ModRM | Lock | PageTable, em_cmpxchg),
|
|
|
I(DstReg | SrcMemFAddr | ModRM | Src2SS, em_lseg),
|
|
|
- D(DstMem | SrcReg | ModRM | BitOp | Lock),
|
|
|
+ I(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr),
|
|
|
I(DstReg | SrcMemFAddr | ModRM | Src2FS, em_lseg),
|
|
|
I(DstReg | SrcMemFAddr | ModRM | Src2GS, em_lseg),
|
|
|
D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
|
|
|
/* 0xB8 - 0xBF */
|
|
|
N, N,
|
|
|
- G(BitOp, group8), D(DstMem | SrcReg | ModRM | BitOp | Lock),
|
|
|
- D(DstReg | SrcMem | ModRM), D(DstReg | SrcMem | ModRM),
|
|
|
+ G(BitOp, group8),
|
|
|
+ I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc),
|
|
|
+ I(DstReg | SrcMem | ModRM, em_bsf), I(DstReg | SrcMem | ModRM, em_bsr),
|
|
|
D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
|
|
|
/* 0xC0 - 0xCF */
|
|
|
D2bv(DstMem | SrcReg | ModRM | Lock),
|
|
@@ -3320,6 +3494,7 @@ static struct opcode twobyte_table[256] = {
|
|
|
#undef D2bv
|
|
|
#undef D2bvIP
|
|
|
#undef I2bv
|
|
|
+#undef I2bvIP
|
|
|
#undef I6ALU
|
|
|
|
|
|
static unsigned imm_size(struct x86_emulate_ctxt *ctxt)
|
|
@@ -3697,6 +3872,11 @@ done:
|
|
|
return (rc != X86EMUL_CONTINUE) ? EMULATION_FAILED : EMULATION_OK;
|
|
|
}
|
|
|
|
|
|
+bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ return ctxt->d & PageTable;
|
|
|
+}
|
|
|
+
|
|
|
static bool string_insn_completed(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
/* The second termination condition only applies for REPE
|
|
@@ -3720,7 +3900,6 @@ static bool string_insn_completed(struct x86_emulate_ctxt *ctxt)
|
|
|
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
|
|
{
|
|
|
struct x86_emulate_ops *ops = ctxt->ops;
|
|
|
- u64 msr_data;
|
|
|
int rc = X86EMUL_CONTINUE;
|
|
|
int saved_dst_type = ctxt->dst.type;
|
|
|
|
|
@@ -3854,15 +4033,6 @@ special_insn:
|
|
|
goto cannot_emulate;
|
|
|
ctxt->dst.val = (s32) ctxt->src.val;
|
|
|
break;
|
|
|
- case 0x6c: /* insb */
|
|
|
- case 0x6d: /* insw/insd */
|
|
|
- ctxt->src.val = ctxt->regs[VCPU_REGS_RDX];
|
|
|
- goto do_io_in;
|
|
|
- case 0x6e: /* outsb */
|
|
|
- case 0x6f: /* outsw/outsd */
|
|
|
- ctxt->dst.val = ctxt->regs[VCPU_REGS_RDX];
|
|
|
- goto do_io_out;
|
|
|
- break;
|
|
|
case 0x70 ... 0x7f: /* jcc (short) */
|
|
|
if (test_cc(ctxt->b, ctxt->eflags))
|
|
|
jmp_rel(ctxt, ctxt->src.val);
|
|
@@ -3870,9 +4040,6 @@ special_insn:
|
|
|
case 0x8d: /* lea r16/r32, m */
|
|
|
ctxt->dst.val = ctxt->src.addr.mem.ea;
|
|
|
break;
|
|
|
- case 0x8f: /* pop (sole member of Grp1a) */
|
|
|
- rc = em_grp1a(ctxt);
|
|
|
- break;
|
|
|
case 0x90 ... 0x97: /* nop / xchg reg, rax */
|
|
|
if (ctxt->dst.addr.reg == &ctxt->regs[VCPU_REGS_RAX])
|
|
|
break;
|
|
@@ -3905,38 +4072,11 @@ special_insn:
|
|
|
ctxt->src.val = ctxt->regs[VCPU_REGS_RCX];
|
|
|
rc = em_grp2(ctxt);
|
|
|
break;
|
|
|
- case 0xe4: /* inb */
|
|
|
- case 0xe5: /* in */
|
|
|
- goto do_io_in;
|
|
|
- case 0xe6: /* outb */
|
|
|
- case 0xe7: /* out */
|
|
|
- goto do_io_out;
|
|
|
- case 0xe8: /* call (near) */ {
|
|
|
- long int rel = ctxt->src.val;
|
|
|
- ctxt->src.val = (unsigned long) ctxt->_eip;
|
|
|
- jmp_rel(ctxt, rel);
|
|
|
- rc = em_push(ctxt);
|
|
|
- break;
|
|
|
- }
|
|
|
case 0xe9: /* jmp rel */
|
|
|
case 0xeb: /* jmp rel short */
|
|
|
jmp_rel(ctxt, ctxt->src.val);
|
|
|
ctxt->dst.type = OP_NONE; /* Disable writeback. */
|
|
|
break;
|
|
|
- case 0xec: /* in al,dx */
|
|
|
- case 0xed: /* in (e/r)ax,dx */
|
|
|
- do_io_in:
|
|
|
- if (!pio_in_emulated(ctxt, ctxt->dst.bytes, ctxt->src.val,
|
|
|
- &ctxt->dst.val))
|
|
|
- goto done; /* IO is needed */
|
|
|
- break;
|
|
|
- case 0xee: /* out dx,al */
|
|
|
- case 0xef: /* out dx,(e/r)ax */
|
|
|
- do_io_out:
|
|
|
- ops->pio_out_emulated(ctxt, ctxt->src.bytes, ctxt->dst.val,
|
|
|
- &ctxt->src.val, 1);
|
|
|
- ctxt->dst.type = OP_NONE; /* Disable writeback. */
|
|
|
- break;
|
|
|
case 0xf4: /* hlt */
|
|
|
ctxt->ops->halt(ctxt);
|
|
|
break;
|
|
@@ -3956,12 +4096,6 @@ special_insn:
|
|
|
case 0xfd: /* std */
|
|
|
ctxt->eflags |= EFLG_DF;
|
|
|
break;
|
|
|
- case 0xfe: /* Grp4 */
|
|
|
- rc = em_grp45(ctxt);
|
|
|
- break;
|
|
|
- case 0xff: /* Grp5 */
|
|
|
- rc = em_grp45(ctxt);
|
|
|
- break;
|
|
|
default:
|
|
|
goto cannot_emulate;
|
|
|
}
|
|
@@ -4036,49 +4170,6 @@ twobyte_insn:
|
|
|
case 0x21: /* mov from dr to reg */
|
|
|
ops->get_dr(ctxt, ctxt->modrm_reg, &ctxt->dst.val);
|
|
|
break;
|
|
|
- case 0x22: /* mov reg, cr */
|
|
|
- if (ops->set_cr(ctxt, ctxt->modrm_reg, ctxt->src.val)) {
|
|
|
- emulate_gp(ctxt, 0);
|
|
|
- rc = X86EMUL_PROPAGATE_FAULT;
|
|
|
- goto done;
|
|
|
- }
|
|
|
- ctxt->dst.type = OP_NONE;
|
|
|
- break;
|
|
|
- case 0x23: /* mov from reg to dr */
|
|
|
- if (ops->set_dr(ctxt, ctxt->modrm_reg, ctxt->src.val &
|
|
|
- ((ctxt->mode == X86EMUL_MODE_PROT64) ?
|
|
|
- ~0ULL : ~0U)) < 0) {
|
|
|
- /* #UD condition is already handled by the code above */
|
|
|
- emulate_gp(ctxt, 0);
|
|
|
- rc = X86EMUL_PROPAGATE_FAULT;
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- ctxt->dst.type = OP_NONE; /* no writeback */
|
|
|
- break;
|
|
|
- case 0x30:
|
|
|
- /* wrmsr */
|
|
|
- msr_data = (u32)ctxt->regs[VCPU_REGS_RAX]
|
|
|
- | ((u64)ctxt->regs[VCPU_REGS_RDX] << 32);
|
|
|
- if (ops->set_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], msr_data)) {
|
|
|
- emulate_gp(ctxt, 0);
|
|
|
- rc = X86EMUL_PROPAGATE_FAULT;
|
|
|
- goto done;
|
|
|
- }
|
|
|
- rc = X86EMUL_CONTINUE;
|
|
|
- break;
|
|
|
- case 0x32:
|
|
|
- /* rdmsr */
|
|
|
- if (ops->get_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], &msr_data)) {
|
|
|
- emulate_gp(ctxt, 0);
|
|
|
- rc = X86EMUL_PROPAGATE_FAULT;
|
|
|
- goto done;
|
|
|
- } else {
|
|
|
- ctxt->regs[VCPU_REGS_RAX] = (u32)msr_data;
|
|
|
- ctxt->regs[VCPU_REGS_RDX] = msr_data >> 32;
|
|
|
- }
|
|
|
- rc = X86EMUL_CONTINUE;
|
|
|
- break;
|
|
|
case 0x40 ... 0x4f: /* cmov */
|
|
|
ctxt->dst.val = ctxt->dst.orig_val = ctxt->src.val;
|
|
|
if (!test_cc(ctxt->b, ctxt->eflags))
|
|
@@ -4091,93 +4182,21 @@ twobyte_insn:
|
|
|
case 0x90 ... 0x9f: /* setcc r/m8 */
|
|
|
ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags);
|
|
|
break;
|
|
|
- case 0xa3:
|
|
|
- bt: /* bt */
|
|
|
- ctxt->dst.type = OP_NONE;
|
|
|
- /* only subword offset */
|
|
|
- ctxt->src.val &= (ctxt->dst.bytes << 3) - 1;
|
|
|
- emulate_2op_SrcV_nobyte(ctxt, "bt");
|
|
|
- break;
|
|
|
case 0xa4: /* shld imm8, r, r/m */
|
|
|
case 0xa5: /* shld cl, r, r/m */
|
|
|
emulate_2op_cl(ctxt, "shld");
|
|
|
break;
|
|
|
- case 0xab:
|
|
|
- bts: /* bts */
|
|
|
- emulate_2op_SrcV_nobyte(ctxt, "bts");
|
|
|
- break;
|
|
|
case 0xac: /* shrd imm8, r, r/m */
|
|
|
case 0xad: /* shrd cl, r, r/m */
|
|
|
emulate_2op_cl(ctxt, "shrd");
|
|
|
break;
|
|
|
case 0xae: /* clflush */
|
|
|
break;
|
|
|
- case 0xb0 ... 0xb1: /* cmpxchg */
|
|
|
- /*
|
|
|
- * Save real source value, then compare EAX against
|
|
|
- * destination.
|
|
|
- */
|
|
|
- ctxt->src.orig_val = ctxt->src.val;
|
|
|
- ctxt->src.val = ctxt->regs[VCPU_REGS_RAX];
|
|
|
- emulate_2op_SrcV(ctxt, "cmp");
|
|
|
- if (ctxt->eflags & EFLG_ZF) {
|
|
|
- /* Success: write back to memory. */
|
|
|
- ctxt->dst.val = ctxt->src.orig_val;
|
|
|
- } else {
|
|
|
- /* Failure: write the value we saw to EAX. */
|
|
|
- ctxt->dst.type = OP_REG;
|
|
|
- ctxt->dst.addr.reg = (unsigned long *)&ctxt->regs[VCPU_REGS_RAX];
|
|
|
- }
|
|
|
- break;
|
|
|
- case 0xb3:
|
|
|
- btr: /* btr */
|
|
|
- emulate_2op_SrcV_nobyte(ctxt, "btr");
|
|
|
- break;
|
|
|
case 0xb6 ... 0xb7: /* movzx */
|
|
|
ctxt->dst.bytes = ctxt->op_bytes;
|
|
|
ctxt->dst.val = (ctxt->d & ByteOp) ? (u8) ctxt->src.val
|
|
|
: (u16) ctxt->src.val;
|
|
|
break;
|
|
|
- case 0xba: /* Grp8 */
|
|
|
- switch (ctxt->modrm_reg & 3) {
|
|
|
- case 0:
|
|
|
- goto bt;
|
|
|
- case 1:
|
|
|
- goto bts;
|
|
|
- case 2:
|
|
|
- goto btr;
|
|
|
- case 3:
|
|
|
- goto btc;
|
|
|
- }
|
|
|
- break;
|
|
|
- case 0xbb:
|
|
|
- btc: /* btc */
|
|
|
- emulate_2op_SrcV_nobyte(ctxt, "btc");
|
|
|
- break;
|
|
|
- case 0xbc: { /* bsf */
|
|
|
- u8 zf;
|
|
|
- __asm__ ("bsf %2, %0; setz %1"
|
|
|
- : "=r"(ctxt->dst.val), "=q"(zf)
|
|
|
- : "r"(ctxt->src.val));
|
|
|
- ctxt->eflags &= ~X86_EFLAGS_ZF;
|
|
|
- if (zf) {
|
|
|
- ctxt->eflags |= X86_EFLAGS_ZF;
|
|
|
- ctxt->dst.type = OP_NONE; /* Disable writeback. */
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case 0xbd: { /* bsr */
|
|
|
- u8 zf;
|
|
|
- __asm__ ("bsr %2, %0; setz %1"
|
|
|
- : "=r"(ctxt->dst.val), "=q"(zf)
|
|
|
- : "r"(ctxt->src.val));
|
|
|
- ctxt->eflags &= ~X86_EFLAGS_ZF;
|
|
|
- if (zf) {
|
|
|
- ctxt->eflags |= X86_EFLAGS_ZF;
|
|
|
- ctxt->dst.type = OP_NONE; /* Disable writeback. */
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
case 0xbe ... 0xbf: /* movsx */
|
|
|
ctxt->dst.bytes = ctxt->op_bytes;
|
|
|
ctxt->dst.val = (ctxt->d & ByteOp) ? (s8) ctxt->src.val :
|
|
@@ -4194,9 +4213,6 @@ twobyte_insn:
|
|
|
ctxt->dst.val = (ctxt->op_bytes == 4) ? (u32) ctxt->src.val :
|
|
|
(u64) ctxt->src.val;
|
|
|
break;
|
|
|
- case 0xc7: /* Grp9 (cmpxchg8b) */
|
|
|
- rc = em_grp9(ctxt);
|
|
|
- break;
|
|
|
default:
|
|
|
goto cannot_emulate;
|
|
|
}
|