|
@@ -343,11 +343,18 @@ static u32 group2_table[] = {
|
|
|
};
|
|
|
|
|
|
/* EFLAGS bit definitions. */
|
|
|
+#define EFLG_ID (1<<21)
|
|
|
+#define EFLG_VIP (1<<20)
|
|
|
+#define EFLG_VIF (1<<19)
|
|
|
+#define EFLG_AC (1<<18)
|
|
|
#define EFLG_VM (1<<17)
|
|
|
#define EFLG_RF (1<<16)
|
|
|
+#define EFLG_IOPL (3<<12)
|
|
|
+#define EFLG_NT (1<<14)
|
|
|
#define EFLG_OF (1<<11)
|
|
|
#define EFLG_DF (1<<10)
|
|
|
#define EFLG_IF (1<<9)
|
|
|
+#define EFLG_TF (1<<8)
|
|
|
#define EFLG_SF (1<<7)
|
|
|
#define EFLG_ZF (1<<6)
|
|
|
#define EFLG_AF (1<<4)
|
|
@@ -1214,6 +1221,49 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int emulate_popf(struct x86_emulate_ctxt *ctxt,
|
|
|
+ struct x86_emulate_ops *ops,
|
|
|
+ void *dest, int len)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ unsigned long val, change_mask;
|
|
|
+ int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
|
|
|
+ int cpl = kvm_x86_ops->get_cpl(ctxt->vcpu);
|
|
|
+
|
|
|
+ rc = emulate_pop(ctxt, ops, &val, len);
|
|
|
+ if (rc != X86EMUL_CONTINUE)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ change_mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_OF
|
|
|
+ | EFLG_TF | EFLG_DF | EFLG_NT | EFLG_RF | EFLG_AC | EFLG_ID;
|
|
|
+
|
|
|
+ switch(ctxt->mode) {
|
|
|
+ case X86EMUL_MODE_PROT64:
|
|
|
+ case X86EMUL_MODE_PROT32:
|
|
|
+ case X86EMUL_MODE_PROT16:
|
|
|
+ if (cpl == 0)
|
|
|
+ change_mask |= EFLG_IOPL;
|
|
|
+ if (cpl <= iopl)
|
|
|
+ change_mask |= EFLG_IF;
|
|
|
+ break;
|
|
|
+ case X86EMUL_MODE_VM86:
|
|
|
+ if (iopl < 3) {
|
|
|
+ kvm_inject_gp(ctxt->vcpu, 0);
|
|
|
+ return X86EMUL_PROPAGATE_FAULT;
|
|
|
+ }
|
|
|
+ change_mask |= EFLG_IF;
|
|
|
+ break;
|
|
|
+ default: /* real mode */
|
|
|
+ change_mask |= (EFLG_IOPL | EFLG_IF);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ *(unsigned long *)dest =
|
|
|
+ (ctxt->eflags & ~change_mask) | (val & change_mask);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg)
|
|
|
{
|
|
|
struct decode_cache *c = &ctxt->decode;
|
|
@@ -2099,7 +2149,10 @@ special_insn:
|
|
|
c->dst.type = OP_REG;
|
|
|
c->dst.ptr = (unsigned long *) &ctxt->eflags;
|
|
|
c->dst.bytes = c->op_bytes;
|
|
|
- goto pop_instruction;
|
|
|
+ rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes);
|
|
|
+ if (rc != X86EMUL_CONTINUE)
|
|
|
+ goto done;
|
|
|
+ break;
|
|
|
case 0xa0 ... 0xa1: /* mov */
|
|
|
c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
|
|
|
c->dst.val = c->src.val;
|