xref: /illumos-gate/usr/src/uts/intel/sys/vmm_data.h (revision 09ea9c53cd9ac02c506f68475d98e8f07b457ffc)
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 /* This file is dual-licensed; see usr/src/contrib/bhyve/LICENSE */
12 
13 /*
14  * Copyright 2025 Oxide Computer Company
15  */
16 
17 #ifndef _VMM_DATA_H_
18 #define	_VMM_DATA_H_
19 
20 /* VMM Data Classes */
21 #define	VDC_VERSION	1	/* Version information for each data class */
22 
23 /* Classes bearing per-CPU data */
24 #define	VDC_REGISTER	2	/* Registers (GPR, segment, etc) */
25 #define	VDC_MSR		3	/* Model-specific registers */
26 #define	VDC_FPU		4	/* FPU (and associated SIMD) */
27 #define	VDC_LAPIC	5	/* Local APIC */
28 #define	VDC_VMM_ARCH	6	/* Arch-specific VMM state (VMX/SVM) */
29 #define	VDC_PMU_AMD	14	/* PMU for AMD CPUs */
30 
31 /* Classes for system-wide devices */
32 #define	VDC_IOAPIC	7	/* bhyve IO-APIC */
33 #define	VDC_ATPIT	8	/* i8254 PIT */
34 #define	VDC_ATPIC	9	/* i8259 PIC */
35 #define	VDC_HPET	10	/* HPET */
36 #define	VDC_PM_TIMER	11	/* ACPI Power Management Timer */
37 #define	VDC_RTC		12	/* IBM PC Real Time Clock */
38 
39 #define	VDC_VMM_TIME	13	/* Time-related VMM data */
40 
41 /* Indicates top of VMM Data Class range, updated as classes are added */
42 #define	VDC_MAX		(VDC_PMU_AMD + 1)
43 
44 
45 /* VMM Data Identifiers */
46 
47 /*
48  * Generic field encoding for 64-bit (or smaller) data which are identified by a
49  * 32-bit (or smaller) name.
50  *
51  * Used by the following classes/version:
52  * - VDC_REGISTER v1: `vm_reg_name` identifiers
53  * - VDC_MSR v1: MSR identifiers
54  * - VDC_VMM_ARCH v1: Identifiers described below
55  */
56 struct vdi_field_entry_v1 {
57 	uint32_t	vfe_ident;
58 	uint32_t	_pad;
59 	uint64_t	vfe_value;
60 };
61 
62 /* VDC_VERSION */
63 struct vdi_version_entry_v1 {
64 	uint16_t	vve_class;
65 	uint16_t	vve_version;
66 	uint16_t	vve_len_expect;
67 	uint16_t	vve_len_per_item;
68 };
69 
70 /*
71  * VDC_FPU:
72  *
73  * Unimplemented for now.  Use VM_GET_FPU/VM_SET_FPU ioctls.
74  */
75 
76 /* VDC_LAPIC: */
77 
78 struct vdi_lapic_page_v1 {
79 	uint32_t	vlp_id;
80 	uint32_t	vlp_version;
81 	uint32_t	vlp_tpr;
82 	uint32_t	vlp_apr;
83 	uint32_t	vlp_ldr;
84 	uint32_t	vlp_dfr;
85 	uint32_t	vlp_svr;
86 	uint32_t	vlp_isr[8];
87 	uint32_t	vlp_tmr[8];
88 	uint32_t	vlp_irr[8];
89 	uint32_t	vlp_esr;
90 	uint32_t	vlp_lvt_cmci;
91 	uint64_t	vlp_icr;
92 	uint32_t	vlp_lvt_timer;
93 	uint32_t	vlp_lvt_thermal;
94 	uint32_t	vlp_lvt_pcint;
95 	uint32_t	vlp_lvt_lint0;
96 	uint32_t	vlp_lvt_lint1;
97 	uint32_t	vlp_lvt_error;
98 	uint32_t	vlp_icr_timer;
99 	uint32_t	vlp_dcr_timer;
100 };
101 
102 struct vdi_lapic_v1 {
103 	struct vdi_lapic_page_v1 vl_lapic;
104 	uint64_t		vl_msr_apicbase;
105 	int64_t			vl_timer_target;
106 	uint32_t		vl_esr_pending;
107 };
108 
109 /*
110  * VDC_VMM_ARCH:
111  */
112 
113 /* VDC_PMU_AMD: */
114 
115 struct vdi_pmu_amd_v1 {
116 	uint64_t	vpa_evtsel[6];
117 	uint64_t	vpa_ctr[6];
118 };
119 
120 /*
121  * Version 1 identifiers:
122  */
123 
124 /*
125  * VM-wide:
126  */
127 
128 /* Is the VM currently in the "paused" state? (0 or 1) */
129 #define	VAI_VM_IS_PAUSED	4
130 
131 /*
132  * per-vCPU:
133  *
134  * Note: While these are currently defined with values disjoint from those in
135  * the VM-wide category, it is not required that they be.  The VM-wide and
136  * per-vCPU identifiers are distinguished by vm_data_xfer`vdx_vcpuid.
137  */
138 
139 /* NMI pending injection for vCPU (0 or 1) */
140 #define	VAI_PEND_NMI		10
141 /* extint pending injection for vCPU (0 or 1) */
142 #define	VAI_PEND_EXTINT		11
143 /* HW exception pending injection for vCPU */
144 #define	VAI_PEND_EXCP		12
145 /* exception/interrupt pending injection for vCPU */
146 #define	VAI_PEND_INTINFO	13
147 
148 /* VDC_IOAPIC: */
149 
150 struct vdi_ioapic_v1 {
151 	uint64_t	vi_pin_reg[32];
152 	uint32_t	vi_pin_level[32];
153 	uint32_t	vi_id;
154 	uint32_t	vi_reg_sel;
155 };
156 
157 /* VDC_ATPIT: */
158 
159 struct vdi_atpit_channel_v1 {
160 	uint16_t	vac_initial;
161 	uint16_t	vac_reg_cr;
162 	uint16_t	vac_reg_ol;
163 	uint8_t		vac_reg_status;
164 	uint8_t		vac_mode;
165 	/*
166 	 * vac_status bits:
167 	 * - 0b00001 status latched
168 	 * - 0b00010 output latched
169 	 * - 0b00100 control register sel
170 	 * - 0b01000 output latch sel
171 	 * - 0b10000 free-running timer
172 	 */
173 	uint8_t		vac_status;
174 
175 	int64_t		vac_time_target;
176 };
177 
178 struct vdi_atpit_v1 {
179 	struct vdi_atpit_channel_v1 va_channel[3];
180 };
181 
182 /* VDC_ATPIC: */
183 
184 struct vdi_atpic_chip_v1 {
185 	uint8_t		vac_icw_state;
186 	/*
187 	 * vac_status bits:
188 	 * - 0b00000001 ready
189 	 * - 0b00000010 auto EOI
190 	 * - 0b00000100 poll
191 	 * - 0b00001000 rotate
192 	 * - 0b00010000 special full nested
193 	 * - 0b00100000 read isr next
194 	 * - 0b01000000 intr raised
195 	 * - 0b10000000 special mask mode
196 	 */
197 	uint8_t		vac_status;
198 	uint8_t		vac_reg_irr;
199 	uint8_t		vac_reg_isr;
200 	uint8_t		vac_reg_imr;
201 	uint8_t		vac_irq_base;
202 	uint8_t		vac_lowprio;
203 	uint8_t		vac_elc;
204 	uint32_t	vac_level[8];
205 };
206 
207 struct vdi_atpic_v1 {
208 	struct vdi_atpic_chip_v1 va_chip[2];
209 };
210 
211 /* VDC_HPET: */
212 
213 struct vdi_hpet_timer_v1 {
214 	uint64_t	vht_config;
215 	uint64_t	vht_msi;
216 	uint32_t	vht_comp_val;
217 	uint32_t	vht_comp_rate;
218 	int64_t		vht_time_target;
219 };
220 
221 struct vdi_hpet_v1 {
222 	uint64_t	vh_config;
223 	uint64_t	vh_isr;
224 	uint32_t	vh_count_base;
225 	int64_t		vh_time_base;
226 
227 	struct vdi_hpet_timer_v1	vh_timers[8];
228 };
229 
230 /* VDC_PM_TIMER: */
231 
232 struct vdi_pm_timer_v1 {
233 	int64_t		vpt_time_base;
234 	/*
235 	 * Since the PM-timer IO port registration can be set by a dedicated
236 	 * ioctl today, it is considered a read-only field in the vmm data
237 	 * interface and its contents will be ignored when writing state data to
238 	 * the timer.
239 	 */
240 	uint16_t	vpt_ioport;
241 };
242 
243 /* VDC_RTC: */
244 
245 struct vdi_rtc_v2 {
246 	int64_t		vr_base_clock;
247 	int64_t		vr_last_period;
248 	uint8_t		vr_content[128];
249 	uint8_t		vr_addr;
250 };
251 
252 /* VDC_VMM_TIME: */
253 
254 /*
255  * Interface for modifying time-related data of a guest, allowing the guest's
256  * TSC and device timers to continue working across inter-machine live
257  * migrations.
258  *
259  * Reads of this data will populate all fields, including:
260  * - current guest TSC (a calculated value)
261  * - guest TSC frequency
262  * - guest boot_time, which tracks the offset of the guest boot based on host
263  *   hrtime
264  * - current host hrtime and wall clock time (hrestime) at the time of read
265  *
266  * Callers writing this data may want to make adjustments to the guest TSC based
267  * on the time between read and write, such as in the case of a migration.
268  * For migrations between machines, the boot_hrtime must also be updated based
269  * on the hrtime of the target system. Callers should populate the host time
270  * fields for the host the write is performed on. These fields are used by the
271  * write interface to make additional adjustments to the guest fields to account
272  * for latency between the userspace adjustment and kernel receipt of those
273  * values.
274  */
275 struct vdi_time_info_v1 {
276 	/* guest-related fields */
277 	uint64_t	vt_guest_freq;	/* guest TSC frequency (hz) */
278 	uint64_t	vt_guest_tsc;	/* current guest TSC */
279 	int64_t		vt_boot_hrtime; /* guest boot_hrtime */
280 
281 	/* host time fields */
282 	int64_t		vt_hrtime;	/* host hrtime (ns) */
283 	uint64_t	vt_hres_sec;	/* host hrestime (sec) */
284 	uint64_t	vt_hres_ns;	/* host hrestime (ns) */
285 };
286 
287 #endif /* _VMM_DATA_H_ */
288