aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2010-02-10 07:21:34 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2010-03-01 10:36:11 -0500
commitd4c6a1549c056f1d817e8f6f2f97d8b44933472f (patch)
tree0187b92c17284b598934fcdc147b08e4f71c9708 /arch
parentf850e2e603bf5a05b0aee7901857cf85715aa694 (diff)
KVM: x86 emulator: Fix popf emulation
POPF behaves differently depending on current CPU mode. Emulate correct logic to prevent guest from changing flags that it can't change otherwise. Signed-off-by: Gleb Natapov <gleb@redhat.com> Cc: stable@kernel.org Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/emulate.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 296e8519dc53..1782387c069e 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -343,11 +343,18 @@ static u32 group2_table[] = {
343}; 343};
344 344
345/* EFLAGS bit definitions. */ 345/* EFLAGS bit definitions. */
346#define EFLG_ID (1<<21)
347#define EFLG_VIP (1<<20)
348#define EFLG_VIF (1<<19)
349#define EFLG_AC (1<<18)
346#define EFLG_VM (1<<17) 350#define EFLG_VM (1<<17)
347#define EFLG_RF (1<<16) 351#define EFLG_RF (1<<16)
352#define EFLG_IOPL (3<<12)
353#define EFLG_NT (1<<14)
348#define EFLG_OF (1<<11) 354#define EFLG_OF (1<<11)
349#define EFLG_DF (1<<10) 355#define EFLG_DF (1<<10)
350#define EFLG_IF (1<<9) 356#define EFLG_IF (1<<9)
357#define EFLG_TF (1<<8)
351#define EFLG_SF (1<<7) 358#define EFLG_SF (1<<7)
352#define EFLG_ZF (1<<6) 359#define EFLG_ZF (1<<6)
353#define EFLG_AF (1<<4) 360#define EFLG_AF (1<<4)
@@ -1214,6 +1221,49 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
1214 return rc; 1221 return rc;
1215} 1222}
1216 1223
1224static int emulate_popf(struct x86_emulate_ctxt *ctxt,
1225 struct x86_emulate_ops *ops,
1226 void *dest, int len)
1227{
1228 int rc;
1229 unsigned long val, change_mask;
1230 int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
1231 int cpl = kvm_x86_ops->get_cpl(ctxt->vcpu);
1232
1233 rc = emulate_pop(ctxt, ops, &val, len);
1234 if (rc != X86EMUL_CONTINUE)
1235 return rc;
1236
1237 change_mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_OF
1238 | EFLG_TF | EFLG_DF | EFLG_NT | EFLG_RF | EFLG_AC | EFLG_ID;
1239
1240 switch(ctxt->mode) {
1241 case X86EMUL_MODE_PROT64:
1242 case X86EMUL_MODE_PROT32:
1243 case X86EMUL_MODE_PROT16:
1244 if (cpl == 0)
1245 change_mask |= EFLG_IOPL;
1246 if (cpl <= iopl)
1247 change_mask |= EFLG_IF;
1248 break;
1249 case X86EMUL_MODE_VM86:
1250 if (iopl < 3) {
1251 kvm_inject_gp(ctxt->vcpu, 0);
1252 return X86EMUL_PROPAGATE_FAULT;
1253 }
1254 change_mask |= EFLG_IF;
1255 break;
1256 default: /* real mode */
1257 change_mask |= (EFLG_IOPL | EFLG_IF);
1258 break;
1259 }
1260
1261 *(unsigned long *)dest =
1262 (ctxt->eflags & ~change_mask) | (val & change_mask);
1263
1264 return rc;
1265}
1266
1217static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg) 1267static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg)
1218{ 1268{
1219 struct decode_cache *c = &ctxt->decode; 1269 struct decode_cache *c = &ctxt->decode;
@@ -2099,7 +2149,10 @@ special_insn:
2099 c->dst.type = OP_REG; 2149 c->dst.type = OP_REG;
2100 c->dst.ptr = (unsigned long *) &ctxt->eflags; 2150 c->dst.ptr = (unsigned long *) &ctxt->eflags;
2101 c->dst.bytes = c->op_bytes; 2151 c->dst.bytes = c->op_bytes;
2102 goto pop_instruction; 2152 rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes);
2153 if (rc != X86EMUL_CONTINUE)
2154 goto done;
2155 break;
2103 case 0xa0 ... 0xa1: /* mov */ 2156 case 0xa0 ... 0xa1: /* mov */
2104 c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; 2157 c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
2105 c->dst.val = c->src.val; 2158 c->dst.val = c->src.val;