diff options
author | Gleb Natapov <gleb@redhat.com> | 2010-02-10 07:21:34 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2010-03-01 10:36:11 -0500 |
commit | d4c6a1549c056f1d817e8f6f2f97d8b44933472f (patch) | |
tree | 0187b92c17284b598934fcdc147b08e4f71c9708 /arch | |
parent | f850e2e603bf5a05b0aee7901857cf85715aa694 (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.c | 55 |
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 | ||
1224 | static 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 | |||
1217 | static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg) | 1267 | static 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; |