]> xenbits.xensource.com Git - people/royger/xen-test-framework.git/commitdiff
PV exception entry points
authorAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 11 Dec 2015 17:12:01 +0000 (17:12 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 18 Dec 2015 18:31:11 +0000 (18:31 +0000)
Infrastructure to register the virtual IDT with Xen and get execution back
into C when an exception occurs.  The existing 32 and 64bit entry points are
mostly reused, with small adjustments for PV guests.

Most of this change is importing and implementing Xen ABI bits for PV guests.

Exceptions are currently fatal.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/entry_32.S
arch/x86/entry_64.S
arch/x86/pv/traps.c
build/files.mk
include/arch/x86/segment.h
include/arch/x86/x86_32/hypercall-x86_32.h
include/arch/x86/x86_64/hypercall-x86_64.h
include/xen/arch-x86/xen-x86_32.h
include/xen/arch-x86/xen-x86_64.h
include/xen/arch-x86/xen.h
include/xtf/hypercall.h

index 3f65d79e5875c600d23456c39907d5b1d128333a..c904257be251c1e06c2efb092875b8eb7710bf0e 100644 (file)
@@ -5,16 +5,16 @@
 
 Stack frame layout:
 
-|          Hardware | Notes                |
-|-------------------+----------------------|
-|               <r> | <l>                  |
-|-------------------+----------------------|
-|               %ss | only on stack switch |
-|              %esp | only on stack switch |
-|            eflags |                      |
-|               %cs |                      |
-|              %eip |                      |
-| %esp-> error_code | if applicable        |
+|               Xen |          Hardware | Notes                |
+|-------------------+-------------------+----------------------|
+|               <r> |               <r> | <l>                  |
+|-------------------+-------------------+----------------------|
+|               %ss |               %ss | only on stack switch |
+|              %esp |              %esp | only on stack switch |
+|            eflags |            eflags |                      |
+| upcall_mask / %cs |               %cs |                      |
+|              %eip |              %eip |                      |
+| %esp-> error_code | %esp-> error_code | if applicable        |
 
 These stubs push an error_code of zero (if applicable) to make a common layout
 for the frame.  A further word of metadata is then pushed, currently just
index 9533c28361e12f7a9d392dd3d51489428be8426e..b0229f3827c0cc5f71fecdab820ec3b0573ab07a 100644 (file)
@@ -5,20 +5,25 @@
 
 Stack frame layout: (first aligned to 16 byte boundary)
 
-|          Hardware | Notes         |
-|-------------------+---------------|
-|               <r> | <l>           |
-|-------------------+---------------|
-|               %ss |               |
-|              %rsp |               |
-|            rflags |               |
-|               %cs |               |
-|              %rip |               |
-| %rsp-> error_code | if applicable |
+|               Xen |          Hardware | Notes         |
+|-------------------+-------------------+---------------|
+|               <r> |               <r> | <l>           |
+|-------------------+-------------------+---------------|
+|               %ss |               %ss |               |
+|              %rsp |              %rsp |               |
+|            rflags |            rflags |               |
+| upcall_mask / %cs |               %cs |               |
+|              %rip |              %rip |               |
+|        error_code | %rsp-> error_code | if applicable |
+|              %r11 |                   |               |
+| %rsp->       %rcx |                   |               |
 
-These stubs push an error_code of zero (if applicable) to make a common
-layout for the frame, then use the upper 32 bits of the error_code to stash
-additional metadata.  Currently just the entry vector.
+The %rcx and %r11 parameters are because Xen will typically SYSRET to the
+entry point; they should be restored promptly.
+
+The stubs then push an error_code (if required) to make a common layout for
+the frame, then use the upper 32bits of the error_code to stash additional
+metadata.  Currently just the entry vector.
 
 */
 
@@ -26,6 +31,12 @@ additional metadata.  Currently just the entry vector.
 
 ENTRY(entry_\sym)
 
+#if defined(CONFIG_ENV_pv64)
+        /* Restore results of Xen SYSRET'ing to this point. */
+        pop   %rcx
+        pop   %r11
+#endif
+
         .if !((1 << \vec) & X86_EXC_HAVE_EC)
         /* Push dummy error code (if needed) to align stack. */
         push  $0
index f8f9c8510827cafb6c8817165e6473709be68283..fda82851c135efcf1ddfb6774d756a8264d48000 100644 (file)
@@ -1,7 +1,61 @@
 #include <xtf/traps.h>
+#include <xtf/lib.h>
+#include <xtf/hypercall.h>
+
+#include <arch/x86/processor.h>
+#include <arch/x86/segment.h>
+
+/* Real entry points */
+void entry_DE(void);
+void entry_DB(void);
+void entry_NMI(void);
+void entry_BP(void);
+void entry_OF(void);
+void entry_BR(void);
+void entry_UD(void);
+void entry_NM(void);
+void entry_DF(void);
+void entry_TS(void);
+void entry_NP(void);
+void entry_SS(void);
+void entry_GP(void);
+void entry_PF(void);
+void entry_MF(void);
+void entry_AC(void);
+void entry_MC(void);
+void entry_XM(void);
+void entry_VE(void);
+
+struct xen_trap_info pv_default_trap_info[] =
+{
+    { X86_EXC_DE,  0|4, __KERN_CS, (unsigned long)&entry_DE  },
+    { X86_EXC_DB,  0|4, __KERN_CS, (unsigned long)&entry_DB  },
+    { X86_EXC_NMI, 0|4, __KERN_CS, (unsigned long)&entry_NMI },
+    { X86_EXC_BP,  3|4, __KERN_CS, (unsigned long)&entry_BP  },
+    { X86_EXC_OF,  3|4, __KERN_CS, (unsigned long)&entry_OF  },
+    { X86_EXC_BR,  0|4, __KERN_CS, (unsigned long)&entry_BR  },
+    { X86_EXC_UD,  0|4, __KERN_CS, (unsigned long)&entry_UD  },
+    { X86_EXC_NM,  0|4, __KERN_CS, (unsigned long)&entry_NM  },
+    { X86_EXC_DF,  0|4, __KERN_CS, (unsigned long)&entry_DF  },
+    { X86_EXC_TS,  0|4, __KERN_CS, (unsigned long)&entry_TS  },
+    { X86_EXC_NP,  0|4, __KERN_CS, (unsigned long)&entry_NP  },
+    { X86_EXC_SS,  0|4, __KERN_CS, (unsigned long)&entry_SS  },
+    { X86_EXC_GP,  0|4, __KERN_CS, (unsigned long)&entry_GP  },
+    { X86_EXC_PF,  0|4, __KERN_CS, (unsigned long)&entry_PF  },
+    { X86_EXC_MF,  0|4, __KERN_CS, (unsigned long)&entry_MF  },
+    { X86_EXC_AC,  0|4, __KERN_CS, (unsigned long)&entry_AC  },
+    { X86_EXC_MC,  0|4, __KERN_CS, (unsigned long)&entry_MC  },
+    { X86_EXC_XM,  0|4, __KERN_CS, (unsigned long)&entry_XM  },
+    { X86_EXC_VE,  0|4, __KERN_CS, (unsigned long)&entry_VE  },
+    { 0 }, /* Sentinel. */
+};
 
 void arch_init_traps(void)
 {
+    int rc = hypercall_set_trap_table(pv_default_trap_info);
+
+    if ( rc )
+        panic("Failed to set trap table: %d\n", rc);
 }
 
 void __noreturn arch_crash_hard(void)
index eb6ab21878d3d44edf4e92f13bcada9888bfc1a2..bf9a3ce48aec9a8af445127f51f5165be32a0429 100644 (file)
@@ -32,4 +32,7 @@ obj-hvm64 += $(ROOT)/arch/x86/entry_64.o
 obj-pv  += $(ROOT)/arch/x86/pv/traps.o
 
 obj-pv32 += $(obj-pv)
+obj-pv32 += $(ROOT)/arch/x86/entry_32.o
+
 obj-pv64 += $(obj-pv)
+obj-pv64 += $(ROOT)/arch/x86/entry_64.o
index 812adf2f1c384589839e155d92e4b1ac8dffa1cb..5a96f603e97973a3813be887e70103eac9efdf3a 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef XTF_X86_SEGMENT_H
 #define XTF_X86_SEGMENT_H
 
+#include <xen/arch-x86/xen.h>
+
 /*
  * GDT layout:
  *
 
 #endif
 
+/*
+ * PV guests by default use the Xen ABI-provided selectors.
+ */
+#if defined(CONFIG_ENV_pv64)
+
+#define __KERN_CS FLAT_RING3_CS64
+#define __KERN_DS FLAT_RING3_DS64
+
+#elif defined(CONFIG_ENV_pv32)
+
+#define __KERN_CS FLAT_RING1_CS
+#define __KERN_DS FLAT_RING1_DS
+
+#endif
+
 #endif /* XTF_X86_SEGMENT_H */
 
 /*
index e6e38dc043113c585ee6b926fd8a13730b43b337..1c627a7efcfbc02923ef5b3b74775a9bb4688101 100644 (file)
@@ -7,6 +7,18 @@
  * Inputs: %ebx, %ecx, %edx, %esi, %edi, %ebp (arguments 1-6)
  */
 
+#define _hypercall32_1(type, hcall, a1)                                 \
+    ({                                                                  \
+        long __res, __ign1;                                             \
+        asm volatile (                                                  \
+            "call hypercall_page + %c[offset]"                          \
+            : "=a" (__res), "=b" (__ign1)                               \
+            : [offset] "i" (hcall * 32),                                \
+              "1" ((long)(a1))                                          \
+            : "memory" );                                               \
+        (type)__res;                                                    \
+    })
+
 #define _hypercall32_2(type, hcall, a1, a2)                             \
     ({                                                                  \
         long __res, __ign1, __ign2;                                     \
index 4a6233b79e97dcafff161ca816f540efd5d83190..43ffe0459cc8594cd206095c5d29dbcaf0cacaef 100644 (file)
@@ -7,6 +7,18 @@
  * Inputs: %rdi, %rsi, %rdx, %r10, %r8, %r9 (arguments 1-6)
  */
 
+#define _hypercall64_1(type, hcall, a1)                                 \
+    ({                                                                  \
+        long __res, __ign1;                                             \
+        asm volatile (                                                  \
+            "call hypercall_page + %c[offset]"                          \
+            : "=a" (__res), "=D" (__ign1)                               \
+            : [offset] "i" (hcall * 32),                                \
+              "1" ((long)(a1))                                          \
+            : "memory" );                                               \
+        (type)__res;                                                    \
+    })
+
 #define _hypercall64_2(type, hcall, a1, a2)                             \
     ({                                                                  \
         long __res, __ign1, __ign2;                                     \
index 175b0a85499bc5f008bcb684cf9a2a715d2dd38a..57a559d52a97a4566c75a821b90cabe17abceec4 100644 (file)
@@ -1,6 +1,18 @@
 #ifndef XEN_PUBLIC_ARCH_X86_XEN_X86_32_H
 #define XEN_PUBLIC_ARCH_X86_XEN_X86_32_H
 
+/*
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+#define FLAT_RING1_CS 0xe019    /* GDT index 259 */
+#define FLAT_RING1_DS 0xe021    /* GDT index 260 */
+#define FLAT_RING1_SS 0xe021    /* GDT index 260 */
+#define FLAT_RING3_CS 0xe02b    /* GDT index 261 */
+#define FLAT_RING3_DS 0xe033    /* GDT index 262 */
+#define FLAT_RING3_SS 0xe033    /* GDT index 262 */
+
 #define MACH2PHYS_VIRT_START 0xF5800000UL
 
 #endif /* XEN_PUBLIC_ARCH_X86_XEN_X86_32_H */
index c8838b2a7853af12a66d04e91054a77674e237df..293fa0dd0263dcaa51879775d8a8045d26dfa846 100644 (file)
@@ -1,6 +1,20 @@
 #ifndef XEN_PUBLIC_ARCH_X86_XEN_X86_64_H
 #define XEN_PUBLIC_ARCH_X86_XEN_X86_64_H
 
+/*
+ * 64-bit segment selectors
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+
+#define FLAT_RING3_CS32 0xe023  /* GDT index 260 */
+#define FLAT_RING3_CS64 0xe033  /* GDT index 261 */
+#define FLAT_RING3_DS32 0xe02b  /* GDT index 262 */
+#define FLAT_RING3_DS64 0x0000  /* NULL selector */
+#define FLAT_RING3_SS32 0xe02b  /* GDT index 262 */
+#define FLAT_RING3_SS64 0xe02b  /* GDT index 262 */
+
 #define MACH2PHYS_VIRT_START 0xFFFF800000000000UL
 
 #endif /* XEN_PUBLIC_ARCH_X86_XEN_X86_64_H */
index 4ae3b9a2b1f4884d4cda249a7bddcbf36090daba..8642eae66bae8e104b9714c4bfda40746733c05f 100644 (file)
 
 #ifndef __ASSEMBLY__
 typedef unsigned long xen_pfn_t;
+
+/*
+ * Send an array of these to HYPERVISOR_set_trap_table().
+ * Terminate the array with a sentinel entry, with traps[].address==0.
+ * The privilege level specifies which modes may enter a trap via a software
+ * interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate
+ * privilege levels as follows:
+ *  Level == 0: Noone may enter
+ *  Level == 1: Kernel may enter
+ *  Level == 2: Kernel may enter
+ *  Level == 3: Everyone may enter
+ */
+struct xen_trap_info {
+    uint8_t       vector;  /* exception vector                              */
+    uint8_t       flags;   /* 0-3: privilege level; 4: clear event enable?  */
+    uint16_t      cs;      /* code selector                                 */
+    unsigned long address; /* code offset                                   */
+};
+
 #endif
 
 #endif /* XEN_PUBLIC_ARCH_X86_XEN_H */
index 9e1fe60cde29886225f76101abd8799690d5ef3d..124ff6a8b2ee23b373cf734cf4e8f2b415425978 100644 (file)
@@ -7,12 +7,14 @@
 #if defined(__x86_64__)
 
 # include <arch/x86/x86_64/hypercall-x86_64.h>
+# define HYPERCALL1 _hypercall64_1
 # define HYPERCALL2 _hypercall64_2
 # define HYPERCALL3 _hypercall64_3
 
 #elif defined(__i386__)
 
 # include <arch/x86/x86_32/hypercall-x86_32.h>
+# define HYPERCALL1 _hypercall32_1
 # define HYPERCALL2 _hypercall32_2
 # define HYPERCALL3 _hypercall32_3
 
@@ -32,6 +34,11 @@ extern uint8_t hypercall_page[PAGE_SIZE];
 /*
  * Hypercall primatives, compiled for the correct bitness
  */
+static inline long hypercall_set_trap_table(const struct xen_trap_info *ti)
+{
+    return HYPERCALL1(long, __HYPERVISOR_set_trap_table, ti);
+}
+
 static inline long hypercall_sched_op(unsigned int cmd, void *arg)
 {
     return HYPERCALL2(long, __HYPERVISOR_sched_op, cmd, arg);