xref: /illumos-gate/usr/src/uts/intel/sys/hma.h (revision e98897e3ff64095f1d7afa3f16c8c3dcbd805e3e)
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