Not sure if it actually makes sense to send a patch with this as I have
more problems to describe than lines that actually fix something - but
well, this hack at least makes some hardware task switches into/out of
VM86 work for me that failed before.

So what I really intend is to get information on what I need to do to
get this right (alternatively consider this a bug report and do the fix
yourself):

* I have disabled privilege checks for task gates (I need to switch out
  of VM86/ring 3 back into ring 0). This is wrong, they still need to be
  applied for software interrupts, but not for exceptions or IRQs (note
  that the check was wrong anyway, it should check the task gate DPL,
  not the TSS one).

  How do I find out what kind of interrupt caused the task switch? (Hm,
  I guess vmx->idt_vectoring_info could do it for Intel and I would have
  to pass this down into the emulator; for AMD see below)

* May the emulator access the vcpu or should this go through a new
  x86_emulate_ops.set_rflags function pointer?

* This works with VMX, but with SVM I have an additional problem: When
  trying to exit VM86 (usually by an exception) through a task gate in
  the IDT, the code runs into the reason = TASK_SWITCH_CALL path. I
  searched a bit in the documentation, but didn't find any obvious way
  to fix this.

* Yes, I've yet to write a nice testcase for kvm-unittests

Signed-off-by: Kevin Wolf <kw...@redhat.com>
---
 arch/x86/kvm/emulate.c |   13 ++++++++++++-
 1 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 05a562b..fdd3cca 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1227,6 +1227,7 @@ static int load_segment_descriptor(struct 
x86_emulate_ctxt *ctxt,
                seg_desc.type = 3;
                seg_desc.p = 1;
                seg_desc.s = 1;
+               seg_desc.dpl = 3;
                goto load;
        }
 
@@ -2246,6 +2247,9 @@ static void save_state_to_tss32(struct x86_emulate_ctxt 
*ctxt,
        tss->ldt_selector = get_segment_selector(ctxt, VCPU_SREG_LDTR);
 }
 
+#define emul_to_vcpu(ctxt) \
+       container_of(ctxt, struct kvm_vcpu, arch.emulate_ctxt)
+
 static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
                                 struct tss_segment_32 *tss)
 {
@@ -2254,7 +2258,14 @@ static int load_state_from_tss32(struct x86_emulate_ctxt 
*ctxt,
        if (ctxt->ops->set_cr(ctxt, 3, tss->cr3))
                return emulate_gp(ctxt, 0);
        ctxt->_eip = tss->eip;
+
        ctxt->eflags = tss->eflags | 2;
+       if (ctxt->eflags & 0x20000)
+               ctxt->mode = X86EMUL_MODE_VM86;
+       else
+               ctxt->mode = X86EMUL_MODE_PROT32;
+       kvm_set_rflags(emul_to_vcpu(ctxt), ctxt->eflags);
+
        ctxt->regs[VCPU_REGS_RAX] = tss->eax;
        ctxt->regs[VCPU_REGS_RCX] = tss->ecx;
        ctxt->regs[VCPU_REGS_RDX] = tss->edx;
@@ -2372,7 +2383,7 @@ static int emulator_do_task_switch(struct 
x86_emulate_ctxt *ctxt,
 
        /* FIXME: check that next_tss_desc is tss */
 
-       if (reason != TASK_SWITCH_IRET) {
+       if (reason != TASK_SWITCH_IRET && reason != TASK_SWITCH_GATE) {
                if ((tss_selector & 3) > next_tss_desc.dpl ||
                    ops->cpl(ctxt) > next_tss_desc.dpl)
                        return emulate_gp(ctxt, 0);
-- 
1.7.6.5

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to