From: Andrew Cooper Date: Thu, 24 Dec 2015 21:06:00 +0000 (+0000) Subject: Setup for 64bit PV userspace execution X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=94d3a7ed1135a2440f9b6253fc166708237417d9;p=people%2Froyger%2Fxen-test-framework.git Setup for 64bit PV userspace execution * Implement read_cr3(), HYPERCALL4() and hypercall_mmuext_op(). * Use FLAT_RING3_SS64 for __{KERN,USER}_DS. * Set user %cr3. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/pv/traps.c b/arch/x86/pv/traps.c index 3612872..54e9a9b 100644 --- a/arch/x86/pv/traps.c +++ b/arch/x86/pv/traps.c @@ -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) diff --git a/include/arch/x86/lib.h b/include/arch/x86/lib.h index 7951695..0ebbe90 100644 --- a/include/arch/x86/lib.h +++ b/include/arch/x86/lib.h @@ -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 */ /* diff --git a/include/arch/x86/segment.h b/include/arch/x86/segment.h index 8082e62..444c903 100644 --- a/include/arch/x86/segment.h +++ b/include/arch/x86/segment.h @@ -56,11 +56,16 @@ * 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) diff --git a/include/arch/x86/x86_32/hypercall-x86_32.h b/include/arch/x86/x86_32/hypercall-x86_32.h index 1c627a7..9bb72ef 100644 --- a/include/arch/x86/x86_32/hypercall-x86_32.h +++ b/include/arch/x86/x86_32/hypercall-x86_32.h @@ -43,6 +43,20 @@ (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 */ /* diff --git a/include/arch/x86/x86_64/hypercall-x86_64.h b/include/arch/x86/x86_64/hypercall-x86_64.h index 43ffe04..885bd30 100644 --- a/include/arch/x86/x86_64/hypercall-x86_64.h +++ b/include/arch/x86/x86_64/hypercall-x86_64.h @@ -43,6 +43,21 @@ (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 */ /* diff --git a/include/xen/xen.h b/include/xen/xen.h index 9b68af3..7ae9de2 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -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 */ /* diff --git a/include/xtf/hypercall.h b/include/xtf/hypercall.h index 7e3bded..5102912 100644 --- a/include/xtf/hypercall.h +++ b/include/xtf/hypercall.h @@ -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);