1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/asm_linkage.h>
28 #ifndef __xpv
29 #include <sys/xpv_support.h>
30 #endif
31 #include <sys/hypervisor.h>
32
33 /*
34 * Hypervisor "system calls"
35 *
36 * i386
37 * %eax == call number
38 * args in registers (%ebx, %ecx, %edx, %esi, %edi)
39 *
40 * amd64
41 * %rax == call number
42 * args in registers (%rdi, %rsi, %rdx, %r10, %r8, %r9)
43 *
44 * Note that for amd64 we use %r10 instead of %rcx for passing 4th argument
45 * as in C calling convention since the "syscall" instruction clobbers %rcx.
46 *
47 * (These calls can be done more efficiently as gcc-style inlines, but
48 * for simplicity and help with initial debugging, we use these primitives
49 * to build the hypervisor calls up from C wrappers.)
50 */
51
52 #if defined(__lint)
53
54 /*ARGSUSED*/
55 long
56 __hypercall0(int callnum)
57 { return (0); }
58
59 /*ARGSUSED*/
60 long
61 __hypercall1(int callnum, ulong_t a1)
62 { return (0); }
63
64 /*ARGSUSED*/
65 long
66 __hypercall2(int callnum, ulong_t a1, ulong_t a2)
67 { return (0); }
68
69 /*ARGSUSED*/
70 long
71 __hypercall3(int callnum, ulong_t a1, ulong_t a2, ulong_t a3)
72 { return (0); }
73
74 /*ARGSUSED*/
75 long
76 __hypercall4(int callnum, ulong_t a1, ulong_t a2, ulong_t a3, ulong_t a4)
77 { return (0); }
78
79 /*ARGSUSED*/
80 long
81 __hypercall5(int callnum,
82 ulong_t a1, ulong_t a2, ulong_t a3, ulong_t a4, ulong_t a5)
83 { return (0); }
84
85 /*ARGSUSED*/
86 int
87 __hypercall0_int(int callnum)
88 { return (0); }
89
90 /*ARGSUSED*/
91 int
92 __hypercall1_int(int callnum, ulong_t a1)
93 { return (0); }
94
95 /*ARGSUSED*/
96 int
97 __hypercall2_int(int callnum, ulong_t a1, ulong_t a2)
98 { return (0); }
99
100 /*ARGSUSED*/
101 int
102 __hypercall3_int(int callnum, ulong_t a1, ulong_t a2, ulong_t a3)
103 { return (0); }
104
105 /*ARGSUSED*/
106 int
107 __hypercall4_int(int callnum, ulong_t a1, ulong_t a2, ulong_t a3, ulong_t a4)
108 { return (0); }
109
110 /*ARGSUSED*/
111 int
112 __hypercall5_int(int callnum,
113 ulong_t a1, ulong_t a2, ulong_t a3, ulong_t a4, ulong_t a5)
114 { return (0); }
115
116 #else /* __lint */
117
118 /*
119 * XXPV grr - assembler can't deal with an instruction in a quoted string
120 */
121 #undef TRAP_INSTR /* cause it's currently "int $0x82" */
122
123 /*
124 * The method for issuing a hypercall (i.e. a system call to the
125 * hypervisor) varies from platform to platform. In 32-bit PV domains, an
126 * 'int 82' triggers the call. In 64-bit PV domains, a 'syscall' does the
127 * trick.
128 *
129 * HVM domains are more complicated. In all cases, we want to issue a
130 * VMEXIT instruction, but AMD and Intel use different opcodes to represent
131 * that instruction. Rather than build CPU-specific modules with the
132 * different opcodes, we use the 'hypercall page' provided by Xen. This
133 * page contains a collection of code stubs that do nothing except issue
134 * hypercalls using the proper instructions for this machine. To keep the
135 * wrapper code as simple and efficient as possible, we preallocate that
136 * page below. When the module is loaded, we ask Xen to remap the
137 * underlying PFN to that of the hypercall page.
138 *
139 * Note: this same mechanism could be used in PV domains, but using
140 * hypercall page requires a call and several more instructions than simply
141 * issuing the proper trap.
142 */
143 #if !defined(__xpv)
144
145 #define HYPERCALL_PAGESIZE 0x1000
146 #define HYPERCALL_SHINFO_PAGESIZE 0x1000
147
148 .data
149 .align HYPERCALL_SHINFO_PAGESIZE
150 .globl hypercall_shared_info_page
151 .type hypercall_shared_info_page, @object
152 .size hypercall_shared_info_page, HYPERCALL_SHINFO_PAGESIZE
153 hypercall_shared_info_page:
154 .skip HYPERCALL_SHINFO_PAGESIZE
155
156 .text
157 .align HYPERCALL_PAGESIZE
158 .globl hypercall_page
159 .type hypercall_page, @function
160 hypercall_page:
161 .skip HYPERCALL_PAGESIZE
162 .size hypercall_page, HYPERCALL_PAGESIZE
163 #if defined(__amd64)
164 #define TRAP_INSTR \
165 shll $5, %eax; \
166 addq $hypercall_page, %rax; \
167 jmp *%rax
168 #else
169 #define TRAP_INSTR \
170 shll $5, %eax; \
171 addl $hypercall_page, %eax; \
172 call *%eax
173 #endif
174
175 #else /* !_xpv */
176
177 #if defined(__amd64)
178 #define TRAP_INSTR syscall
179 #elif defined(__i386)
180 #define TRAP_INSTR int $0x82
181 #endif
182 #endif /* !__xpv */
183
184
185 #if defined(__amd64)
186
187 ENTRY_NP(__hypercall0)
188 ALTENTRY(__hypercall0_int)
189 movl %edi, %eax
190 TRAP_INSTR
191 ret
192 SET_SIZE(__hypercall0)
193
194 ENTRY_NP(__hypercall1)
195 ALTENTRY(__hypercall1_int)
196 movl %edi, %eax
197 movq %rsi, %rdi /* arg 1 */
198 TRAP_INSTR
199 ret
200 SET_SIZE(__hypercall1)
201
202 ENTRY_NP(__hypercall2)
203 ALTENTRY(__hypercall2_int)
204 movl %edi, %eax
205 movq %rsi, %rdi /* arg 1 */
206 movq %rdx, %rsi /* arg 2 */
207 TRAP_INSTR
208 ret
209 SET_SIZE(__hypercall2)
210
211 ENTRY_NP(__hypercall3)
212 ALTENTRY(__hypercall3_int)
213 movl %edi, %eax
214 movq %rsi, %rdi /* arg 1 */
215 movq %rdx, %rsi /* arg 2 */
216 movq %rcx, %rdx /* arg 3 */
217 TRAP_INSTR
218 ret
219 SET_SIZE(__hypercall3)
220
221 ENTRY_NP(__hypercall4)
222 ALTENTRY(__hypercall4_int)
223 movl %edi, %eax
224 movq %rsi, %rdi /* arg 1 */
225 movq %rdx, %rsi /* arg 2 */
226 movq %rcx, %rdx /* arg 3 */
227 movq %r8, %r10 /* r10 = 4th arg */
228 TRAP_INSTR
229 ret
230 SET_SIZE(__hypercall4)
231
232 ENTRY_NP(__hypercall5)
233 ALTENTRY(__hypercall5_int)
234 movl %edi, %eax
235 movq %rsi, %rdi /* arg 1 */
236 movq %rdx, %rsi /* arg 2 */
237 movq %rcx, %rdx /* arg 3 */
238 movq %r8, %r10 /* r10 = 4th arg */
239 movq %r9, %r8 /* arg 5 */
240 TRAP_INSTR
241 ret
242 SET_SIZE(__hypercall5)
243
244 #elif defined(__i386)
245
246 ENTRY_NP(__hypercall0)
247 ALTENTRY(__hypercall0_int)
248 movl 4(%esp), %eax
249 TRAP_INSTR
250 ret
251 SET_SIZE(__hypercall0)
252
253 ENTRY_NP(__hypercall1)
254 ALTENTRY(__hypercall1_int)
255 pushl %ebx
256 movl 8(%esp), %eax
257 movl 12(%esp), %ebx
258 TRAP_INSTR
259 popl %ebx
260 ret
261 SET_SIZE(__hypercall1)
262
263 ENTRY_NP(__hypercall2)
264 ALTENTRY(__hypercall2_int)
265 pushl %ebx
266 movl 8(%esp), %eax
267 movl 12(%esp), %ebx
268 movl 16(%esp), %ecx
269 TRAP_INSTR
270 popl %ebx
271 ret
272 SET_SIZE(__hypercall2)
273
274 ENTRY_NP(__hypercall3)
275 ALTENTRY(__hypercall3_int)
276 pushl %ebx
277 movl 8(%esp), %eax
278 movl 12(%esp), %ebx
279 movl 16(%esp), %ecx
280 movl 20(%esp), %edx
281 TRAP_INSTR
282 popl %ebx
283 ret
284 SET_SIZE(__hypercall3)
285
286 ENTRY_NP(__hypercall4)
287 ALTENTRY(__hypercall4_int)
288 pushl %ebx
289 pushl %esi
290 movl 12(%esp), %eax
291 movl 16(%esp), %ebx
292 movl 20(%esp), %ecx
293 movl 24(%esp), %edx
294 movl 28(%esp), %esi
295 TRAP_INSTR
296 popl %esi
297 popl %ebx
298 ret
299 SET_SIZE(__hypercall4)
300
301 ENTRY_NP(__hypercall5)
302 ALTENTRY(__hypercall5_int)
303 pushl %ebx
304 pushl %esi
305 pushl %edi
306 movl 16(%esp), %eax
307 movl 20(%esp), %ebx
308 movl 24(%esp), %ecx
309 movl 28(%esp), %edx
310 movl 32(%esp), %esi
311 movl 36(%esp), %edi
312 TRAP_INSTR
313 popl %edi
314 popl %esi
315 popl %ebx
316 ret
317 SET_SIZE(__hypercall5)
318
319 #endif /* __i386 */
320
321 #endif /* lint */