On Mon, 18 Feb 2008 10:39:31 +0100
Alexander Graf [EMAIL PROTECTED] wrote:
So if you want to see a VMentry failure, just remove the SS patching
and you'll see one. My guess would be that you see a lot of problems
with otherwise working code too then, though, as SS can be anything in
that state.
So I made some tests and you were right, removing the SS patching
showed VM entry failure but it also generated lots of problems. Thus I
tried to modify a little bit the code and with the following patch (see
the end of the email) I can detect VM Entry failures without generating
other problems. It works when you use a distribution that is
big-real-mode free. I pasted the patch just to show the idea.
It's interesting because we can continue to use the virtual mode for the
majority of distribution and we can detect when a VM entry failure is
detected it means that we need to switch from virtual mode to full real
mode emulation. Such failure is caught in handle_vmentry_failure() when
patch applied. If it's doable, the next step is the modification of the
SS segment selector to succeed the vm-entry and the switch from virtual
mode to a real mode emulation that could be done in
handle_vmentry_failure(). Does it make sense?
Regards,
Guillaume
---
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 46e0e58..c2c3897 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1166,15 +1166,13 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
(vmcs_readl(CR4_READ_SHADOW) X86_CR4_VME));
update_exception_bitmap(vcpu);
-
+
+ fix_pmode_dataseg(VCPU_SREG_SS, vcpu-arch.rmode.ss);
fix_pmode_dataseg(VCPU_SREG_ES, vcpu-arch.rmode.es);
fix_pmode_dataseg(VCPU_SREG_DS, vcpu-arch.rmode.ds);
fix_pmode_dataseg(VCPU_SREG_GS, vcpu-arch.rmode.gs);
fix_pmode_dataseg(VCPU_SREG_FS, vcpu-arch.rmode.fs);
- vmcs_write16(GUEST_SS_SELECTOR, 0);
- vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
-
vmcs_write16(GUEST_CS_SELECTOR,
vmcs_read16(GUEST_CS_SELECTOR) ~SELECTOR_RPL_MASK);
vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
@@ -1228,20 +1226,12 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
update_exception_bitmap(vcpu);
- vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) 4);
- vmcs_write32(GUEST_SS_LIMIT, 0x);
- vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
-
- vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
- vmcs_write32(GUEST_CS_LIMIT, 0x);
- if (vmcs_readl(GUEST_CS_BASE) == 0x)
- vmcs_writel(GUEST_CS_BASE, 0xf);
- vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) 4);
-
+ fix_rmode_seg(VCPU_SREG_CS, vcpu-arch.rmode.cs);
fix_rmode_seg(VCPU_SREG_ES, vcpu-arch.rmode.es);
fix_rmode_seg(VCPU_SREG_DS, vcpu-arch.rmode.ds);
fix_rmode_seg(VCPU_SREG_GS, vcpu-arch.rmode.gs);
fix_rmode_seg(VCPU_SREG_FS, vcpu-arch.rmode.fs);
+ fix_rmode_seg(VCPU_SREG_SS, vcpu-arch.rmode.ss);
kvm_mmu_reset_context(vcpu);
init_rmode_tss(vcpu-kvm);
@@ -2257,6 +2247,39 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu
*vcpu,
static const int kvm_vmx_max_exit_handlers =
ARRAY_SIZE(kvm_vmx_exit_handlers);
+static int handle_vmentry_failure(u32 exit_reason, struct kvm_vcpu *vcpu)
+{
+ unsigned long exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ u32 info_field = vmcs_read32(VMX_INSTRUCTION_INFO);
+ unsigned int basic_exit_reason = (uint16_t) exit_reason;
+
+ printk(%s: exit reason 0x%x \n, __FUNCTION__, exit_reason);
+ printk(%s: vmentry failure reason %u \n, __FUNCTION__,
basic_exit_reason);
+ printk(%s: VMX-instruction Information field 0x%x \n, __FUNCTION__,
info_field);
+
+ switch (basic_exit_reason) {
+ case EXIT_REASON_INVALID_GUEST_STATE:
+ printk(caused by invalid guest state (%ld).\n,
exit_qualification);
+ /* At this point we need to modify SS selector to pass
vmentry test.
+* This modification prevent the usage of virtual mode
to emulate real
+* mode so we need to pass in big real mode emulation
+* with somehting like:
+* vcpu-arch.rmode.emulate = 1
+*/
+ break;
+ case EXIT_REASON_MSR_LOADING:
+ printk(caused by MSR entry %ld loading.\n,
exit_qualification);
+ break;
+ case EXIT_REASON_MACHINE_CHECK:
+ printk(caused by machine check.\n);
+ break;
+ default:
+ printk(reason not known yet!\n);
+ break;
+ }
+ return 0;
+}
+
/*
* The guest has exited. See if we can