xref: /illumos-gate/usr/src/uts/common/xen/os/hypercall.c (revision d321a33cdd896e6b211d113a33698dd76e89b861)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Provides basic C wrappers around hypervisor invocation.
31  *
32  * i386: eax = vector: ebx, ecx, edx, esi, edi = args 1-5
33  *	 eax = return value
34  *	 (argument registers may be clobbered on return)
35  *
36  * amd64:rax = vector: rdi, rsi, rdx, r10, r8, r9 = args 1-6
37  *	 rax = return value
38  *	 (arguments registers not clobbered on return; rcx, r11 are)
39  */
40 
41 #include <sys/types.h>
42 #ifdef XPV_HVM_DRIVER
43 #include <sys/xpv_support.h>
44 #endif
45 
46 #include <sys/hypervisor.h>
47 #include <xen/public/sched.h>
48 #include <sys/debug.h>
49 #include <sys/archsystm.h>
50 
51 long
52 HYPERVISOR_set_trap_table(trap_info_t *table)
53 {
54 	return (__hypercall1(__HYPERVISOR_set_trap_table, (ulong_t)table));
55 }
56 
57 int
58 HYPERVISOR_mmu_update(mmu_update_t *req, int count, int *success_count,
59     domid_t domain_id)
60 {
61 	return (__hypercall4_int(__HYPERVISOR_mmu_update,
62 	    (ulong_t)req, (long)count, (ulong_t)success_count,
63 	    (ulong_t)domain_id));
64 }
65 
66 long
67 HYPERVISOR_set_gdt(ulong_t *frame_list, int entries)
68 {
69 	return (__hypercall2(
70 	    __HYPERVISOR_set_gdt, (ulong_t)frame_list, (long)entries));
71 }
72 
73 /*
74  * XXPV Seems like "sp" would be a better name for both amd64 and i386?
75  * For now stay consistent with xen project source.
76  */
77 long
78 HYPERVISOR_stack_switch(ulong_t ss, ulong_t esp)
79 {
80 	return (__hypercall2(__HYPERVISOR_stack_switch, ss, esp));
81 }
82 
83 #if defined(__amd64)
84 
85 long
86 HYPERVISOR_set_callbacks(ulong_t event_address, ulong_t failsafe_address,
87     ulong_t syscall_address)
88 {
89 	return (__hypercall3(__HYPERVISOR_set_callbacks,
90 	    event_address, failsafe_address, syscall_address));
91 }
92 
93 #elif defined(__i386)
94 
95 long
96 HYPERVISOR_set_callbacks(
97     ulong_t event_selector, ulong_t event_address,
98     ulong_t failsafe_selector, ulong_t failsafe_address)
99 {
100 	return (__hypercall4(__HYPERVISOR_set_callbacks,
101 	    event_selector, event_address,
102 	    failsafe_selector, failsafe_address));
103 }
104 
105 #endif	/* __amd64 */
106 
107 long
108 HYPERVISOR_fpu_taskswitch(int set)
109 {
110 	return (__hypercall1(__HYPERVISOR_fpu_taskswitch, (long)set));
111 }
112 
113 /* *** __HYPERVISOR_sched_op_compat *** OBSOLETED */
114 
115 long
116 HYPERVISOR_platform_op(xen_platform_op_t *platform_op)
117 {
118 	return (__hypercall1(__HYPERVISOR_platform_op, (ulong_t)platform_op));
119 }
120 
121 /* *** __HYPERVISOR_set_debugreg *** NOT IMPLEMENTED */
122 
123 /* *** __HYPERVISOR_get_debugreg *** NOT IMPLEMENTED */
124 
125 long
126 HYPERVISOR_update_descriptor(maddr_t ma, uint64_t desc)
127 {
128 #if defined(__amd64)
129 
130 	return (__hypercall2(__HYPERVISOR_update_descriptor, ma, desc));
131 
132 #elif defined(__i386)
133 
134 	return (__hypercall4(__HYPERVISOR_update_descriptor,
135 	    (ulong_t)ma, (ulong_t)(ma >>32),
136 	    (ulong_t)desc, (ulong_t)(desc >> 32)));
137 
138 #endif
139 }
140 
141 long
142 HYPERVISOR_memory_op(int cmd, void *arg)
143 {
144 	return (__hypercall2(__HYPERVISOR_memory_op, (long)cmd,
145 	    (ulong_t)arg));
146 }
147 
148 long
149 HYPERVISOR_multicall(void *call_list, uint_t nr_calls)
150 {
151 	return (__hypercall2(__HYPERVISOR_multicall,
152 	    (ulong_t)call_list, (ulong_t)nr_calls));
153 }
154 
155 int
156 HYPERVISOR_update_va_mapping(ulong_t va, uint64_t new_pte, ulong_t flags)
157 {
158 #if !defined(_BOOT)
159 	if (IN_XPV_PANIC())
160 		return (0);
161 #endif
162 #if defined(__amd64)
163 
164 	return (__hypercall3_int(__HYPERVISOR_update_va_mapping, va,
165 	    new_pte, flags));
166 
167 #elif defined(__i386)
168 
169 	return (__hypercall4_int(__HYPERVISOR_update_va_mapping, va,
170 	    (ulong_t)new_pte, (ulong_t)(new_pte >> 32), flags));
171 
172 #endif	/* __i386 */
173 }
174 
175 /*
176  * Note: this timeout must be the Xen system time not hrtime (see
177  * xpv_timestamp.c).
178  */
179 long
180 HYPERVISOR_set_timer_op(uint64_t timeout)
181 {
182 #if defined(__amd64)
183 
184 	return (__hypercall1(__HYPERVISOR_set_timer_op, timeout));
185 
186 #elif defined(__i386)
187 
188 	uint32_t timeout_hi = (uint32_t)(timeout >> 32);
189 	uint32_t timeout_lo = (uint32_t)timeout;
190 	return (__hypercall2(__HYPERVISOR_set_timer_op,
191 	    (ulong_t)timeout_lo, (ulong_t)timeout_hi));
192 
193 #endif	/* __i386 */
194 }
195 
196 /* *** __HYPERVISOR_event_channel_op_compat *** OBSOLETED */
197 
198 long
199 HYPERVISOR_xen_version(int cmd, void *arg)
200 {
201 	return (__hypercall2(__HYPERVISOR_xen_version, (long)cmd,
202 	    (ulong_t)arg));
203 }
204 
205 long
206 HYPERVISOR_console_io(int cmd, int count, char *str)
207 {
208 	return (__hypercall3(__HYPERVISOR_console_io, (long)cmd, (long)count,
209 	    (ulong_t)str));
210 }
211 
212 /* *** __HYPERVISOR_physdev_op_compat *** OBSOLETED */
213 
214 long
215 HYPERVISOR_grant_table_op(uint_t cmd, void *uop, uint_t count)
216 {
217 	int ret_val;
218 	ret_val = __hypercall3(__HYPERVISOR_grant_table_op,
219 	    (long)cmd, (ulong_t)uop, (ulong_t)count);
220 
221 #if !defined(_BOOT) && !defined(XPV_HVM_DRIVER)
222 	/*
223 	 * XXPV --
224 	 * The map_grant_ref call suffers a poor design flaw.
225 	 * It's the only hypervisor interface that creates page table mappings
226 	 * that doesn't take an entire PTE. Hence we can't create the
227 	 * mapping with a particular setting of the software PTE bits, NX, etc.
228 	 *
229 	 * Until the interface is fixed, we need to minimize the possiblity
230 	 * of dtrace or kmdb blowing up on a foreign mapping that doesn't
231 	 * have a correct setting for the soft bits. We'll force them here.
232 	 */
233 	if (ret_val == 0 && cmd == GNTTABOP_map_grant_ref) {
234 		extern void xen_fix_foreign(uint64_t);
235 		gnttab_map_grant_ref_t *mapops = (gnttab_map_grant_ref_t *)uop;
236 		uint_t i;
237 		for (i = 0; i < count; ++i) {
238 			if (mapops[i].status == GNTST_okay)
239 				xen_fix_foreign(mapops[i].host_addr);
240 		}
241 	}
242 #endif
243 	return (ret_val);
244 }
245 
246 long
247 HYPERVISOR_vm_assist(uint_t cmd, uint_t type)
248 {
249 	return (__hypercall2(__HYPERVISOR_vm_assist,
250 	    (ulong_t)cmd, (ulong_t)type));
251 }
252 
253 int
254 HYPERVISOR_update_va_mapping_otherdomain(ulong_t va,
255     uint64_t new_pte, ulong_t flags, domid_t domain_id)
256 {
257 #if defined(__amd64)
258 
259 	return (__hypercall4_int(__HYPERVISOR_update_va_mapping_otherdomain,
260 	    va, new_pte, flags, (ulong_t)domain_id));
261 
262 #elif defined(__i386)
263 
264 	return (__hypercall5_int(__HYPERVISOR_update_va_mapping_otherdomain,
265 	    va, (ulong_t)new_pte, (ulong_t)(new_pte >> 32), flags,
266 	    (ulong_t)domain_id));
267 
268 #endif	/* __i386 */
269 }
270 
271 /*
272  * *** __HYPERVISOR_iret ***
273  *   see HYPERVISOR_IRET() macro in i86xpv/sys/machprivregs.h
274  */
275 
276 long
277 HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args)
278 {
279 	return (__hypercall3(__HYPERVISOR_vcpu_op, (long)cmd, (long)vcpuid,
280 	    (ulong_t)extra_args));
281 }
282 
283 #if defined(__amd64)
284 
285 long
286 HYPERVISOR_set_segment_base(int reg, ulong_t value)
287 {
288 	return (__hypercall2(__HYPERVISOR_set_segment_base, (long)reg, value));
289 }
290 
291 #endif	/* __amd64 */
292 
293 int
294 HYPERVISOR_mmuext_op(struct mmuext_op *req, int count, uint_t *success_count,
295     domid_t domain_id)
296 {
297 	return (__hypercall4_int(__HYPERVISOR_mmuext_op,
298 	    (ulong_t)req, (long)count, (ulong_t)success_count,
299 	    (ulong_t)domain_id));
300 }
301 
302 long
303 HYPERVISOR_acm_op(int cmd, void *arg)
304 {
305 	return (__hypercall2(__HYPERVISOR_acm_op, (long)cmd, (ulong_t)arg));
306 }
307 
308 long
309 HYPERVISOR_nmi_op(int cmd, void *arg)
310 {
311 	return (__hypercall2(__HYPERVISOR_nmi_op, (long)cmd, (ulong_t)arg));
312 }
313 
314 long
315 HYPERVISOR_sched_op(int cmd, void *arg)
316 {
317 	return (__hypercall2(__HYPERVISOR_sched_op,
318 	    (ulong_t)cmd, (ulong_t)arg));
319 }
320 
321 long
322 HYPERVISOR_callback_op(int cmd, void *arg)
323 {
324 	return (__hypercall2(__HYPERVISOR_callback_op,
325 	    (ulong_t)cmd, (ulong_t)arg));
326 }
327 
328 /* *** __HYPERVISOR_xenoprof_op *** NOT IMPLEMENTED */
329 
330 long
331 HYPERVISOR_event_channel_op(int cmd, void *arg)
332 {
333 	return (__hypercall2(__HYPERVISOR_event_channel_op, (long)cmd,
334 	    (ulong_t)arg));
335 }
336 
337 long
338 HYPERVISOR_physdev_op(int cmd, void *arg)
339 {
340 	return (__hypercall2(__HYPERVISOR_physdev_op, (long)cmd,
341 	    (ulong_t)arg));
342 }
343 
344 long
345 HYPERVISOR_hvm_op(int cmd, void *arg)
346 {
347 	return (__hypercall2(__HYPERVISOR_hvm_op, (long)cmd, (ulong_t)arg));
348 }
349 
350 long
351 HYPERVISOR_sysctl(xen_sysctl_t *sysctl)
352 {
353 	return (__hypercall1(__HYPERVISOR_sysctl, (ulong_t)sysctl));
354 }
355 
356 long
357 HYPERVISOR_domctl(xen_domctl_t *domctl)
358 {
359 	return (__hypercall1(__HYPERVISOR_domctl, (ulong_t)domctl));
360 }
361 
362 /* *** __HYPERVISOR_kexec_op *** NOT IMPLEMENTED */
363 
364 /*
365  *
366  * HYPERCALL HELPER ROUTINES
367  *    These don't have there own unique hypercalls.
368  *
369  */
370 
371 long
372 HYPERVISOR_yield(void)
373 {
374 	return (HYPERVISOR_sched_op(SCHEDOP_yield, NULL));
375 }
376 
377 long
378 HYPERVISOR_block(void)
379 {
380 	return (HYPERVISOR_sched_op(SCHEDOP_block, NULL));
381 }
382 
383 long
384 HYPERVISOR_shutdown(uint_t reason)
385 {
386 	struct sched_shutdown sched_shutdown;
387 
388 	sched_shutdown.reason = reason;
389 
390 	return (HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown));
391 }
392 
393 /*
394  * Poll one or more event-channel ports, and return when pending.
395  * An optional timeout (in nanoseconds, absolute time since boot) may be
396  * specified. Note: this timeout must be the Xen system time not hrtime (see
397  * xpv_timestamp.c).
398  */
399 long
400 HYPERVISOR_poll(evtchn_port_t *ports, uint_t nr_ports, uint64_t timeout)
401 {
402 	struct sched_poll sched_poll;
403 
404 	/*LINTED: constant in conditional context*/
405 	set_xen_guest_handle(sched_poll.ports, ports);
406 	sched_poll.nr_ports = nr_ports;
407 	sched_poll.timeout = timeout;
408 
409 	return (HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll));
410 }
411 
412 long
413 HYPERVISOR_suspend(ulong_t start_info_mfn)
414 {
415 	struct sched_shutdown sched_shutdown;
416 
417 	sched_shutdown.reason = SHUTDOWN_suspend;
418 
419 	return (__hypercall3(__HYPERVISOR_sched_op, SCHEDOP_shutdown,
420 	    (ulong_t)&sched_shutdown, start_info_mfn));
421 }
422