From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Xen-devel <xen-devel@lists.xen.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>,
Jan Beulich <JBeulich@suse.com>
Subject: [PATCH 4/9] x86/pv: Implement pv_hypercall() in C
Date: Mon, 18 Jul 2016 10:51:40 +0100 [thread overview]
Message-ID: <1468835505-7278-5-git-send-email-andrew.cooper3@citrix.com> (raw)
In-Reply-To: <1468835505-7278-1-git-send-email-andrew.cooper3@citrix.com>
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 <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
---
xen/arch/x86/hypercall.c | 115 +++++++++++++++++++++++++++++++++++++
xen/arch/x86/trace.c | 27 ---------
xen/arch/x86/x86_64/asm-offsets.c | 1 -
xen/arch/x86/x86_64/compat/entry.S | 68 +---------------------
xen/arch/x86/x86_64/entry.S | 60 +------------------
5 files changed, 119 insertions(+), 152 deletions(-)
diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c
index 4b42f86..2dc787e 100644
--- a/xen/arch/x86/hypercall.c
+++ b/xen/arch/x86/hypercall.c
@@ -17,7 +17,9 @@
* Copyright (c) 2015,2016 Citrix Systems Ltd.
*/
+#include <xen/compiler.h>
#include <xen/hypercall.h>
+#include <xen/trace.h>
#define ARGS(x, n) \
[ __HYPERVISOR_ ## x ] = (n)
@@ -111,6 +113,119 @@ const uint8_t compat_hypercall_args_table[NR_hypercalls] =
#undef ARGS
+long pv_hypercall(struct cpu_user_regs *regs)
+{
+ struct vcpu *curr = current;
+#ifndef NDEBUG
+ unsigned long old_rip = regs->rip;
+#endif
+ long ret;
+ uint32_t eax = regs->eax;
+
+ ASSERT(curr->arch.flags & TF_kernel_mode);
+
+ if ( (eax >= NR_hypercalls) || !hypercall_table[eax] )
+ return -ENOSYS;
+
+ 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);
+ }
+
+ ret = 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->edx = 0xdeadbeefdeadf00dUL;
+ case 2: regs->esi = 0xdeadbeefdeadf00dUL;
+ case 1: regs->edi = 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);
+ }
+
+ ret = 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);
+
+ return ret;
+}
+
/*
* 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 <xen/sched.h>
#include <xen/trace.h>
-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 1a8e085..521af48 100644
--- a/xen/arch/x86/x86_64/compat/entry.S
+++ b/xen/arch/x86/x86_64/compat/entry.S
@@ -25,70 +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
+ mov %rsp, %rdi
+ call pv_hypercall
movl %eax,UREGS_rax(%rsp) # save the return value
/* %rbx: struct vcpu */
@@ -167,10 +107,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 5c6606b..1a7f8b7 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -101,60 +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
+ mov %rsp, %rdi
+ call pv_hypercall
movq %rax,UREGS_rax(%rsp) # save the return value
/* %rbx: struct vcpu */
@@ -231,10 +179,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
--
2.1.4
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
next prev parent reply other threads:[~2016-07-18 9:51 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-18 9:51 [PATCH 0/9] x86: Move the pv hypercall into C Andrew Cooper
2016-07-18 9:51 ` [PATCH 1/9] x86/hypercall: Move some of the hvm hypercall infrastructure into hypercall.h Andrew Cooper
2016-08-02 12:50 ` Jan Beulich
2016-08-02 13:14 ` Andrew Cooper
2016-08-02 13:28 ` Jan Beulich
2016-08-02 14:04 ` Julien Grall
2016-08-02 14:17 ` Jan Beulich
2016-08-02 14:26 ` Julien Grall
2016-08-02 14:54 ` Jan Beulich
2016-08-02 14:59 ` Andrew Cooper
2016-08-02 15:05 ` Jan Beulich
2016-08-02 18:43 ` Stefano Stabellini
2016-08-03 8:53 ` Jan Beulich
2016-08-03 10:55 ` Julien Grall
2016-08-03 18:20 ` Stefano Stabellini
2016-08-04 11:27 ` Julien Grall
2016-07-18 9:51 ` [PATCH 2/9] x86/pv: Support do_set_segment_base() for compat guests Andrew Cooper
2016-08-02 12:52 ` Jan Beulich
2016-08-02 13:25 ` Andrew Cooper
2016-08-02 13:31 ` Jan Beulich
2016-08-02 13:39 ` Andrew Cooper
2016-08-02 13:47 ` Jan Beulich
2016-07-18 9:51 ` [PATCH 3/9] x86/hypercall: Move the hypercall arg tables into C Andrew Cooper
2016-08-02 12:59 ` Jan Beulich
2016-07-18 9:51 ` Andrew Cooper [this message]
2016-08-02 13:12 ` [PATCH 4/9] x86/pv: Implement pv_hypercall() in C Jan Beulich
2016-08-02 14:06 ` Andrew Cooper
2016-08-02 14:19 ` Jan Beulich
2016-08-11 11:57 ` Andrew Cooper
2016-08-11 12:20 ` Jan Beulich
2016-07-18 9:51 ` [PATCH 5/9] x86/hypercall: Move the hypercall tables into C Andrew Cooper
2016-08-02 13:23 ` Jan Beulich
2016-08-02 13:30 ` Andrew Cooper
2016-08-02 13:40 ` Jan Beulich
2016-08-11 12:00 ` Andrew Cooper
2016-07-18 9:51 ` [PATCH 6/9] xen/multicall: Rework arch multicall handling Andrew Cooper
2016-07-20 12:35 ` Julien Grall
2016-08-03 15:02 ` Jan Beulich
2016-08-03 15:12 ` Andrew Cooper
2016-07-18 9:51 ` [PATCH 7/9] x86/pv: Merge the pv hypercall tables Andrew Cooper
2016-08-03 15:07 ` Jan Beulich
2016-08-11 12:36 ` Andrew Cooper
2016-07-18 9:51 ` [PATCH 8/9] x86/hypercall: Merge the hypercall arg tables Andrew Cooper
2016-08-03 15:12 ` Jan Beulich
2016-08-03 15:15 ` Andrew Cooper
2016-08-03 15:28 ` Jan Beulich
2016-07-18 9:51 ` [PATCH 9/9] x86/hypercall: Reduce the size of the hypercall tables Andrew Cooper
2016-08-03 15:17 ` Jan Beulich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1468835505-7278-5-git-send-email-andrew.cooper3@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=JBeulich@suse.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).