1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
/*
* 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 <sys/fp.h>
#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 */
|