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
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.
*/
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
#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)
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
#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 */
/*
* 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; \
* 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; \
#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 */
#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 */
#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 */
#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
/*
* 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);