This is xnu-11215.1.10. See this file in:
/*
* Copyright (c) 2024 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _I386_X86_HYPERCALL_H_
#define _I386_X86_HYPERCALL_H_
#include <kern/hvg_hypercall.h>
#include <i386/cpuid.h>
/*
* Apple Hypercall Calling Convention (x64)
*
* Registers | Usage |
* --------------------------------------------------------
* %rax | In: hypercall code |
* | Out: if RFLAGS.CF = 0 (success) |
* | hypercall output[0] |
* | if RFLAGS.CF = 1 (error) |
* | hypercall error value |
* %rdi | In: 1st argument |
* | Out: hypercall output[1] |
* %rsi | In: 2nd argument |
* | Out: hypercall output[2] |
* %rdx | In: 3rd argument |
* | Out: hypercall output[3] |
* %rcx | In: 4th argument |
* | Out: hypercall output[4] |
* %r8 | In: 5th argument |
* | Out: hypercall output[5] |
* %r9 | In: 6th argument |
* | Out: hypercall output[6] |
*
* %rax is used by the caller to specify hypercall code. When a hypercall fails,
* the hypervisor stores errno in %rax. A successful hypercall returns the
* output of the call in %rax, %rdi, %rsi, %rdx, %rcx, %r8, and %r9.
*/
typedef struct hvg_hcall_output_regs {
uint64_t rax;
uint64_t rdi;
uint64_t rsi;
uint64_t rdx;
uint64_t rcx;
uint64_t r8;
uint64_t r9;
} hvg_hcall_output_regs_t;
/*
* To avoid collision with other hypercall interfaces (e.g., KVM) in the vmcall
* namespace, Apple hypercalls put "A" (0x41) in the top byte of %eax so that
* hypervisors can support multiple hypercall interfaces simultaneously and
* handle Apple hypercalls correctly for compatiblity.
*
* For example, KVM uses the same vmcall instruction and has call code 1 for
* KVM_HC_VAPIC_POLL_IRQ. When invoking an Apple hypercall with code 1, a
* hypervisor will not accidentially treat the Apple hypercall as a KVM call.
*/
#define HVG_HCALL_CODE(code) ('A' << 24 | (code & 0xFFFFFF))
/*
* Caller is responsible for checking the existence of Apple Hypercall
* before invoking Apple hypercalls.
*/
#if defined(MACH_KERNEL_PRIVATE)
#define HVG_HCALL_RETURN(rax) {\
__asm__ __volatile__ goto (\
"jnc 2f \n\t" \
"jmp %l0 \n\t" \
"2: \n\t" \
: /* no output */ \
: /* no input */ \
: /* no clobber */ \
: error);\
return HVG_HCALL_SUCCESS;\
error:\
return (hvg_hcall_return_t)rax;\
}
static 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)
{
__asm__ __volatile__ ("movq %12, %%r8 \n\t"
"movq %13, %%r9 \n\t"
"vmcall \n\t"
"movq %%r8, %5 \n\t"
"movq %%r9, %6 \n\t"
: "=a" (output->rax), /* %0: output[0] */
"=D" (output->rdi), /* %1: output[1] */
"=S" (output->rsi), /* %2: output[2] */
"=d" (output->rdx), /* %3: output[3] */
"=c" (output->rcx), /* %4: output[4] */
"=r" (output->r8), /* %5: output[5] */
"=r" (output->r9) /* %6: output[6] */
: "a" (HVG_HCALL_CODE(code)),/* %7: call code */
"D" (rdi), /* %8: arg[0] */
"S" (rsi), /* %9: arg[1] */
"d" (rdx), /* %10: arg[2] */
"c" (rcx), /* %11: arg[3] */
"r" (r8), /* %12: arg[4] */
"r" (r9) /* %13: arg[5] */
: "memory", "r8", "r9");
HVG_HCALL_RETURN(output->rax);
}
static inline hvg_hcall_return_t
hvg_hypercall0(const uint64_t code,
hvg_hcall_output_regs_t *output)
{
return hvg_hypercall6(code, 0, 0, 0, 0, 0, 0, output);
}
static inline hvg_hcall_return_t
hvg_hypercall1(const uint64_t code,
const uint64_t rdi,
hvg_hcall_output_regs_t *output)
{
return hvg_hypercall6(code, rdi, 0, 0, 0, 0, 0, output);
}
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)
{
return hvg_hypercall6(code, rdi, rsi, 0, 0, 0, 0, output);
}
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)
{
return hvg_hypercall6(code, rdi, rsi, rdx, 0, 0, 0, output);
}
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)
{
return hvg_hypercall6(code, rdi, rsi, rdx, rcx, 0, 0, output);
}
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)
{
return hvg_hypercall6(code, rdi, rsi, rdx, rcx, r8, 0, output);
}
static inline long
kvmcompat_hypercall2(unsigned long code, unsigned long a0, unsigned long a1)
{
long retval;
__asm__ __volatile__ (
"vmcall"
: "=a" (retval)
: "a" (code), "b" (a0), "c" (a1)
: "memory"
);
return retval;
}
#endif /* MACH_KERNEL_PRIVATE */
#endif /* _I386_X86_HYPERCALL_H_ */