[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86/hvm: hypercall adjustments



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1179221308 -3600
# Node ID f4390e34ad120afd4f7d65789d2394b7c6dfd7a5
# Parent  eb027b704dc55bb7f6e01a4b068c1ac407331ec1
x86/hvm: hypercall adjustments

- share more code between 32- and 64-bit variants
- properly handle continuations for 32-bit guests on 64-bit hv
- properly handle preemption (this must *not* rely on regs->eip, as
- other code may overwrite the value there by calling
- hvm_store_cpu_guest_regs()
- deny hypercall access when called from guest in vm86 mode, which
  requires that ???_guest_x86_mode() make real and vm86 modes distinguishable

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
---
 xen/arch/x86/domain.c           |    9 ++
 xen/arch/x86/hvm/hvm.c          |  121 +++++++++++++++++-----------------------
 xen/arch/x86/hvm/platform.c     |    3 
 xen/arch/x86/hvm/svm/svm.c      |   24 ++-----
 xen/arch/x86/hvm/vmx/vmx.c      |   29 ++-------
 xen/include/asm-x86/hypercall.h |    9 ++
 6 files changed, 90 insertions(+), 105 deletions(-)

diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Tue May 15 10:13:11 2007 +0100
+++ b/xen/arch/x86/domain.c     Tue May 15 10:28:28 2007 +0100
@@ -38,6 +38,7 @@
 #include <asm/mpspec.h>
 #include <asm/ldt.h>
 #include <asm/paging.h>
+#include <asm/hypercall.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
 #include <asm/msr.h>
@@ -1231,6 +1232,8 @@ void sync_vcpu_execstate(struct vcpu *v)
     __arg;                                                                  \
 })
 
+DEFINE_PER_CPU(char, hc_preempted);
+
 unsigned long hypercall_create_continuation(
     unsigned int op, const char *format, ...)
 {
@@ -1262,7 +1265,9 @@ unsigned long hypercall_create_continuat
         regs->eip -= 2;  /* re-execute 'syscall' / 'int 0x82' */
 
 #ifdef __x86_64__
-        if ( !is_pv_32on64_domain(current->domain) )
+        if ( !is_hvm_vcpu(current) ?
+             !is_pv_32on64_vcpu(current) :
+             (hvm_guest_x86_mode(current) == 8) )
         {
             for ( i = 0; *p != '\0'; i++ )
             {
@@ -1298,6 +1303,8 @@ unsigned long hypercall_create_continuat
                 }
             }
         }
+
+        this_cpu(hc_preempted) = 1;
     }
 
     va_end(args);
diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Tue May 15 10:13:11 2007 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Tue May 15 10:28:28 2007 +0100
@@ -663,7 +663,7 @@ typedef unsigned long hvm_hypercall_t(
 
 #if defined(__i386__)
 
-static hvm_hypercall_t *hvm_hypercall_table[NR_hypercalls] = {
+static hvm_hypercall_t *hvm_hypercall32_table[NR_hypercalls] = {
     HYPERCALL(memory_op),
     HYPERCALL(multicall),
     HYPERCALL(xen_version),
@@ -672,21 +672,6 @@ static hvm_hypercall_t *hvm_hypercall_ta
     HYPERCALL(hvm_op)
 };
 
-static void __hvm_do_hypercall(struct cpu_user_regs *pregs)
-{
-    if ( (pregs->eax >= NR_hypercalls) || !hvm_hypercall_table[pregs->eax] )
-    {
-        if ( pregs->eax != __HYPERVISOR_grant_table_op )
-            gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d bad hypercall %d.\n",
-                     current->domain->domain_id, current->vcpu_id, pregs->eax);
-        pregs->eax = -ENOSYS;
-        return;
-    }
-
-    pregs->eax = hvm_hypercall_table[pregs->eax](
-        pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi);
-}
-
 #else /* defined(__x86_64__) */
 
 static long do_memory_op_compat32(int cmd, XEN_GUEST_HANDLE(void) arg)
@@ -746,49 +731,38 @@ static hvm_hypercall_t *hvm_hypercall32_
     HYPERCALL(hvm_op)
 };
 
-static void __hvm_do_hypercall(struct cpu_user_regs *pregs)
-{
-    pregs->rax = (uint32_t)pregs->eax; /* mask in case compat32 caller */
-    if ( (pregs->rax >= NR_hypercalls) || !hvm_hypercall64_table[pregs->rax] )
-    {
-        if ( pregs->rax != __HYPERVISOR_grant_table_op )
-            gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d bad hypercall %ld.\n",
-                     current->domain->domain_id, current->vcpu_id, pregs->rax);
-        pregs->rax = -ENOSYS;
-        return;
-    }
-
-    if ( current->arch.paging.mode->guest_levels == 4 )
-    {
-        pregs->rax = hvm_hypercall64_table[pregs->rax](pregs->rdi,
-                                                       pregs->rsi,
-                                                       pregs->rdx,
-                                                       pregs->r10,
-                                                       pregs->r8);
-    }
-    else
-    {
-        pregs->eax = hvm_hypercall32_table[pregs->eax]((uint32_t)pregs->ebx,
-                                                       (uint32_t)pregs->ecx,
-                                                       (uint32_t)pregs->edx,
-                                                       (uint32_t)pregs->esi,
-                                                       (uint32_t)pregs->edi);
-    }
-}
-
 #endif /* defined(__x86_64__) */
 
 int hvm_do_hypercall(struct cpu_user_regs *regs)
 {
-    int flush, preempted;
-    unsigned long old_eip;
-
-    hvm_store_cpu_guest_regs(current, regs, NULL);
-
-    if ( unlikely(ring_3(regs)) )
-    {
-        regs->eax = -EPERM;
-        return 0;
+    int flush, mode = hvm_guest_x86_mode(current);
+    uint32_t eax = regs->eax;
+
+    switch ( mode )
+    {
+#ifdef __x86_64__
+    case 8:
+#endif
+    case 4:
+    case 2:
+        hvm_store_cpu_guest_regs(current, regs, NULL);
+        if ( unlikely(ring_3(regs)) )
+        {
+    default:
+            regs->eax = -EPERM;
+            return HVM_HCALL_completed;
+        }
+    case 0:
+        break;
+    }
+
+    if ( (eax >= NR_hypercalls) || !hvm_hypercall32_table[eax] )
+    {
+        if ( eax != __HYPERVISOR_grant_table_op )
+            gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d bad hypercall %u.\n",
+                     current->domain->domain_id, current->vcpu_id, eax);
+        regs->eax = -ENOSYS;
+        return HVM_HCALL_completed;
     }
 
     /*
@@ -796,20 +770,29 @@ int hvm_do_hypercall(struct cpu_user_reg
      * For now we also need to flush when pages are added, as qemu-dm is not
      * yet capable of faulting pages into an existing valid mapcache bucket.
      */
-    flush = ((uint32_t)regs->eax == __HYPERVISOR_memory_op);
-
-    /* Check for preemption: RIP will be modified from this dummy value. */
-    old_eip = regs->eip;
-    regs->eip = 0xF0F0F0FF;
-
-    __hvm_do_hypercall(regs);
-
-    preempted = (regs->eip != 0xF0F0F0FF);
-    regs->eip = old_eip;
-
-    hvm_load_cpu_guest_regs(current, regs);
-
-    return (preempted ? HVM_HCALL_preempted :
+    flush = (eax == __HYPERVISOR_memory_op);
+    this_cpu(hc_preempted) = 0;
+
+#ifdef __x86_64__
+    if ( mode == 8 )
+    {
+        regs->rax = hvm_hypercall64_table[eax](regs->rdi,
+                                               regs->rsi,
+                                               regs->rdx,
+                                               regs->r10,
+                                               regs->r8);
+    }
+    else
+#endif
+    {
+        regs->eax = hvm_hypercall32_table[eax]((uint32_t)regs->ebx,
+                                               (uint32_t)regs->ecx,
+                                               (uint32_t)regs->edx,
+                                               (uint32_t)regs->esi,
+                                               (uint32_t)regs->edi);
+    }
+
+    return (this_cpu(hc_preempted) ? HVM_HCALL_preempted :
             flush ? HVM_HCALL_invalidate : HVM_HCALL_completed);
 }
 
diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/platform.c
--- a/xen/arch/x86/hvm/platform.c       Tue May 15 10:13:11 2007 +0100
+++ b/xen/arch/x86/hvm/platform.c       Tue May 15 10:28:28 2007 +0100
@@ -1037,6 +1037,9 @@ void handle_mmio(unsigned long gpa)
     df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
 
     address_bytes = hvm_guest_x86_mode(v);
+    if (address_bytes < 2)
+        /* real or vm86 modes */
+        address_bytes = 2;
     inst_addr = hvm_get_segment_base(v, x86_seg_cs) + regs->eip;
     inst_len = hvm_instruction_length(inst_addr, address_bytes);
     if ( inst_len <= 0 )
diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Tue May 15 10:13:11 2007 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Tue May 15 10:28:28 2007 +0100
@@ -554,14 +554,6 @@ static inline void svm_restore_dr(struct
         __restore_debug_registers(v);
 }
 
-static int svm_realmode(struct vcpu *v)
-{
-    unsigned long cr0 = v->arch.hvm_svm.cpu_shadow_cr0;
-    unsigned long eflags = v->arch.hvm_svm.vmcb->rflags;
-
-    return (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE);
-}
-
 static int svm_interrupts_enabled(struct vcpu *v)
 {
     unsigned long eflags = v->arch.hvm_svm.vmcb->rflags;
@@ -572,13 +564,13 @@ static int svm_guest_x86_mode(struct vcp
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
 
-    if ( svm_long_mode_enabled(v) && vmcb->cs.attr.fields.l )
+    if ( unlikely(!(v->arch.hvm_svm.cpu_shadow_cr0 & X86_CR0_PE)) )
+        return 0;
+    if ( unlikely(vmcb->rflags & X86_EFLAGS_VM) )
+        return 1;
+    if ( svm_long_mode_enabled(v) && likely(vmcb->cs.attr.fields.l) )
         return 8;
-
-    if ( svm_realmode(v) )
-        return 2;
-
-    return (vmcb->cs.attr.fields.db ? 4 : 2);
+    return (likely(vmcb->cs.attr.fields.db) ? 4 : 2);
 }
 
 static void svm_update_host_cr3(struct vcpu *v)
@@ -1950,7 +1942,9 @@ static int svm_cr_access(struct vcpu *v,
     case INSTR_SMSW:
         value = v->arch.hvm_svm.cpu_shadow_cr0 & 0xFFFF;
         modrm = buffer[index+2];
-        addr_size = svm_guest_x86_mode( v );
+        addr_size = svm_guest_x86_mode(v);
+        if ( addr_size < 2 )
+            addr_size = 2;
         if ( likely((modrm & 0xC0) >> 6 == 3) )
         {
             gpreg = decode_src_reg(prefix, modrm);
diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Tue May 15 10:13:11 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Tue May 15 10:28:28 2007 +0100
@@ -994,31 +994,20 @@ static void vmx_init_hypercall_page(stru
     *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
 }
 
-static int vmx_realmode(struct vcpu *v)
-{
-    unsigned long rflags;
+static int vmx_guest_x86_mode(struct vcpu *v)
+{
+    unsigned int cs_ar_bytes;
 
     ASSERT(v == current);
 
-    rflags = __vmread(GUEST_RFLAGS);
-    return rflags & X86_EFLAGS_VM;
-}
-
-static int vmx_guest_x86_mode(struct vcpu *v)
-{
-    unsigned long cs_ar_bytes;
-
-    ASSERT(v == current);
-
+    if ( unlikely(!(v->arch.hvm_vmx.cpu_shadow_cr0 & X86_CR0_PE)) )
+        return 0;
+    if ( unlikely(__vmread(GUEST_RFLAGS) & X86_EFLAGS_VM) )
+        return 1;
     cs_ar_bytes = __vmread(GUEST_CS_AR_BYTES);
-
-    if ( vmx_long_mode_enabled(v) && (cs_ar_bytes & (1u<<13)) )
+    if ( vmx_long_mode_enabled(v) && likely(cs_ar_bytes & (1u<<13)) )
         return 8;
-
-    if ( vmx_realmode(v) )
-        return 2;
-
-    return ((cs_ar_bytes & (1u<<14)) ? 4 : 2);
+    return (likely(cs_ar_bytes & (1u<<14)) ? 4 : 2);
 }
 
 static int vmx_pae_enabled(struct vcpu *v)
diff -r eb027b704dc5 -r f4390e34ad12 xen/include/asm-x86/hypercall.h
--- a/xen/include/asm-x86/hypercall.h   Tue May 15 10:13:11 2007 +0100
+++ b/xen/include/asm-x86/hypercall.h   Tue May 15 10:28:28 2007 +0100
@@ -14,6 +14,15 @@
  * invocation of do_mmu_update() is resuming a previously preempted call.
  */
 #define MMU_UPDATE_PREEMPTED          (~(~0U>>1))
+
+/*
+ * This gets set to a non-zero value whenever hypercall_create_continuation()
+ * is used (outside of multicall context; in multicall context the second call
+ * from do_multicall() itself will have this effect). Internal callers of
+ * hypercall handlers interested in this condition must clear the flag prior
+ * to invoking the respective handler(s).
+ */
+DECLARE_PER_CPU(char, hc_preempted);
 
 extern long
 do_event_channel_op_compat(

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.