xref: /xnu-8020.140.41/osfmk/i386/x86_hypercall.h (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
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 #include <kern/hvg_hypercall.h>
33 
34 /*
35  * Apple Hypercall Calling Convention (x64)
36  *
37  * Registers |                Usage                       |
38  * --------------------------------------------------------
39  *      %rax |    In:  hypercall code                     |
40  *           |    Out: if RFLAGS.CF = 0 (success)         |
41  *           |           hypercall output[0]              |
42  *           |         if RFLAGS.CF = 1 (error)           |
43  *           |           hypercall error value            |
44  *      %rdi |    In:  1st argument                       |
45  *           |    Out: hypercall output[1]                |
46  *      %rsi |    In:  2nd argument                       |
47  *           |    Out: hypercall output[2]                |
48  *      %rdx |    In:  3rd argument                       |
49  *           |    Out: hypercall output[3]                |
50  *      %rcx |    In:  4th argument                       |
51  *           |    Out: hypercall output[4]                |
52  *      %r8  |    In:  5th argument                       |
53  *           |    Out: hypercall output[5]                |
54  *      %r9  |    In:  6th argument                       |
55  *           |    Out: hypercall output[6]                |
56  *
57  * %rax is used by the caller to specify hypercall code. When a hypercall fails,
58  * the hypervisor stores errno in %rax. A successful hypercall returns the
59  * output of the call in %rax, %rdi, %rsi, %rdx, %rcx, %r8, and %r9.
60  */
61 
62 typedef struct hvg_hcall_output_regs {
63 	uint64_t   rax;
64 	uint64_t   rdi;
65 	uint64_t   rsi;
66 	uint64_t   rdx;
67 	uint64_t   rcx;
68 	uint64_t   r8;
69 	uint64_t   r9;
70 } hvg_hcall_output_regs_t;
71 
72 /*
73  * To avoid collision with other hypercall interfaces (e.g., KVM) in the vmcall
74  * namespace, Apple hypercalls put "A" (0x41) in the top byte of %eax so that
75  * hypervisors can support multiple hypercall interfaces simultaneously and
76  * handle Apple hypercalls correctly for compatiblity.
77  *
78  * For example, KVM uses the same vmcall instruction and has call code 1 for
79  * KVM_HC_VAPIC_POLL_IRQ. When invoking an Apple hypercall with code 1, a
80  * hypervisor will not accidentially treat the Apple hypercall as a KVM call.
81  */
82 
83 #define HVG_HCALL_CODE(code) ('A' << 24 | (code & 0xFFFFFF))
84 
85 
86 /*
87  * Caller is responsible for checking the existence of Apple Hypercall
88  * before invoking Apple hypercalls.
89  */
90 
91 #define HVG_HCALL_RETURN(rax) {\
92 	__asm__ __volatile__ goto (\
93 	                           "jnc 2f  \n\t" \
94 	                           "jmp %l0 \n\t" \
95 	                           "2:      \n\t" \
96 	                          : /* no output */ \
97 	                          : /* no input */  \
98 	                          : /* no clobber */ \
99 	                          : error);\
100 	return HVG_HCALL_SUCCESS;\
101 error:\
102 	return (hvg_hcall_return_t)rax;\
103 }
104 
105 static inline hvg_hcall_return_t
hvg_hypercall6(uint64_t code,uint64_t rdi,uint64_t rsi,uint64_t rdx,uint64_t rcx,uint64_t r8,uint64_t r9,hvg_hcall_output_regs_t * output)106 hvg_hypercall6(uint64_t code, uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9,
107     hvg_hcall_output_regs_t *output)
108 {
109 	__asm__ __volatile__ ("movq %12, %%r8  \n\t"
110                           "movq %13, %%r9  \n\t"
111                           "vmcall          \n\t"
112                           "movq %%r8, %5   \n\t"
113                           "movq %%r9, %6   \n\t"
114                         : "=a" (output->rax),         /* %0:  output[0] */
115                           "=D" (output->rdi),         /* %1:  output[1] */
116                           "=S" (output->rsi),         /* %2:  output[2] */
117                           "=d" (output->rdx),         /* %3:  output[3] */
118                           "=c" (output->rcx),         /* %4:  output[4] */
119                           "=r" (output->r8),          /* %5:  output[5] */
120                           "=r" (output->r9)           /* %6:  output[6] */
121                         : "a"  (HVG_HCALL_CODE(code)),/* %7:  call code */
122                           "D"  (rdi),                 /* %8:  arg[0]    */
123                           "S"  (rsi),                 /* %9:  arg[1]    */
124                           "d"  (rdx),                 /* %10: arg[2]    */
125                           "c"  (rcx),                 /* %11: arg[3]    */
126                           "r"  (r8),                  /* %12: arg[4]    */
127                           "r"  (r9)                   /* %13: arg[5]    */
128                         : "memory", "r8", "r9");
129 	HVG_HCALL_RETURN(output->rax);
130 }
131 
132 static inline hvg_hcall_return_t
hvg_hypercall0(const uint64_t code,hvg_hcall_output_regs_t * output)133 hvg_hypercall0(const uint64_t code,
134     hvg_hcall_output_regs_t *output)
135 {
136 	return hvg_hypercall6(code, 0, 0, 0, 0, 0, 0, output);
137 }
138 
139 static inline hvg_hcall_return_t
hvg_hypercall1(const uint64_t code,const uint64_t rdi,hvg_hcall_output_regs_t * output)140 hvg_hypercall1(const uint64_t code,
141     const uint64_t rdi,
142     hvg_hcall_output_regs_t *output)
143 {
144 	return hvg_hypercall6(code, rdi, 0, 0, 0, 0, 0, output);
145 }
146 
147 static inline hvg_hcall_return_t
hvg_hypercall2(const uint64_t code,const uint64_t rdi,const uint64_t rsi,hvg_hcall_output_regs_t * output)148 hvg_hypercall2(const uint64_t code,
149     const uint64_t rdi, const uint64_t rsi,
150     hvg_hcall_output_regs_t *output)
151 {
152 	return hvg_hypercall6(code, rdi, rsi, 0, 0, 0, 0, output);
153 }
154 
155 static inline hvg_hcall_return_t
hvg_hypercall3(const uint64_t code,const uint64_t rdi,const uint64_t rsi,const uint64_t rdx,hvg_hcall_output_regs_t * output)156 hvg_hypercall3(const uint64_t code,
157     const uint64_t rdi, const uint64_t rsi, const uint64_t rdx,
158     hvg_hcall_output_regs_t *output)
159 {
160 	return hvg_hypercall6(code, rdi, rsi, rdx, 0, 0, 0, output);
161 }
162 
163 static inline hvg_hcall_return_t
hvg_hypercall4(const uint64_t code,const uint64_t rdi,const uint64_t rsi,const uint64_t rdx,const uint64_t rcx,hvg_hcall_output_regs_t * output)164 hvg_hypercall4(const uint64_t code,
165     const uint64_t rdi, const uint64_t rsi, const uint64_t rdx, const uint64_t rcx,
166     hvg_hcall_output_regs_t *output)
167 {
168 	return hvg_hypercall6(code, rdi, rsi, rdx, rcx, 0, 0, output);
169 }
170 
171 static inline hvg_hcall_return_t
hvg_hypercall5(const uint64_t code,const uint64_t rdi,const uint64_t rsi,const uint64_t rdx,const uint64_t rcx,const uint64_t r8,hvg_hcall_output_regs_t * output)172 hvg_hypercall5(const uint64_t code,
173     const uint64_t rdi, const uint64_t rsi, const uint64_t rdx, const uint64_t rcx, const uint64_t r8,
174     hvg_hcall_output_regs_t *output)
175 {
176 	return hvg_hypercall6(code, rdi, rsi, rdx, rcx, r8, 0, output);
177 }
178 
179 #endif /* _I386_X86_HYPERCALL_H_ */
180