From: Andrew Cooper Date: Fri, 11 Dec 2015 17:12:01 +0000 (+0000) Subject: PV exception entry points X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=7ba39f7de7a8f6ad7c70443a74e1ed4ae69e0163;p=people%2Froyger%2Fxen-test-framework.git PV exception entry points 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 --- diff --git a/arch/x86/entry_32.S b/arch/x86/entry_32.S index 3f65d79..c904257 100644 --- a/arch/x86/entry_32.S +++ b/arch/x86/entry_32.S @@ -5,16 +5,16 @@ Stack frame layout: -| Hardware | Notes | -|-------------------+----------------------| -| | | -|-------------------+----------------------| -| %ss | only on stack switch | -| %esp | only on stack switch | -| eflags | | -| %cs | | -| %eip | | -| %esp-> error_code | if applicable | +| Xen | Hardware | Notes | +|-------------------+-------------------+----------------------| +| | | | +|-------------------+-------------------+----------------------| +| %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 diff --git a/arch/x86/entry_64.S b/arch/x86/entry_64.S index 9533c28..b0229f3 100644 --- a/arch/x86/entry_64.S +++ b/arch/x86/entry_64.S @@ -5,20 +5,25 @@ Stack frame layout: (first aligned to 16 byte boundary) -| Hardware | Notes | -|-------------------+---------------| -| | | -|-------------------+---------------| -| %ss | | -| %rsp | | -| rflags | | -| %cs | | -| %rip | | -| %rsp-> error_code | if applicable | +| Xen | Hardware | Notes | +|-------------------+-------------------+---------------| +| | | | +|-------------------+-------------------+---------------| +| %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 diff --git a/arch/x86/pv/traps.c b/arch/x86/pv/traps.c index f8f9c85..fda8285 100644 --- a/arch/x86/pv/traps.c +++ b/arch/x86/pv/traps.c @@ -1,7 +1,61 @@ #include +#include +#include + +#include +#include + +/* 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) diff --git a/build/files.mk b/build/files.mk index eb6ab21..bf9a3ce 100644 --- a/build/files.mk +++ b/build/files.mk @@ -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 diff --git a/include/arch/x86/segment.h b/include/arch/x86/segment.h index 812adf2..5a96f60 100644 --- a/include/arch/x86/segment.h +++ b/include/arch/x86/segment.h @@ -1,6 +1,8 @@ #ifndef XTF_X86_SEGMENT_H #define XTF_X86_SEGMENT_H +#include + /* * GDT layout: * @@ -31,6 +33,21 @@ #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 */ /* diff --git a/include/arch/x86/x86_32/hypercall-x86_32.h b/include/arch/x86/x86_32/hypercall-x86_32.h index e6e38dc..1c627a7 100644 --- a/include/arch/x86/x86_32/hypercall-x86_32.h +++ b/include/arch/x86/x86_32/hypercall-x86_32.h @@ -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; \ diff --git a/include/arch/x86/x86_64/hypercall-x86_64.h b/include/arch/x86/x86_64/hypercall-x86_64.h index 4a6233b..43ffe04 100644 --- a/include/arch/x86/x86_64/hypercall-x86_64.h +++ b/include/arch/x86/x86_64/hypercall-x86_64.h @@ -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; \ diff --git a/include/xen/arch-x86/xen-x86_32.h b/include/xen/arch-x86/xen-x86_32.h index 175b0a8..57a559d 100644 --- a/include/xen/arch-x86/xen-x86_32.h +++ b/include/xen/arch-x86/xen-x86_32.h @@ -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 */ diff --git a/include/xen/arch-x86/xen-x86_64.h b/include/xen/arch-x86/xen-x86_64.h index c8838b2..293fa0d 100644 --- a/include/xen/arch-x86/xen-x86_64.h +++ b/include/xen/arch-x86/xen-x86_64.h @@ -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 */ diff --git a/include/xen/arch-x86/xen.h b/include/xen/arch-x86/xen.h index 4ae3b9a..8642eae 100644 --- a/include/xen/arch-x86/xen.h +++ b/include/xen/arch-x86/xen.h @@ -17,6 +17,25 @@ #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 */ diff --git a/include/xtf/hypercall.h b/include/xtf/hypercall.h index 9e1fe60..124ff6a 100644 --- a/include/xtf/hypercall.h +++ b/include/xtf/hypercall.h @@ -7,12 +7,14 @@ #if defined(__x86_64__) # include +# define HYPERCALL1 _hypercall64_1 # define HYPERCALL2 _hypercall64_2 # define HYPERCALL3 _hypercall64_3 #elif defined(__i386__) # include +# 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);