WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH] x86/hvm: hypercall adjustments

To: <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] x86/hvm: hypercall adjustments
From: "Jan Beulich" <jbeulich@xxxxxxxxxx>
Date: Mon, 14 May 2007 17:30:38 +0200
Delivery-date: Mon, 14 May 2007 08:28:20 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
- 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>

Index: 2007-05-14/xen/arch/x86/domain.c
===================================================================
--- 2007-05-14.orig/xen/arch/x86/domain.c       2007-05-14 13:43:44.000000000 
+0200
+++ 2007-05-14/xen/arch/x86/domain.c    2007-05-14 14:27:23.000000000 +0200
@@ -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>
@@ -1234,6 +1235,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, ...)
 {
@@ -1265,7 +1268,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++ )
             {
@@ -1301,6 +1306,8 @@ unsigned long hypercall_create_continuat
                 }
             }
         }
+
+        this_cpu(hc_preempted) = 1;
     }
 
     va_end(args);
Index: 2007-05-14/xen/arch/x86/hvm/hvm.c
===================================================================
--- 2007-05-14.orig/xen/arch/x86/hvm/hvm.c      2007-05-14 13:47:02.000000000 
+0200
+++ 2007-05-14/xen/arch/x86/hvm/hvm.c   2007-05-14 14:21:26.000000000 +0200
@@ -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;
+    int flush, mode = hvm_guest_x86_mode(current);
+    uint32_t eax = regs->eax;
 
-    hvm_store_cpu_guest_regs(current, regs, NULL);
+    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 ( unlikely(ring_3(regs)) )
+    if ( (eax >= NR_hypercalls) || !hvm_hypercall32_table[eax] )
     {
-        regs->eax = -EPERM;
-        return 0;
+        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);
+    flush = (eax == __HYPERVISOR_memory_op);
+    this_cpu(hc_preempted) = 0;
 
-    preempted = (regs->eip != 0xF0F0F0FF);
-    regs->eip = old_eip;
-
-    hvm_load_cpu_guest_regs(current, regs);
+#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 (preempted ? HVM_HCALL_preempted :
+    return (this_cpu(hc_preempted) ? HVM_HCALL_preempted :
             flush ? HVM_HCALL_invalidate : HVM_HCALL_completed);
 }
 
Index: 2007-05-14/xen/arch/x86/hvm/platform.c
===================================================================
--- 2007-05-14.orig/xen/arch/x86/hvm/platform.c 2007-04-23 10:01:41.000000000 
+0200
+++ 2007-05-14/xen/arch/x86/hvm/platform.c      2007-05-14 13:47:25.000000000 
+0200
@@ -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 )
Index: 2007-05-14/xen/arch/x86/hvm/svm/svm.c
===================================================================
--- 2007-05-14.orig/xen/arch/x86/hvm/svm/svm.c  2007-05-03 09:45:09.000000000 
+0200
+++ 2007-05-14/xen/arch/x86/hvm/svm/svm.c       2007-05-14 13:47:25.000000000 
+0200
@@ -563,14 +563,6 @@ static inline void svm_restore_dr(struct
 }
 
 
-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;
@@ -581,13 +573,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);
 }
 
 void svm_update_host_cr3(struct vcpu *v)
Index: 2007-05-14/xen/arch/x86/hvm/vmx/vmx.c
===================================================================
--- 2007-05-14.orig/xen/arch/x86/hvm/vmx/vmx.c  2007-05-03 09:45:09.000000000 
+0200
+++ 2007-05-14/xen/arch/x86/hvm/vmx/vmx.c       2007-05-14 13:47:25.000000000 
+0200
@@ -995,31 +995,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;
-
-    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;
+    unsigned int 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)
Index: 2007-05-14/xen/include/asm-x86/hypercall.h
===================================================================
--- 2007-05-14.orig/xen/include/asm-x86/hypercall.h     2007-04-23 
10:01:46.000000000 +0200
+++ 2007-05-14/xen/include/asm-x86/hypercall.h  2007-05-14 14:26:36.000000000 
+0200
@@ -15,6 +15,15 @@
  */
 #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_GUEST_HANDLE(evtchn_op_t) uop);



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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH] x86/hvm: hypercall adjustments, Jan Beulich <=