Re: [kvm-devel] catch vmentry failure (was enable gfxboot on VMX)

2008-03-02 Thread Avi Kivity
Guillaume Thouvenin wrote:
 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?

   

Yes.  An alternative (useful if a failed vmentry corrupts the guest 
state) is to check all register state when switching modes.

 -
 + 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);
   

Ideally you wouldn't call fix_rmode_seg() at all.  The guest will 
emulate until such time as the segments are valid for v8086, for example 
when the guest reloads them itself.

 + 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
   

Note you might need to emulate in protected mode as well, for a small 
part of the switch, for similar reasons.

-- 
error compiling committee.c: too many arguments to function


-
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse012070mrt/direct/01/
___
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel


[kvm-devel] catch vmentry failure (was enable gfxboot on VMX)

2008-02-29 Thread Guillaume Thouvenin
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