]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/x86_hypercall.h
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / i386 / x86_hypercall.h
1 /*
2 * Copyright (c) 2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #ifndef _I386_X86_HYPERCALL_H_
30 #define _I386_X86_HYPERCALL_H_
31
32 #if DEBUG || DEVELOPMENT
33
34
35 /*
36 * Apple Hypercall Calling Convention (x64)
37 *
38 * Registers | Usage |
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] |
57 *
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.
61 */
62
63 typedef struct hvg_hcall_output_regs {
64 uint64_t rax;
65 uint64_t rdi;
66 uint64_t rsi;
67 uint64_t rdx;
68 uint64_t rcx;
69 uint64_t r8;
70 uint64_t r9;
71 } hvg_hcall_output_regs_t;
72
73 /*
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.
78 *
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.
82 */
83
84 #define HVG_HCALL_CODE(code) ('A' << 24 | (code & 0xFFFFFF))
85
86
87 /*
88 * Caller is responsible for checking the existence of Apple Hypercall
89 * before invoking Apple hypercalls.
90 */
91
92 #define HVG_HCALL_RETURN(rax) {\
93 __asm__ __volatile__ goto (\
94 "jnc 2f \n\t" \
95 "jmp %l0 \n\t" \
96 "2: \n\t" \
97 : /* no output */ \
98 : /* no input */ \
99 : /* no clobber */ \
100 : error);\
101 return HVG_HCALL_SUCCESS;\
102 error:\
103 return (hvg_hcall_return_t)rax;\
104 }
105
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)
109 {
110 __asm__ __volatile__ ("movq %12, %%r8 \n\t"
111 "movq %13, %%r9 \n\t"
112 "vmcall \n\t"
113 "movq %%r8, %5 \n\t"
114 "movq %%r9, %6 \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);
131 }
132
133 static inline hvg_hcall_return_t
134 hvg_hypercall0(const uint64_t code,
135 hvg_hcall_output_regs_t *output)
136 {
137 return hvg_hypercall6(code, 0, 0, 0, 0, 0, 0, output);
138 }
139
140 static inline hvg_hcall_return_t
141 hvg_hypercall1(const uint64_t code,
142 const uint64_t rdi,
143 hvg_hcall_output_regs_t *output)
144 {
145 return hvg_hypercall6(code, rdi, 0, 0, 0, 0, 0, output);
146 }
147
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)
152 {
153 return hvg_hypercall6(code, rdi, rsi, 0, 0, 0, 0, output);
154 }
155
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)
160 {
161 return hvg_hypercall6(code, rdi, rsi, rdx, 0, 0, 0, output);
162 }
163
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)
168 {
169 return hvg_hypercall6(code, rdi, rsi, rdx, rcx, 0, 0, output);
170 }
171
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)
176 {
177 return hvg_hypercall6(code, rdi, rsi, rdx, rcx, r8, 0, output);
178 }
179
180 #endif /* DEBUG || DEVELOPMENT */
181
182 #endif /* _I386_X86_HYPERCALL_H_ */