aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2012-02-08 08:34:41 -0500
committerAvi Kivity <avi@redhat.com>2012-03-08 07:10:29 -0500
commit4cee4798a304ee1ea579423ca048f16ceaccdfb5 (patch)
tree1088f534433daf9e9f705453038ced11c059570e /arch/x86/kvm
parentea5e97e8bf1d56a4d9461c39e082b9c31a7be4ff (diff)
KVM: x86 emulator: Allow PM/VM86 switch during task switch
Task switches can switch between Protected Mode and VM86. The current mode must be updated during the task switch emulation so that the new segment selectors are interpreted correctly. In order to let privilege checks succeed, rflags needs to be updated in the vcpu struct as this causes a CPL update. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/emulate.c20
-rw-r--r--arch/x86/kvm/svm.c4
-rw-r--r--arch/x86/kvm/x86.c6
3 files changed, 30 insertions, 0 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b19e9fffe582..83756223f8aa 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2344,6 +2344,8 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
2344 return emulate_gp(ctxt, 0); 2344 return emulate_gp(ctxt, 0);
2345 ctxt->_eip = tss->eip; 2345 ctxt->_eip = tss->eip;
2346 ctxt->eflags = tss->eflags | 2; 2346 ctxt->eflags = tss->eflags | 2;
2347
2348 /* General purpose registers */
2347 ctxt->regs[VCPU_REGS_RAX] = tss->eax; 2349 ctxt->regs[VCPU_REGS_RAX] = tss->eax;
2348 ctxt->regs[VCPU_REGS_RCX] = tss->ecx; 2350 ctxt->regs[VCPU_REGS_RCX] = tss->ecx;
2349 ctxt->regs[VCPU_REGS_RDX] = tss->edx; 2351 ctxt->regs[VCPU_REGS_RDX] = tss->edx;
@@ -2366,6 +2368,24 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
2366 set_segment_selector(ctxt, tss->gs, VCPU_SREG_GS); 2368 set_segment_selector(ctxt, tss->gs, VCPU_SREG_GS);
2367 2369
2368 /* 2370 /*
2371 * If we're switching between Protected Mode and VM86, we need to make
2372 * sure to update the mode before loading the segment descriptors so
2373 * that the selectors are interpreted correctly.
2374 *
2375 * Need to get rflags to the vcpu struct immediately because it
2376 * influences the CPL which is checked at least when loading the segment
2377 * descriptors and when pushing an error code to the new kernel stack.
2378 *
2379 * TODO Introduce a separate ctxt->ops->set_cpl callback
2380 */
2381 if (ctxt->eflags & X86_EFLAGS_VM)
2382 ctxt->mode = X86EMUL_MODE_VM86;
2383 else
2384 ctxt->mode = X86EMUL_MODE_PROT32;
2385
2386 ctxt->ops->set_rflags(ctxt, ctxt->eflags);
2387
2388 /*
2369 * Now load segment descriptors. If fault happenes at this stage 2389 * Now load segment descriptors. If fault happenes at this stage
2370 * it is handled in a context of new task 2390 * it is handled in a context of new task
2371 */ 2391 */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index ab39d84dee00..53efd597f39e 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1354,7 +1354,11 @@ static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
1354 1354
1355static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) 1355static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
1356{ 1356{
1357 unsigned long old_rflags = to_svm(vcpu)->vmcb->save.rflags;
1358
1357 to_svm(vcpu)->vmcb->save.rflags = rflags; 1359 to_svm(vcpu)->vmcb->save.rflags = rflags;
1360 if ((old_rflags ^ rflags) & X86_EFLAGS_VM)
1361 svm_update_cpl(vcpu);
1358} 1362}
1359 1363
1360static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg) 1364static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 490a1b1a255f..03a1fd47a6d3 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4129,6 +4129,11 @@ static int emulator_set_cr(struct x86_emulate_ctxt *ctxt, int cr, ulong val)
4129 return res; 4129 return res;
4130} 4130}
4131 4131
4132static void emulator_set_rflags(struct x86_emulate_ctxt *ctxt, ulong val)
4133{
4134 kvm_set_rflags(emul_to_vcpu(ctxt), val);
4135}
4136
4132static int emulator_get_cpl(struct x86_emulate_ctxt *ctxt) 4137static int emulator_get_cpl(struct x86_emulate_ctxt *ctxt)
4133{ 4138{
4134 return kvm_x86_ops->get_cpl(emul_to_vcpu(ctxt)); 4139 return kvm_x86_ops->get_cpl(emul_to_vcpu(ctxt));
@@ -4310,6 +4315,7 @@ static struct x86_emulate_ops emulate_ops = {
4310 .set_idt = emulator_set_idt, 4315 .set_idt = emulator_set_idt,
4311 .get_cr = emulator_get_cr, 4316 .get_cr = emulator_get_cr,
4312 .set_cr = emulator_set_cr, 4317 .set_cr = emulator_set_cr,
4318 .set_rflags = emulator_set_rflags,
4313 .cpl = emulator_get_cpl, 4319 .cpl = emulator_get_cpl,
4314 .get_dr = emulator_get_dr, 4320 .get_dr = emulator_get_dr,
4315 .set_dr = emulator_set_dr, 4321 .set_dr = emulator_set_dr,