aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-x86/xen/hypercall.h
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-07-08 18:06:37 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-16 04:57:00 -0400
commite74359028d5489a281fb2c379a47b1d3cb14526e (patch)
tree564a2049511f15e5c0187fc31b16a45e5b614999 /include/asm-x86/xen/hypercall.h
parentca15f20f1126f897500ade892a2d598a08da1b56 (diff)
xen64: fix calls into hypercall page
The 64-bit calling convention for hypercalls uses different registers from 32-bit. Annoyingly, gcc's asm syntax doesn't have a way to specify one of the extra numeric reigisters in a constraint, so we must use explicitly placed register variables. Given that we have to do it for some args, may as well do it for all. Also fix syntax gcc generates for the call instruction itself. We need a plain direct call, but the asm expansion which works on 32-bit generates a rip-relative addressing mode in 64-bit, which is treated as an indirect call. The alternative is to pass the hypercall page offset into the asm, and have it add it to the hypercall page start address to generate the call. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Cc: Stephen Tweedie <sct@redhat.com> Cc: Eduardo Habkost <ehabkost@redhat.com> Cc: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include/asm-x86/xen/hypercall.h')
-rw-r--r--include/asm-x86/xen/hypercall.h170
1 files changed, 122 insertions, 48 deletions
diff --git a/include/asm-x86/xen/hypercall.h b/include/asm-x86/xen/hypercall.h
index 0551b9d82ec4..d0c5dedcb001 100644
--- a/include/asm-x86/xen/hypercall.h
+++ b/include/asm-x86/xen/hypercall.h
@@ -40,83 +40,157 @@
40#include <xen/interface/sched.h> 40#include <xen/interface/sched.h>
41#include <xen/interface/physdev.h> 41#include <xen/interface/physdev.h>
42 42
43/*
44 * The hypercall asms have to meet several constraints:
45 * - Work on 32- and 64-bit.
46 * The two architectures put their arguments in different sets of
47 * registers.
48 *
49 * - Work around asm syntax quirks
50 * It isn't possible to specify one of the rNN registers in a
51 * constraint, so we use explicit register variables to get the
52 * args into the right place.
53 *
54 * - Mark all registers as potentially clobbered
55 * Even unused parameters can be clobbered by the hypervisor, so we
56 * need to make sure gcc knows it.
57 *
58 * - Avoid compiler bugs.
59 * This is the tricky part. Because x86_32 has such a constrained
60 * register set, gcc versions below 4.3 have trouble generating
61 * code when all the arg registers and memory are trashed by the
62 * asm. There are syntactically simpler ways of achieving the
63 * semantics below, but they cause the compiler to crash.
64 *
65 * The only combination I found which works is:
66 * - assign the __argX variables first
67 * - list all actually used parameters as "+r" (__argX)
68 * - clobber the rest
69 *
70 * The result certainly isn't pretty, and it really shows up cpp's
71 * weakness as as macro language. Sorry. (But let's just give thanks
72 * there aren't more than 5 arguments...)
73 */
74
43extern struct { char _entry[32]; } hypercall_page[]; 75extern struct { char _entry[32]; } hypercall_page[];
44 76
77#define __HYPERCALL "call hypercall_page+%c[offset]"
78#define __HYPERCALL_ENTRY(x) \
79 [offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0]))
80
81#ifdef CONFIG_X86_32
82#define __HYPERCALL_RETREG "eax"
83#define __HYPERCALL_ARG1REG "ebx"
84#define __HYPERCALL_ARG2REG "ecx"
85#define __HYPERCALL_ARG3REG "edx"
86#define __HYPERCALL_ARG4REG "esi"
87#define __HYPERCALL_ARG5REG "edi"
88#else
89#define __HYPERCALL_RETREG "rax"
90#define __HYPERCALL_ARG1REG "rdi"
91#define __HYPERCALL_ARG2REG "rsi"
92#define __HYPERCALL_ARG3REG "rdx"
93#define __HYPERCALL_ARG4REG "r10"
94#define __HYPERCALL_ARG5REG "r8"
95#endif
96
97#define __HYPERCALL_DECLS \
98 register unsigned long __res asm(__HYPERCALL_RETREG); \
99 register unsigned long __arg1 asm(__HYPERCALL_ARG1REG) = __arg1; \
100 register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \
101 register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \
102 register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \
103 register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5;
104
105#define __HYPERCALL_0PARAM "=r" (__res)
106#define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1)
107#define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2)
108#define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3)
109#define __HYPERCALL_4PARAM __HYPERCALL_3PARAM, "+r" (__arg4)
110#define __HYPERCALL_5PARAM __HYPERCALL_4PARAM, "+r" (__arg5)
111
112#define __HYPERCALL_0ARG()
113#define __HYPERCALL_1ARG(a1) \
114 __HYPERCALL_0ARG() __arg1 = (unsigned long)(a1);
115#define __HYPERCALL_2ARG(a1,a2) \
116 __HYPERCALL_1ARG(a1) __arg2 = (unsigned long)(a2);
117#define __HYPERCALL_3ARG(a1,a2,a3) \
118 __HYPERCALL_2ARG(a1,a2) __arg3 = (unsigned long)(a3);
119#define __HYPERCALL_4ARG(a1,a2,a3,a4) \
120 __HYPERCALL_3ARG(a1,a2,a3) __arg4 = (unsigned long)(a4);
121#define __HYPERCALL_5ARG(a1,a2,a3,a4,a5) \
122 __HYPERCALL_4ARG(a1,a2,a3,a4) __arg5 = (unsigned long)(a5);
123
124#define __HYPERCALL_CLOBBER5 "memory"
125#define __HYPERCALL_CLOBBER4 __HYPERCALL_CLOBBER5, __HYPERCALL_ARG5REG
126#define __HYPERCALL_CLOBBER3 __HYPERCALL_CLOBBER4, __HYPERCALL_ARG4REG
127#define __HYPERCALL_CLOBBER2 __HYPERCALL_CLOBBER3, __HYPERCALL_ARG3REG
128#define __HYPERCALL_CLOBBER1 __HYPERCALL_CLOBBER2, __HYPERCALL_ARG2REG
129#define __HYPERCALL_CLOBBER0 __HYPERCALL_CLOBBER1, __HYPERCALL_ARG1REG
130
45#define _hypercall0(type, name) \ 131#define _hypercall0(type, name) \
46({ \ 132({ \
47 long __res; \ 133 __HYPERCALL_DECLS; \
48 asm volatile ( \ 134 __HYPERCALL_0ARG(); \
49 "call %[call]" \ 135 asm volatile (__HYPERCALL \
50 : "=a" (__res) \ 136 : __HYPERCALL_0PARAM \
51 : [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ 137 : __HYPERCALL_ENTRY(name) \
52 : "memory" ); \ 138 : __HYPERCALL_CLOBBER0); \
53 (type)__res; \ 139 (type)__res; \
54}) 140})
55 141
56#define _hypercall1(type, name, a1) \ 142#define _hypercall1(type, name, a1) \
57({ \ 143({ \
58 long __res, __ign1; \ 144 __HYPERCALL_DECLS; \
59 asm volatile ( \ 145 __HYPERCALL_1ARG(a1); \
60 "call %[call]" \ 146 asm volatile (__HYPERCALL \
61 : "=a" (__res), "=b" (__ign1) \ 147 : __HYPERCALL_1PARAM \
62 : "1" ((long)(a1)), \ 148 : __HYPERCALL_ENTRY(name) \
63 [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ 149 : __HYPERCALL_CLOBBER1); \
64 : "memory" ); \
65 (type)__res; \ 150 (type)__res; \
66}) 151})
67 152
68#define _hypercall2(type, name, a1, a2) \ 153#define _hypercall2(type, name, a1, a2) \
69({ \ 154({ \
70 long __res, __ign1, __ign2; \ 155 __HYPERCALL_DECLS; \
71 asm volatile ( \ 156 __HYPERCALL_2ARG(a1, a2); \
72 "call %[call]" \ 157 asm volatile (__HYPERCALL \
73 : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ 158 : __HYPERCALL_2PARAM \
74 : "1" ((long)(a1)), "2" ((long)(a2)), \ 159 : __HYPERCALL_ENTRY(name) \
75 [call] "m" (hypercall_page[__HYPERVISOR_##name]) \ 160 : __HYPERCALL_CLOBBER2); \
76 : "memory" ); \
77 (type)__res; \ 161 (type)__res; \
78}) 162})
79 163
80#define _hypercall3(type, name, a1, a2, a3) \ 164#define _hypercall3(type, name, a1, a2, a3) \
81({ \ 165({ \
82 long __res, __ign1, __ign2, __ign3; \ 166 __HYPERCALL_DECLS; \
83 asm volatile ( \ 167 __HYPERCALL_3ARG(a1, a2, a3); \
84 "call %[call]" \ 168 asm volatile (__HYPERCALL \
85 : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ 169 : __HYPERCALL_3PARAM \
86 "=d" (__ign3) \ 170 : __HYPERCALL_ENTRY(name) \
87 : "1" ((long)(a1)), "2" ((long)(a2)), \ 171 : __HYPERCALL_CLOBBER3); \
88 "3" ((long)(a3)), \
89 [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
90 : "memory" ); \
91 (type)__res; \ 172 (type)__res; \
92}) 173})
93 174
94#define _hypercall4(type, name, a1, a2, a3, a4) \ 175#define _hypercall4(type, name, a1, a2, a3, a4) \
95({ \ 176({ \
96 long __res, __ign1, __ign2, __ign3, __ign4; \ 177 __HYPERCALL_DECLS; \
97 asm volatile ( \ 178 __HYPERCALL_4ARG(a1, a2, a3, a4); \
98 "call %[call]" \ 179 asm volatile (__HYPERCALL \
99 : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ 180 : __HYPERCALL_4PARAM \
100 "=d" (__ign3), "=S" (__ign4) \ 181 : __HYPERCALL_ENTRY(name) \
101 : "1" ((long)(a1)), "2" ((long)(a2)), \ 182 : __HYPERCALL_CLOBBER4); \
102 "3" ((long)(a3)), "4" ((long)(a4)), \
103 [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
104 : "memory" ); \
105 (type)__res; \ 183 (type)__res; \
106}) 184})
107 185
108#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ 186#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
109({ \ 187({ \
110 long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ 188 __HYPERCALL_DECLS; \
111 asm volatile ( \ 189 __HYPERCALL_5ARG(a1, a2, a3, a4, a5); \
112 "call %[call]" \ 190 asm volatile (__HYPERCALL \
113 : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ 191 : __HYPERCALL_5PARAM \
114 "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ 192 : __HYPERCALL_ENTRY(name) \
115 : "1" ((long)(a1)), "2" ((long)(a2)), \ 193 : __HYPERCALL_CLOBBER5); \
116 "3" ((long)(a3)), "4" ((long)(a4)), \
117 "5" ((long)(a5)), \
118 [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
119 : "memory" ); \
120 (type)__res; \ 194 (type)__res; \
121}) 195})
122 196