From patchwork Tue Sep 6 10:12:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Cooper X-Patchwork-Id: 9316321 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4CCEC601C0 for ; Tue, 6 Sep 2016 10:15:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3C33528B77 for ; Tue, 6 Sep 2016 10:15:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3124528C36; Tue, 6 Sep 2016 10:15:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 5964328C31 for ; Tue, 6 Sep 2016 10:15:22 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bhDNN-0005iF-KU; Tue, 06 Sep 2016 10:13:09 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bhDNL-0005ew-QB for xen-devel@lists.xen.org; Tue, 06 Sep 2016 10:13:08 +0000 Received: from [85.158.139.211] by server-12.bemta-5.messagelabs.com id 36/D2-09561-3B69EC75; Tue, 06 Sep 2016 10:13:07 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprFIsWRWlGSWpSXmKPExsXitHRDpO6maef CDaa2SVgs+biYxYHR4+ju30wBjFGsmXlJ+RUJrBnH3k1lL3icU3GifR1zA+Mh/y5GTg4JAX+J 6ysmsIPYbAL6ErtffGICsUUE1CVOd1xk7WLk4GAW8JM49MAXJCwsYCsx8esvVhCbRUBFomPWc zYQm1fAU2L2irfsECPlJM4f/8kMYnMKeEkc63sEZgsB1Wx40coCYatJXOu/xA7RKyhxcuYTsD izgITEwRcvmEHWSghwS/zttp/AyDcLSdUsJFULGJlWMaoXpxaVpRbpWuolFWWmZ5TkJmbm6Bo amOrlphYXJ6an5iQmFesl5+duYgSGEwMQ7GBc2+p8iFGSg0lJlFct8Fy4EF9SfkplRmJxRnxR aU5q8SFGGQ4OJQle1alAOcGi1PTUirTMHGBgw6QlOHiURHgDQNK8xQWJucWZ6RCpU4y6HH82T L7CJMSSl5+XKiXOWwRSJABSlFGaBzcCFmWXGGWlhHkZgY4S4ilILcrNLEGVf8UozsGoJMw7AW QKT2ZeCdymV0BHMAEdsW73aZAjShIRUlINjDpsPf9Z/5Va6Smm+esKlUfcLP9tZa3FbxTEfe3 F4wf3hapf/zi4/0Ctm96XlPLAzsMdVtdDkj/aKl/hdnpt1PXPoTzMx+hNrapUwxfZs8ur5YN3 nTO9FWGtfPvX8/Xl5m3bNlj9/NKk/ObTI2W93GlsR63/Tnj8pf2BwobKrQ6nN/R8e14qosRSn JFoqMVcVJwIAEIGGqmtAgAA X-Env-Sender: prvs=05022f6da=Andrew.Cooper3@citrix.com X-Msg-Ref: server-5.tower-206.messagelabs.com!1473156783!56406356!2 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 8.84; banners=-,-,- X-VirusChecked: Checked Received: (qmail 63720 invoked from network); 6 Sep 2016 10:13:05 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-5.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 6 Sep 2016 10:13:05 -0000 X-IronPort-AV: E=Sophos;i="5.30,291,1470700800"; d="scan'208";a="376488454" From: Andrew Cooper To: Xen-devel Date: Tue, 6 Sep 2016 11:12:54 +0100 Message-ID: <1473156779-11759-5-git-send-email-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1473156779-11759-1-git-send-email-andrew.cooper3@citrix.com> References: <1473156779-11759-1-git-send-email-andrew.cooper3@citrix.com> MIME-Version: 1.0 X-DLP: MIA1 Cc: Andrew Cooper , Jan Beulich Subject: [Xen-devel] [PATCH v2 4/9] x86/pv: Implement pv_hypercall() in C X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP In a similar style to hvm_do_hypercall(). The C version is far easier to understand and edit than the assembly versions. There are a few small differences however. The register clobbering values have changed (to match the HVM side), and in particular clobber the upper 32bits of 64bit arguments. The hypercall and performance counter record are reordered to increase code sharing between the 32bit and 64bit cases. The sole callers of __trace_hypercall_entry() were the assembly code. Given the new C layout, it is more convenient to fold __trace_hypercall_entry() into pv_hypercall(), and call __trace_hypercall() directly. Finally, pv_hypercall() will treat a NULL hypercall function pointer as -ENOSYS, allowing further cleanup. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- CC: Jan Beulich v2: * Use guest_mode_kernel() rather than TF_kernel_mode * Consistent use of 32bit stores * Don't truncate rax for 64bit domains * Move eax return assignment into C --- xen/arch/x86/hypercall.c | 120 +++++++++++++++++++++++++++++++++++++ xen/arch/x86/trace.c | 27 --------- xen/arch/x86/x86_64/asm-offsets.c | 1 - xen/arch/x86/x86_64/compat/entry.S | 69 +-------------------- xen/arch/x86/x86_64/entry.S | 61 +------------------ 5 files changed, 124 insertions(+), 154 deletions(-) diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c index 4b42f86..13a89a0 100644 --- a/xen/arch/x86/hypercall.c +++ b/xen/arch/x86/hypercall.c @@ -17,7 +17,12 @@ * Copyright (c) 2015,2016 Citrix Systems Ltd. */ +#include #include +#include + +extern hypercall_fn_t *const hypercall_table[NR_hypercalls], + *const compat_hypercall_table[NR_hypercalls]; #define ARGS(x, n) \ [ __HYPERVISOR_ ## x ] = (n) @@ -111,6 +116,121 @@ const uint8_t compat_hypercall_args_table[NR_hypercalls] = #undef ARGS +void pv_hypercall(struct cpu_user_regs *regs) +{ + struct vcpu *curr = current; +#ifndef NDEBUG + unsigned long old_rip = regs->rip; +#endif + unsigned long eax; + + ASSERT(guest_kernel_mode(curr, regs)); + + eax = is_pv_32bit_vcpu(curr) ? regs->_eax : regs->eax; + + if ( (eax >= NR_hypercalls) || !hypercall_table[eax] ) + { + regs->eax = -ENOSYS; + return; + } + + if ( !is_pv_32bit_vcpu(curr) ) + { + unsigned long rdi = regs->rdi; + unsigned long rsi = regs->rsi; + unsigned long rdx = regs->rdx; + unsigned long r10 = regs->r10; + unsigned long r8 = regs->r8; + unsigned long r9 = regs->r9; + +#ifndef NDEBUG + /* Deliberately corrupt parameter regs not used by this hypercall. */ + switch ( hypercall_args_table[eax] ) + { + case 0: rdi = 0xdeadbeefdeadf00dUL; + case 1: rsi = 0xdeadbeefdeadf00dUL; + case 2: rdx = 0xdeadbeefdeadf00dUL; + case 3: r10 = 0xdeadbeefdeadf00dUL; + case 4: r8 = 0xdeadbeefdeadf00dUL; + case 5: r9 = 0xdeadbeefdeadf00dUL; + } +#endif + if ( unlikely(tb_init_done) ) + { + unsigned long args[6] = { rdi, rsi, rdx, r10, r8, r9 }; + + __trace_hypercall(TRC_PV_HYPERCALL_V2, eax, args); + } + + regs->eax = hypercall_table[eax](rdi, rsi, rdx, r10, r8, r9); + +#ifndef NDEBUG + if ( regs->rip == old_rip ) + { + /* Deliberately corrupt parameter regs used by this hypercall. */ + switch ( hypercall_args_table[eax] ) + { + case 6: regs->r9 = 0xdeadbeefdeadf00dUL; + case 5: regs->r8 = 0xdeadbeefdeadf00dUL; + case 4: regs->r10 = 0xdeadbeefdeadf00dUL; + case 3: regs->rdx = 0xdeadbeefdeadf00dUL; + case 2: regs->rsi = 0xdeadbeefdeadf00dUL; + case 1: regs->rdi = 0xdeadbeefdeadf00dUL; + } + } +#endif + } + else + { + unsigned int ebx = regs->_ebx; + unsigned int ecx = regs->_ecx; + unsigned int edx = regs->_edx; + unsigned int esi = regs->_esi; + unsigned int edi = regs->_edi; + unsigned int ebp = regs->_ebp; + +#ifndef NDEBUG + /* Deliberately corrupt parameter regs not used by this hypercall. */ + switch ( compat_hypercall_args_table[eax] ) + { + case 0: ebx = 0xdeadf00d; + case 1: ecx = 0xdeadf00d; + case 2: edx = 0xdeadf00d; + case 3: esi = 0xdeadf00d; + case 4: edi = 0xdeadf00d; + case 5: ebp = 0xdeadf00d; + } +#endif + + if ( unlikely(tb_init_done) ) + { + unsigned long args[6] = { ebx, ecx, edx, esi, edi, ebp }; + + __trace_hypercall(TRC_PV_HYPERCALL_V2, eax, args); + } + + regs->_eax = compat_hypercall_table[eax](ebx, ecx, edx, esi, edi, ebp); + +#ifndef NDEBUG + if ( regs->rip == old_rip ) + { + /* Deliberately corrupt parameter regs used by this hypercall. */ + switch ( compat_hypercall_args_table[eax] ) + { + case 6: regs->_ebp = 0xdeadf00d; + case 5: regs->_edi = 0xdeadf00d; + case 4: regs->_esi = 0xdeadf00d; + case 3: regs->_edx = 0xdeadf00d; + case 2: regs->_ecx = 0xdeadf00d; + case 1: regs->_ebx = 0xdeadf00d; + } + } +#endif + } + + perfc_incr(hypercalls); +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/trace.c b/xen/arch/x86/trace.c index bd8596c..f11b309 100644 --- a/xen/arch/x86/trace.c +++ b/xen/arch/x86/trace.c @@ -6,33 +6,6 @@ #include #include -void __trace_hypercall_entry(void) -{ - struct cpu_user_regs *regs = guest_cpu_user_regs(); - unsigned long args[6]; - - if ( is_pv_32bit_vcpu(current) ) - { - args[0] = regs->ebx; - args[1] = regs->ecx; - args[2] = regs->edx; - args[3] = regs->esi; - args[4] = regs->edi; - args[5] = regs->ebp; - } - else - { - args[0] = regs->rdi; - args[1] = regs->rsi; - args[2] = regs->rdx; - args[3] = regs->r10; - args[4] = regs->r8; - args[5] = regs->r9; - } - - __trace_hypercall(TRC_PV_HYPERCALL_V2, regs->eax, args); -} - void __trace_pv_trap(int trapnr, unsigned long eip, int use_error_code, unsigned error_code) { diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c index 05d2b85..64905c6 100644 --- a/xen/arch/x86/x86_64/asm-offsets.c +++ b/xen/arch/x86/x86_64/asm-offsets.c @@ -153,7 +153,6 @@ void __dummy__(void) BLANK(); #ifdef CONFIG_PERF_COUNTERS - DEFINE(ASM_PERFC_hypercalls, PERFC_hypercalls); DEFINE(ASM_PERFC_exceptions, PERFC_exceptions); BLANK(); #endif diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S index f0eae56..e3cc10d 100644 --- a/xen/arch/x86/x86_64/compat/entry.S +++ b/xen/arch/x86/x86_64/compat/entry.S @@ -25,71 +25,10 @@ UNLIKELY_START(ne, msi_check) LOAD_C_CLOBBERED compat=1 ax=0 UNLIKELY_END(msi_check) - movl UREGS_rax(%rsp),%eax GET_CURRENT(bx) - cmpl $NR_hypercalls,%eax - jae compat_bad_hypercall -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - pushq UREGS_rbx(%rsp); pushq %rcx; pushq %rdx; pushq %rsi; pushq %rdi - pushq UREGS_rbp+5*8(%rsp) - leaq compat_hypercall_args_table(%rip),%r10 - movl $6,%ecx - subb (%r10,%rax,1),%cl - movq %rsp,%rdi - movl $0xDEADBEEF,%eax - rep stosq - popq %r8 ; popq %r9 ; xchgl %r8d,%r9d /* Args 5&6: zero extend */ - popq %rdx; popq %rcx; xchgl %edx,%ecx /* Args 3&4: zero extend */ - popq %rdi; popq %rsi; xchgl %edi,%esi /* Args 1&2: zero extend */ - movl UREGS_rax(%rsp),%eax - pushq %rax - pushq UREGS_rip+8(%rsp) -#define SHADOW_BYTES 16 /* Shadow EIP + shadow hypercall # */ -#else - /* Relocate argument registers and zero-extend to 64 bits. */ - xchgl %ecx,%esi /* Arg 2, Arg 4 */ - movl %edx,%edx /* Arg 3 */ - movl %edi,%r8d /* Arg 5 */ - movl %ebp,%r9d /* Arg 6 */ - movl UREGS_rbx(%rsp),%edi /* Arg 1 */ -#define SHADOW_BYTES 0 /* No on-stack shadow state */ -#endif - cmpb $0,tb_init_done(%rip) -UNLIKELY_START(ne, compat_trace) - call __trace_hypercall_entry - /* Restore the registers that __trace_hypercall_entry clobbered. */ - movl UREGS_rax+SHADOW_BYTES(%rsp),%eax /* Hypercall # */ - movl UREGS_rbx+SHADOW_BYTES(%rsp),%edi /* Arg 1 */ - movl UREGS_rcx+SHADOW_BYTES(%rsp),%esi /* Arg 2 */ - movl UREGS_rdx+SHADOW_BYTES(%rsp),%edx /* Arg 3 */ - movl UREGS_rsi+SHADOW_BYTES(%rsp),%ecx /* Arg 4 */ - movl UREGS_rdi+SHADOW_BYTES(%rsp),%r8d /* Arg 5 */ - movl UREGS_rbp+SHADOW_BYTES(%rsp),%r9d /* Arg 6 */ -#undef SHADOW_BYTES -UNLIKELY_END(compat_trace) - leaq compat_hypercall_table(%rip),%r10 - PERFC_INCR(hypercalls, %rax, %rbx) - callq *(%r10,%rax,8) -#ifndef NDEBUG - /* Deliberately corrupt parameter regs used by this hypercall. */ - popq %r10 # Shadow RIP - cmpq %r10,UREGS_rip+8(%rsp) - popq %rcx # Shadow hypercall index - jne compat_skip_clobber /* If RIP has changed then don't clobber. */ - leaq compat_hypercall_args_table(%rip),%r10 - movb (%r10,%rcx,1),%cl - movl $0xDEADBEEF,%r10d - testb %cl,%cl; jz compat_skip_clobber; movl %r10d,UREGS_rbx(%rsp) - cmpb $2, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rcx(%rsp) - cmpb $3, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rdx(%rsp) - cmpb $4, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rsi(%rsp) - cmpb $5, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rdi(%rsp) - cmpb $6, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rbp(%rsp) -compat_skip_clobber: -#endif - movl %eax,UREGS_rax(%rsp) # save the return value + mov %rsp, %rdi + call pv_hypercall /* %rbx: struct vcpu */ ENTRY(compat_test_all_events) @@ -167,10 +106,6 @@ compat_process_trap: call compat_create_bounce_frame jmp compat_test_all_events -compat_bad_hypercall: - movl $-ENOSYS,UREGS_rax(%rsp) - jmp compat_test_all_events - /* %rbx: struct vcpu, interrupts disabled */ ENTRY(compat_restore_all_guest) ASSERT_INTERRUPTS_DISABLED diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 086fcec..7b25f6b 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -101,61 +101,8 @@ ENTRY(lstar_enter) testb $TF_kernel_mode,VCPU_thread_flags(%rbx) jz switch_to_kernel -/*hypercall:*/ - movq %r10,%rcx - cmpq $NR_hypercalls,%rax - jae bad_hypercall -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - pushq %rdi; pushq %rsi; pushq %rdx; pushq %rcx; pushq %r8 ; pushq %r9 - leaq hypercall_args_table(%rip),%r10 - movq $6,%rcx - sub (%r10,%rax,1),%cl - movq %rsp,%rdi - movl $0xDEADBEEF,%eax - rep stosq - popq %r9 ; popq %r8 ; popq %rcx; popq %rdx; popq %rsi; popq %rdi - movq UREGS_rax(%rsp),%rax - pushq %rax - pushq UREGS_rip+8(%rsp) -#define SHADOW_BYTES 16 /* Shadow EIP + shadow hypercall # */ -#else -#define SHADOW_BYTES 0 /* No on-stack shadow state */ -#endif - cmpb $0,tb_init_done(%rip) -UNLIKELY_START(ne, trace) - call __trace_hypercall_entry - /* Restore the registers that __trace_hypercall_entry clobbered. */ - movq UREGS_rax+SHADOW_BYTES(%rsp),%rax /* Hypercall # */ - movq UREGS_rdi+SHADOW_BYTES(%rsp),%rdi /* Arg 1 */ - movq UREGS_rsi+SHADOW_BYTES(%rsp),%rsi /* Arg 2 */ - movq UREGS_rdx+SHADOW_BYTES(%rsp),%rdx /* Arg 3 */ - movq UREGS_r10+SHADOW_BYTES(%rsp),%rcx /* Arg 4 */ - movq UREGS_r8 +SHADOW_BYTES(%rsp),%r8 /* Arg 5 */ - movq UREGS_r9 +SHADOW_BYTES(%rsp),%r9 /* Arg 6 */ -#undef SHADOW_BYTES -UNLIKELY_END(trace) - leaq hypercall_table(%rip),%r10 - PERFC_INCR(hypercalls, %rax, %rbx) - callq *(%r10,%rax,8) -#ifndef NDEBUG - /* Deliberately corrupt parameter regs used by this hypercall. */ - popq %r10 # Shadow RIP - cmpq %r10,UREGS_rip+8(%rsp) - popq %rcx # Shadow hypercall index - jne skip_clobber /* If RIP has changed then don't clobber. */ - leaq hypercall_args_table(%rip),%r10 - movb (%r10,%rcx,1),%cl - movl $0xDEADBEEF,%r10d - cmpb $1,%cl; jb skip_clobber; movq %r10,UREGS_rdi(%rsp) - cmpb $2,%cl; jb skip_clobber; movq %r10,UREGS_rsi(%rsp) - cmpb $3,%cl; jb skip_clobber; movq %r10,UREGS_rdx(%rsp) - cmpb $4,%cl; jb skip_clobber; movq %r10,UREGS_r10(%rsp) - cmpb $5,%cl; jb skip_clobber; movq %r10,UREGS_r8(%rsp) - cmpb $6,%cl; jb skip_clobber; movq %r10,UREGS_r9(%rsp) -skip_clobber: -#endif - movq %rax,UREGS_rax(%rsp) # save the return value + mov %rsp, %rdi + call pv_hypercall /* %rbx: struct vcpu */ test_all_events: @@ -231,10 +178,6 @@ process_trap: call create_bounce_frame jmp test_all_events -bad_hypercall: - movq $-ENOSYS,UREGS_rax(%rsp) - jmp test_all_events - ENTRY(sysenter_entry) sti pushq $FLAT_USER_SS