/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2019 Joyent, Inc. * Copyright 2022 Oxide Computer Company */ #ifndef _SYS_HMA_H #define _SYS_HMA_H /* * Hypervisor Multiplexor API * * This provides a set of APIs that are usable by hypervisor implementations * that allows them to coexist and to make sure that they are all in a * consistent state. */ #include #ifdef __cplusplus extern "C" { #endif /* * Register a hypervisor with HMA. On success, a pointer to the opaque * registration token will be returned, indicating that proper host setup has * occurred for further hypervisor actions. */ typedef struct hma_reg hma_reg_t; extern hma_reg_t *hma_register(const char *); extern hma_reg_t *hma_register_exclusive(const char *); extern void hma_unregister(hma_reg_t *); /* * Allocate or free a VPID for use with VMX. * * This must not be performed by a hypervisor until it has successfully * registered via hma_register(). */ extern uint16_t hma_vmx_vpid_alloc(void); extern void hma_vmx_vpid_free(uint16_t); /* * On all active CPUs, perform a single-context INVEPT on the given EPTP. */ extern void hma_vmx_invept_allcpus(uintptr_t); struct hma_svm_asid { uint64_t hsa_gen; uint32_t hsa_asid; }; typedef struct hma_svm_asid hma_svm_asid_t; extern void hma_svm_asid_init(hma_svm_asid_t *); extern uint8_t hma_svm_asid_update(hma_svm_asid_t *, boolean_t, boolean_t); /* * FPU related management. These functions provide a set of APIs to manage the * FPU state and switch between host and guest management of this state. */ typedef struct hma_fpu hma_fpu_t; /* * Allocate and free FPU state management structures. */ extern hma_fpu_t *hma_fpu_alloc(int); extern void hma_fpu_free(hma_fpu_t *); /* * Resets the FPU to the standard x86 default state. This should be called after * allocation and whenever the guest needs to logically reset the state (when * the CPU is reset, etc.). If the system supports xsave, then the xbv state * will be set to have the x87 and SSE portions as valid and the rest will be * set to their initial states (regardless of whether or not they will be * advertised in the host). */ extern int hma_fpu_init(hma_fpu_t *); /* * Save the current host's FPU state and restore the guest's state in the FPU. * At this point, CR0.TS will not be set. The caller must not use the FPU in any * way before entering the guest. * * This should be used in normal operation before entering the guest. It should * also be used in a thread context operation when the thread is being scheduled * again. This interface has an implicit assumption that a given guest state * will be mapped to only one specific OS thread at any given time. * * This must be called with preemption disabled. */ extern void hma_fpu_start_guest(hma_fpu_t *); /* * Save the current guest's FPU state and restore the host's state in the FPU. * By the time the thread returns to userland, the FPU will be in a usable * state; however, the FPU will not be usable while inside the kernel (CR0.TS * will be set). * * This should be used in normal operation after leaving the guest and returning * to user land. It should also be used in a thread context operation when the * thread is being descheduled. Like the hma_fpu_start_guest() interface, this * interface has an implicit assumption that a given guest state will be mapped * to only a single OS thread at any given time. * * This must be called with preemption disabled. */ extern void hma_fpu_stop_guest(hma_fpu_t *); typedef enum { HFXR_OK = 0, HFXR_NO_SPACE, /* buffer is not large enough */ HFXR_BAD_ALIGN, /* buffer is not properly (64-byte) aligned */ HFXR_UNSUP_FMT, /* data using unsupported (compressed) format */ HFXR_UNSUP_FEAT, /* data has unsupported features set */ HFXR_INVALID_DATA, /* CPU determined xsave data is invalid */ } hma_fpu_xsave_result_t; /* * Get and set the contents of the FPU save area, formatted as XSAVE-style * information. If XSAVE is not supported by the host, the input and output * values will be translated to and from the FXSAVE format. Attempts to set * XSAVE values not supported by the host will result in an error. * * These functions cannot be called while the FPU is in use by the guest. It is * up to callers to guarantee this invariant. */ extern hma_fpu_xsave_result_t hma_fpu_get_xsave_state(const hma_fpu_t *, void *, size_t); extern hma_fpu_xsave_result_t hma_fpu_set_xsave_state(hma_fpu_t *, void *, size_t); typedef struct hma_xsave_state_desc { uint64_t hxsd_bit; uint32_t hxsd_size; uint32_t hxsd_off; } hma_xsave_state_desc_t; /* * Get a description of the data fields supported by the host via the XSAVE APIs * for getting/setting guest FPU data. See the function definition for more * detailed parameter usage. */ extern uint_t hma_fpu_describe_xsave_state(hma_xsave_state_desc_t *, uint_t, size_t *); /* * Get and set the contents of the FPU save area. This sets the fxsave style * information. In all cases when this is in use, if an XSAVE state is actually * used by the host, then this will end up zeroing all of the non-fxsave state * and it will reset the xbv to indicate that the legacy x87 and SSE portions * are valid. * * These functions cannot be called while the FPU is in use by the guest. It is * up to callers to guarantee this fact. */ extern void hma_fpu_get_fxsave_state(const hma_fpu_t *, struct fxsave_state *); extern int hma_fpu_set_fxsave_state(hma_fpu_t *, const struct fxsave_state *); /* Perform HMA initialization steps during boot-up. */ extern void hma_init(void); #ifdef __cplusplus } #endif #endif /* _SYS_HMA_H */