diff options
| -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; |
