]>
Commit | Line | Data |
---|---|---|
c3c9b80d A |
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_ */ |