1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019 Joyent, Inc. 14 * Copyright 2022 Oxide Computer Company 15 */ 16 17 #ifndef _SYS_HMA_H 18 #define _SYS_HMA_H 19 20 /* 21 * Hypervisor Multiplexor API 22 * 23 * This provides a set of APIs that are usable by hypervisor implementations 24 * that allows them to coexist and to make sure that they are all in a 25 * consistent state. 26 */ 27 28 #include <sys/fp.h> 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 35 /* 36 * Register a hypervisor with HMA. On success, a pointer to the opaque 37 * registration token will be returned, indicating that proper host setup has 38 * occurred for further hypervisor actions. 39 */ 40 typedef struct hma_reg hma_reg_t; 41 extern hma_reg_t *hma_register(const char *); 42 extern hma_reg_t *hma_register_exclusive(const char *); 43 extern void hma_unregister(hma_reg_t *); 44 45 /* 46 * Allocate or free a VPID for use with VMX. 47 * 48 * This must not be performed by a hypervisor until it has successfully 49 * registered via hma_register(). 50 */ 51 extern uint16_t hma_vmx_vpid_alloc(void); 52 extern void hma_vmx_vpid_free(uint16_t); 53 54 /* 55 * On all active CPUs, perform a single-context INVEPT on the given EPTP. 56 */ 57 extern void hma_vmx_invept_allcpus(uintptr_t); 58 59 struct hma_svm_asid { 60 uint64_t hsa_gen; 61 uint32_t hsa_asid; 62 }; 63 typedef struct hma_svm_asid hma_svm_asid_t; 64 65 extern void hma_svm_asid_init(hma_svm_asid_t *); 66 extern uint8_t hma_svm_asid_update(hma_svm_asid_t *, boolean_t, boolean_t); 67 68 /* 69 * FPU related management. These functions provide a set of APIs to manage the 70 * FPU state and switch between host and guest management of this state. 71 */ 72 73 typedef struct hma_fpu hma_fpu_t; 74 75 /* 76 * Allocate and free FPU state management structures. 77 */ 78 extern hma_fpu_t *hma_fpu_alloc(int); 79 extern void hma_fpu_free(hma_fpu_t *); 80 81 /* 82 * Resets the FPU to the standard x86 default state. This should be called after 83 * allocation and whenever the guest needs to logically reset the state (when 84 * the CPU is reset, etc.). If the system supports xsave, then the xbv state 85 * will be set to have the x87 and SSE portions as valid and the rest will be 86 * set to their initial states (regardless of whether or not they will be 87 * advertised in the host). 88 */ 89 extern int hma_fpu_init(hma_fpu_t *); 90 91 /* 92 * Save the current host's FPU state and restore the guest's state in the FPU. 93 * At this point, CR0.TS will not be set. The caller must not use the FPU in any 94 * way before entering the guest. 95 * 96 * This should be used in normal operation before entering the guest. It should 97 * also be used in a thread context operation when the thread is being scheduled 98 * again. This interface has an implicit assumption that a given guest state 99 * will be mapped to only one specific OS thread at any given time. 100 * 101 * This must be called with preemption disabled. 102 */ 103 extern void hma_fpu_start_guest(hma_fpu_t *); 104 105 /* 106 * Save the current guest's FPU state and restore the host's state in the FPU. 107 * By the time the thread returns to userland, the FPU will be in a usable 108 * state; however, the FPU will not be usable while inside the kernel (CR0.TS 109 * will be set). 110 * 111 * This should be used in normal operation after leaving the guest and returning 112 * to user land. It should also be used in a thread context operation when the 113 * thread is being descheduled. Like the hma_fpu_start_guest() interface, this 114 * interface has an implicit assumption that a given guest state will be mapped 115 * to only a single OS thread at any given time. 116 * 117 * This must be called with preemption disabled. 118 */ 119 extern void hma_fpu_stop_guest(hma_fpu_t *); 120 121 typedef enum { 122 HFXR_OK = 0, 123 HFXR_NO_SPACE, /* buffer is not large enough */ 124 HFXR_BAD_ALIGN, /* buffer is not properly (64-byte) aligned */ 125 HFXR_UNSUP_FMT, /* data using unsupported (compressed) format */ 126 HFXR_UNSUP_FEAT, /* data has unsupported features set */ 127 HFXR_INVALID_DATA, /* CPU determined xsave data is invalid */ 128 } hma_fpu_xsave_result_t; 129 130 /* 131 * Get and set the contents of the FPU save area, formatted as XSAVE-style 132 * information. If XSAVE is not supported by the host, the input and output 133 * values will be translated to and from the FXSAVE format. Attempts to set 134 * XSAVE values not supported by the host will result in an error. 135 * 136 * These functions cannot be called while the FPU is in use by the guest. It is 137 * up to callers to guarantee this invariant. 138 */ 139 extern hma_fpu_xsave_result_t hma_fpu_get_xsave_state(const hma_fpu_t *, void *, 140 size_t); 141 extern hma_fpu_xsave_result_t hma_fpu_set_xsave_state(hma_fpu_t *, void *, 142 size_t); 143 144 typedef struct hma_xsave_state_desc { 145 uint64_t hxsd_bit; 146 uint32_t hxsd_size; 147 uint32_t hxsd_off; 148 } hma_xsave_state_desc_t; 149 150 /* 151 * Get a description of the data fields supported by the host via the XSAVE APIs 152 * for getting/setting guest FPU data. See the function definition for more 153 * detailed parameter usage. 154 */ 155 extern uint_t hma_fpu_describe_xsave_state(hma_xsave_state_desc_t *, uint_t, 156 size_t *); 157 158 /* 159 * Get and set the contents of the FPU save area. This sets the fxsave style 160 * information. In all cases when this is in use, if an XSAVE state is actually 161 * used by the host, then this will end up zeroing all of the non-fxsave state 162 * and it will reset the xbv to indicate that the legacy x87 and SSE portions 163 * are valid. 164 * 165 * These functions cannot be called while the FPU is in use by the guest. It is 166 * up to callers to guarantee this fact. 167 */ 168 extern void hma_fpu_get_fxsave_state(const hma_fpu_t *, struct fxsave_state *); 169 extern int hma_fpu_set_fxsave_state(hma_fpu_t *, const struct fxsave_state *); 170 171 /* Perform HMA initialization steps during boot-up. */ 172 extern void hma_init(void); 173 174 #ifdef __cplusplus 175 } 176 #endif 177 178 #endif /* _SYS_HMA_H */ 179