On Mon, Jan 30, 2012 at 12:05:37PM +0100, Kevin Wolf wrote: > >> + > >> + /* > >> + * If we're switching between Protected Mode and VM86, we need to make > >> + * sure to update the mode before loading the segment descriptors so > >> + * that the selectors are interpreted correctly. > >> + * > >> + * Need to get it to the vcpu struct immediately because it influences > >> + * the CPL which is checked at least when loading the segment > >> + * descriptors and when pushing an error code to the new kernel stack. > >> + */ > >> + if (ctxt->eflags & X86_EFLAGS_VM) > >> + ctxt->mode = X86EMUL_MODE_VM86; > >> + else > >> + ctxt->mode = X86EMUL_MODE_PROT32; > >> + > > > > Shouldn't this be done after the set_segment_selector() block? My > > interpretation of the SDM is that if a fault happens while loading > > descriptors the fault happens with old segment cache, that is, it needs > > to be interpreted according to the old mode. > > This is closely related to my argument with Gleb whether CPL changes > when rflags is reloaded or if it only happens when cs is reloaded. I > argued that it makes more sense to couple it with cs, so I guess I have > to agree with you mostly. > > The SDM says that any faults during loading the segment descriptors > happen in the context of the new task, and the task switch is completed > before an exception is generated. So it shouldn't make any difference to > the guest what the exact point is at which we change CPL, it's an KVM > internal decision. > Actually no. What if fault happens during loading of CS descriptor? Spec clearly says it should be performed in a new task context. Meaning in vm86 mode. So cpl switch should happen already. > So what about this order: > > 1. Reload general purpose registers and eflags without updating mode > or writing back rflags to the vcpu struct. > > 2. Load segment selectors without changing the DPL yet. > > 3. Load segment descriptors, and disable the privilege checks in > load_segment_descriptor using a new flag. For SVM, this updates > the CPL when cs is reloaded. > > 4. Call ctxt->ops.set_rflag so that VMX updates the CPL. Should be > cleaned up in a follow-up patch, so that VMX uses set_segment > to update the CPL, like SVM does. > > Would this match your interpretation? > > >> + ctxt->ops->set_rflags(ctxt, ctxt->eflags); > >> + > >> + /* General purpose registers */ > >> ctxt->regs[VCPU_REGS_RAX] = tss->eax; > >> ctxt->regs[VCPU_REGS_RCX] = tss->ecx; > >> ctxt->regs[VCPU_REGS_RDX] = tss->edx; > >> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > >> index dc3e945..502b5c3 100644 > >> --- a/arch/x86/kvm/x86.c > >> +++ b/arch/x86/kvm/x86.c > >> @@ -4040,6 +4040,11 @@ static int emulator_set_cr(struct x86_emulate_ctxt *ctxt, int cr, ulong val) > >> return res; > >> } > >> > >> +static void emulator_set_rflags(struct x86_emulate_ctxt *ctxt, ulong val) > >> +{ > >> + kvm_set_rflags(emul_to_vcpu(ctxt), val); > >> +} > >> + > >> static int emulator_get_cpl(struct x86_emulate_ctxt *ctxt) > >> { > >> return kvm_x86_ops->get_cpl(emul_to_vcpu(ctxt)); > >> @@ -4199,6 +4204,7 @@ static struct x86_emulate_ops emulate_ops = { > >> .set_idt = emulator_set_idt, > >> .get_cr = emulator_get_cr, > >> .set_cr = emulator_set_cr, > >> + .set_rflags = emulator_set_rflags, > >> .cpl = emulator_get_cpl, > >> .get_dr = emulator_get_dr, > >> .set_dr = emulator_set_dr, > > > > It would be good to switch the entire emulator to use ->set_rflags() > > instead of sometimes letting the caller do it. > > If we change the CPL only with a cs reload, set_rflags can be dropped > completely in the end. > > Kevin -- Gleb. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html