]> xenbits.xensource.com Git - people/royger/xen-test-framework.git/commitdiff
Setup for 64bit PV userspace execution
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 24 Dec 2015 21:06:00 +0000 (21:06 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 5 Jan 2016 18:59:38 +0000 (18:59 +0000)
* Implement read_cr3(), HYPERCALL4() and hypercall_mmuext_op().
* Use FLAT_RING3_SS64 for __{KERN,USER}_DS.
* Set user %cr3.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/pv/traps.c
include/arch/x86/lib.h
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/xen.h
include/xtf/hypercall.h

index 3612872f622716183d41a8c8060fc0c0224d7791..54e9a9b3f8627bcb1efe37493bac5ab3d791c2cc 100644 (file)
@@ -67,6 +67,25 @@ void arch_init_traps(void)
     write_es(__USER_DS);
     write_fs(__USER_DS);
     write_gs(__USER_DS);
+
+#ifdef __x86_64__
+    /*
+     * Set the user pagetables (only applicable to 64bit PV).
+     *
+     * XTF uses a shared user/kernel address space, so register the kernel
+     * %cr3 as the user %cr3.
+     */
+    mmuext_op_t ext =
+    {
+        .cmd = MMUEXT_NEW_USER_BASEPTR,
+        .arg1.mfn = read_cr3() >> PAGE_SHIFT,
+    };
+
+    rc = hypercall_mmuext_op(&ext, 1, NULL, DOMID_SELF);
+    if ( rc )
+        panic("Failed to set user %%cr3: %d\n", rc);
+
+#endif
 }
 
 void __noreturn arch_crash_hard(void)
index 795169500450c94fd9f7c5949151f094e97562cd..0ebbe90f8362f33f21d826da5f2b00ae4ca3a9ac 100644 (file)
@@ -176,6 +176,15 @@ static inline unsigned long read_dr7(void)
     return val;
 }
 
+static inline unsigned long read_cr3(void)
+{
+    unsigned long cr3;
+
+    asm volatile ("mov %%cr3, %0" : "=r" (cr3));
+
+    return cr3;
+}
+
 #endif /* XTF_X86_LIB_H */
 
 /*
index 8082e62bd4aecb8fbc36696b48ff1d5f26513002..444c903130b8726b99184519802b6794201c6f3f 100644 (file)
  * report cpl0 when interrupting kernel mode.  Trim the kernel selectors down
  * to rpl0 so they match the exception frames; Xen will take care of bumping
  * rpl back to 3 when required.
+ *
+ * In Long mode, it is permitted to have NULL selectors for the plain data
+ * segment selectors (this is expressed in the Xen ABI), but not for %ss.  As
+ * __{KERN,USER}_DS are used for all data selectors including %ss, use the
+ * FLAT_RING3_SS64 rather than FLAT_RING3_DS64.
  */
 #define __KERN_CS (FLAT_RING3_CS64 & ~3)
-#define __KERN_DS (FLAT_RING3_DS64 & ~3)
+#define __KERN_DS (FLAT_RING3_SS64 & ~3)
 #define __USER_CS FLAT_RING3_CS64
-#define __USER_DS FLAT_RING3_DS64
+#define __USER_DS FLAT_RING3_SS64
 
 #elif defined(CONFIG_ENV_pv32)
 
index 1c627a7efcfbc02923ef5b3b74775a9bb4688101..9bb72ef08094be8c6629cac00698fc0ec099764c 100644 (file)
         (type)__res;                                                    \
     })
 
+#define _hypercall32_4(type, hcall, a1, a2, a3, a4)                     \
+    ({                                                                  \
+        long __res, __ign1, __ign2, __ign3, __ign4;                     \
+        asm volatile (                                                  \
+            "call hypercall_page + %c[offset]"                          \
+            : "=a" (__res), "=b" (__ign1), "=c" (__ign2), "=d" (__ign3),\
+              "=S" (__ign4)                                             \
+            : [offset] "i" (hcall * 32),                                \
+              "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)),     \
+              "4" ((long)(a4))                                          \
+            : "memory" );                                               \
+        (type)__res;                                                    \
+    })
+
 #endif /* XTF_X86_32_HYPERCALL_H */
 
 /*
index 43ffe0459cc8594cd206095c5d29dbcaf0cacaef..885bd30ed9f61a6abf6f4426f4970b4dc0972835 100644 (file)
         (type)__res;                                                    \
     })
 
+#define _hypercall64_4(type, hcall, a1, a2, a3, a4)                     \
+    ({                                                                  \
+        long __res, __ign1, __ign2, __ign3, __ign4;                     \
+        register long _a4 asm ("r10") = ((long)(a4));                   \
+        asm volatile (                                                  \
+            "call hypercall_page + %c[offset]"                          \
+            : "=a" (__res), "=D" (__ign1), "=S" (__ign2), "=d" (__ign3),\
+              "=&r" (__ign4)                                            \
+            : [offset] "i" (hcall * 32),                                \
+              "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)),     \
+              "4" (_a4)                                                 \
+            : "memory" );                                               \
+        (type)__res;                                                    \
+    })
+
 #endif /* XTF_X86_64_HYPERCALL_H */
 
 /*
index 9b68af3c637ae21f5f5f429d2d9d110220eb451c..7ae9de2e6f96f2d84290e2b4dba7ba9aff9389fd 100644 (file)
@@ -107,6 +107,112 @@ struct start_info {
 typedef struct start_info start_info_t;
 #endif
 
+/*
+ * MMU EXTENDED OPERATIONS
+ *
+ * HYPERVISOR_mmuext_op(mmuext_op_t uops[],
+ *                      unsigned int count,
+ *                      unsigned int *pdone,
+ *                      unsigned int foreigndom)
+ *
+ * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ *
+ * cmd: MMUEXT_(UN)PIN_*_TABLE
+ * mfn: Machine frame number to be (un)pinned as a p.t. page.
+ *      The frame must belong to the FD, if one is specified.
+ *
+ * cmd: MMUEXT_NEW_BASEPTR
+ * mfn: Machine frame number of new page-table base to install in MMU.
+ *
+ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only]
+ * mfn: Machine frame number of new page-table base to install in MMU
+ *      when in user space.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_LOCAL
+ * No additional arguments. Flushes local TLB.
+ *
+ * cmd: MMUEXT_INVLPG_LOCAL
+ * linear_addr: Linear address to be flushed from the local TLB.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_MULTI
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_INVLPG_MULTI
+ * linear_addr: Linear address to be flushed.
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_ALL
+ * No additional arguments. Flushes all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_INVLPG_ALL
+ * linear_addr: Linear address to be flushed from all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE
+ * No additional arguments. Writes back and flushes cache contents.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE_GLOBAL
+ * No additional arguments. Writes back and flushes cache contents
+ * on all CPUs in the system.
+ *
+ * cmd: MMUEXT_SET_LDT
+ * linear_addr: Linear address of LDT base (NB. must be page-aligned).
+ * nr_ents: Number of entries in LDT.
+ *
+ * cmd: MMUEXT_CLEAR_PAGE
+ * mfn: Machine frame number to be cleared.
+ *
+ * cmd: MMUEXT_COPY_PAGE
+ * mfn: Machine frame number of the destination page.
+ * src_mfn: Machine frame number of the source page.
+ *
+ * cmd: MMUEXT_[UN]MARK_SUPER
+ * mfn: Machine frame number of head of superpage to be [un]marked.
+ */
+#define MMUEXT_PIN_L1_TABLE      0
+#define MMUEXT_PIN_L2_TABLE      1
+#define MMUEXT_PIN_L3_TABLE      2
+#define MMUEXT_PIN_L4_TABLE      3
+#define MMUEXT_UNPIN_TABLE       4
+#define MMUEXT_NEW_BASEPTR       5
+#define MMUEXT_TLB_FLUSH_LOCAL   6
+#define MMUEXT_INVLPG_LOCAL      7
+#define MMUEXT_TLB_FLUSH_MULTI   8
+#define MMUEXT_INVLPG_MULTI      9
+#define MMUEXT_TLB_FLUSH_ALL    10
+#define MMUEXT_INVLPG_ALL       11
+#define MMUEXT_FLUSH_CACHE      12
+#define MMUEXT_SET_LDT          13
+#define MMUEXT_NEW_USER_BASEPTR 15
+#define MMUEXT_CLEAR_PAGE       16
+#define MMUEXT_COPY_PAGE        17
+#define MMUEXT_FLUSH_CACHE_GLOBAL 18
+#define MMUEXT_MARK_SUPER       19
+#define MMUEXT_UNMARK_SUPER     20
+
+#ifndef __ASSEMBLY__
+struct mmuext_op {
+    unsigned int cmd; /* => enum mmuext_cmd */
+    union {
+        /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR
+         * CLEAR_PAGE, COPY_PAGE, [UN]MARK_SUPER */
+        xen_pfn_t     mfn;
+        /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
+        unsigned long linear_addr;
+    } arg1;
+    union {
+        /* SET_LDT */
+        unsigned int nr_ents;
+        /* TLB_FLUSH_MULTI, INVLPG_MULTI */
+        const void *vcpumask;
+        /* COPY_PAGE */
+        xen_pfn_t src_mfn;
+    } arg2;
+};
+typedef struct mmuext_op mmuext_op_t;
+#endif
+
 #endif /* XEN_PUBLIC_XEN_H */
 
 /*
index 7e3bded3e2cc7863a1ba092ecb0e37178223e2e8..5102912b6cba62c27e967224044ac15f2128fac0 100644 (file)
@@ -10,6 +10,7 @@
 # define HYPERCALL1 _hypercall64_1
 # define HYPERCALL2 _hypercall64_2
 # define HYPERCALL3 _hypercall64_3
+# define HYPERCALL4 _hypercall64_4
 
 #elif defined(__i386__)
 
@@ -17,6 +18,7 @@
 # define HYPERCALL1 _hypercall32_1
 # define HYPERCALL2 _hypercall32_2
 # define HYPERCALL3 _hypercall32_3
+# define HYPERCALL4 _hypercall32_4
 
 #else
 # error Bad architecture for hypercalls
@@ -44,6 +46,15 @@ static inline long hypercall_stack_switch(const unsigned int ss, const void *sp)
     return HYPERCALL2(long, __HYPERVISOR_stack_switch, ss, sp);
 }
 
+static inline long hypercall_mmuext_op(const mmuext_op_t ops[],
+                                       unsigned int count,
+                                       unsigned int *done,
+                                       unsigned int foreigndom)
+{
+    return HYPERCALL4(long, __HYPERVISOR_mmuext_op,
+                      ops, count, done, foreigndom);
+}
+
 static inline long hypercall_sched_op(unsigned int cmd, void *arg)
 {
     return HYPERCALL2(long, __HYPERVISOR_sched_op, cmd, arg);