]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/x86_hypercall.h
2 * Copyright (c) 2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #ifndef _I386_X86_HYPERCALL_H_
30 #define _I386_X86_HYPERCALL_H_
32 #if DEBUG || DEVELOPMENT
36 * Apple Hypercall Calling Convention (x64)
39 * --------------------------------------------------------
40 * %rax | In: hypercall code |
41 * | Out: if RFLAGS.CF = 0 (success) |
42 * | hypercall output[0] |
43 * | if RFLAGS.CF = 1 (error) |
44 * | hypercall error value |
45 * %rdi | In: 1st argument |
46 * | Out: hypercall output[1] |
47 * %rsi | In: 2nd argument |
48 * | Out: hypercall output[2] |
49 * %rdx | In: 3rd argument |
50 * | Out: hypercall output[3] |
51 * %rcx | In: 4th argument |
52 * | Out: hypercall output[4] |
53 * %r8 | In: 5th argument |
54 * | Out: hypercall output[5] |
55 * %r9 | In: 6th argument |
56 * | Out: hypercall output[6] |
58 * %rax is used by the caller to specify hypercall code. When a hypercall fails,
59 * the hypervisor stores errno in %rax. A successful hypercall returns the
60 * output of the call in %rax, %rdi, %rsi, %rdx, %rcx, %r8, and %r9.
63 typedef struct hvg_hcall_output_regs
{
71 } hvg_hcall_output_regs_t
;
74 * To avoid collision with other hypercall interfaces (e.g., KVM) in the vmcall
75 * namespace, Apple hypercalls put "A" (0x41) in the top byte of %eax so that
76 * hypervisors can support multiple hypercall interfaces simultaneously and
77 * handle Apple hypercalls correctly for compatiblity.
79 * For example, KVM uses the same vmcall instruction and has call code 1 for
80 * KVM_HC_VAPIC_POLL_IRQ. When invoking an Apple hypercall with code 1, a
81 * hypervisor will not accidentially treat the Apple hypercall as a KVM call.
84 #define HVG_HCALL_CODE(code) ('A' << 24 | (code & 0xFFFFFF))
88 * Caller is responsible for checking the existence of Apple Hypercall
89 * before invoking Apple hypercalls.
92 #define HVG_HCALL_RETURN(rax) {\
93 __asm__ __volatile__ goto (\
101 return HVG_HCALL_SUCCESS;\
103 return (hvg_hcall_return_t)rax;\
106 static inline hvg_hcall_return_t
107 hvg_hypercall6(uint64_t code
, uint64_t rdi
, uint64_t rsi
, uint64_t rdx
, uint64_t rcx
, uint64_t r8
, uint64_t r9
,
108 hvg_hcall_output_regs_t
*output
)
110 __asm__
__volatile__ ("movq %12, %%r8 \n\t"
111 "movq %13, %%r9 \n\t"
115 : "=a" (output
->rax
), /* %0: output[0] */
116 "=D" (output
->rdi
), /* %1: output[1] */
117 "=S" (output
->rsi
), /* %2: output[2] */
118 "=d" (output
->rdx
), /* %3: output[3] */
119 "=c" (output
->rcx
), /* %4: output[4] */
120 "=r" (output
->r8
), /* %5: output[5] */
121 "=r" (output
->r9
) /* %6: output[6] */
122 : "a" (HVG_HCALL_CODE(code
)),/* %7: call code */
123 "D" (rdi
), /* %8: arg[0] */
124 "S" (rsi
), /* %9: arg[1] */
125 "d" (rdx
), /* %10: arg[2] */
126 "c" (rcx
), /* %11: arg[3] */
127 "r" (r8
), /* %12: arg[4] */
128 "r" (r9
) /* %13: arg[5] */
129 : "memory", "r8", "r9");
130 HVG_HCALL_RETURN(output
->rax
);
133 static inline hvg_hcall_return_t
134 hvg_hypercall0(const uint64_t code
,
135 hvg_hcall_output_regs_t
*output
)
137 return hvg_hypercall6(code
, 0, 0, 0, 0, 0, 0, output
);
140 static inline hvg_hcall_return_t
141 hvg_hypercall1(const uint64_t code
,
143 hvg_hcall_output_regs_t
*output
)
145 return hvg_hypercall6(code
, rdi
, 0, 0, 0, 0, 0, output
);
148 static inline hvg_hcall_return_t
149 hvg_hypercall2(const uint64_t code
,
150 const uint64_t rdi
, const uint64_t rsi
,
151 hvg_hcall_output_regs_t
*output
)
153 return hvg_hypercall6(code
, rdi
, rsi
, 0, 0, 0, 0, output
);
156 static inline hvg_hcall_return_t
157 hvg_hypercall3(const uint64_t code
,
158 const uint64_t rdi
, const uint64_t rsi
, const uint64_t rdx
,
159 hvg_hcall_output_regs_t
*output
)
161 return hvg_hypercall6(code
, rdi
, rsi
, rdx
, 0, 0, 0, output
);
164 static inline hvg_hcall_return_t
165 hvg_hypercall4(const uint64_t code
,
166 const uint64_t rdi
, const uint64_t rsi
, const uint64_t rdx
, const uint64_t rcx
,
167 hvg_hcall_output_regs_t
*output
)
169 return hvg_hypercall6(code
, rdi
, rsi
, rdx
, rcx
, 0, 0, output
);
172 static inline hvg_hcall_return_t
173 hvg_hypercall5(const uint64_t code
,
174 const uint64_t rdi
, const uint64_t rsi
, const uint64_t rdx
, const uint64_t rcx
, const uint64_t r8
,
175 hvg_hcall_output_regs_t
*output
)
177 return hvg_hypercall6(code
, rdi
, rsi
, rdx
, rcx
, r8
, 0, output
);
180 #endif /* DEBUG || DEVELOPMENT */
182 #endif /* _I386_X86_HYPERCALL_H_ */