xref: /illumos-gate/usr/src/uts/intel/io/vmm/intel/vmx_msr.c (revision 32640292)
1bf21cd93STycho Nightingale /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney  *
4bf21cd93STycho Nightingale  * Copyright (c) 2011 NetApp, Inc.
5bf21cd93STycho Nightingale  * All rights reserved.
6bf21cd93STycho Nightingale  *
7bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
8bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
9bf21cd93STycho Nightingale  * are met:
10bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
11bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
12bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
13bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
14bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
15bf21cd93STycho Nightingale  *
16bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26bf21cd93STycho Nightingale  * SUCH DAMAGE.
274c87aefeSPatrick Mooney  */
284c87aefeSPatrick Mooney /*
29c9b7e76bSJason King  * Copyright 2020 Joyent, Inc.
306b641d7aSPatrick Mooney  * Copyright 2021 Oxide Computer Company
31bf21cd93STycho Nightingale  */
32bf21cd93STycho Nightingale 
33bf21cd93STycho Nightingale #include <sys/cdefs.h>
34bf21cd93STycho Nightingale 
35bf21cd93STycho Nightingale #include <sys/param.h>
36bf21cd93STycho Nightingale #include <sys/systm.h>
374c87aefeSPatrick Mooney #include <sys/proc.h>
38bf21cd93STycho Nightingale 
39bf21cd93STycho Nightingale #include <machine/clock.h>
40bf21cd93STycho Nightingale #include <machine/cpufunc.h>
41bf21cd93STycho Nightingale #include <machine/md_var.h>
42bf21cd93STycho Nightingale #include <machine/specialreg.h>
43bf21cd93STycho Nightingale #include <machine/vmm.h>
44d2f938fdSPatrick Mooney #include <sys/vmm_kernel.h>
45bf21cd93STycho Nightingale 
46bf21cd93STycho Nightingale #include "vmx.h"
47bf21cd93STycho Nightingale #include "vmx_msr.h"
48bf21cd93STycho Nightingale 
4984659b24SMichael Zeller static bool
vmx_ctl_allows_one_setting(uint64_t msr_val,int bitpos)50bf21cd93STycho Nightingale vmx_ctl_allows_one_setting(uint64_t msr_val, int bitpos)
51bf21cd93STycho Nightingale {
52bf21cd93STycho Nightingale 
5384659b24SMichael Zeller 	return ((msr_val & (1UL << (bitpos + 32))) != 0);
54bf21cd93STycho Nightingale }
55bf21cd93STycho Nightingale 
5684659b24SMichael Zeller static bool
vmx_ctl_allows_zero_setting(uint64_t msr_val,int bitpos)57bf21cd93STycho Nightingale vmx_ctl_allows_zero_setting(uint64_t msr_val, int bitpos)
58bf21cd93STycho Nightingale {
59bf21cd93STycho Nightingale 
6084659b24SMichael Zeller 	return ((msr_val & (1UL << bitpos)) == 0);
61bf21cd93STycho Nightingale }
62bf21cd93STycho Nightingale 
63bf21cd93STycho Nightingale /*
64bf21cd93STycho Nightingale  * Generate a bitmask to be used for the VMCS execution control fields.
65bf21cd93STycho Nightingale  *
66bf21cd93STycho Nightingale  * The caller specifies what bits should be set to one in 'ones_mask'
67bf21cd93STycho Nightingale  * and what bits should be set to zero in 'zeros_mask'. The don't-care
68bf21cd93STycho Nightingale  * bits are set to the default value. The default values are obtained
69bf21cd93STycho Nightingale  * based on "Algorithm 3" in Section 27.5.1 "Algorithms for Determining
70bf21cd93STycho Nightingale  * VMX Capabilities".
71bf21cd93STycho Nightingale  *
72bf21cd93STycho Nightingale  * Returns zero on success and non-zero on error.
73bf21cd93STycho Nightingale  */
74bf21cd93STycho Nightingale int
vmx_set_ctlreg(int ctl_reg,int true_ctl_reg,uint32_t ones_mask,uint32_t zeros_mask,uint32_t * retval)75bf21cd93STycho Nightingale vmx_set_ctlreg(int ctl_reg, int true_ctl_reg, uint32_t ones_mask,
762699b94cSPatrick Mooney     uint32_t zeros_mask, uint32_t *retval)
77bf21cd93STycho Nightingale {
78bf21cd93STycho Nightingale 	int i;
79bf21cd93STycho Nightingale 	uint64_t val, trueval;
8084659b24SMichael Zeller 	bool true_ctls_avail, one_allowed, zero_allowed;
81bf21cd93STycho Nightingale 
82bf21cd93STycho Nightingale 	/* We cannot ask the same bit to be set to both '1' and '0' */
83bf21cd93STycho Nightingale 	if ((ones_mask ^ zeros_mask) != (ones_mask | zeros_mask))
84bf21cd93STycho Nightingale 		return (EINVAL);
85bf21cd93STycho Nightingale 
8684659b24SMichael Zeller 	true_ctls_avail = (rdmsr(MSR_VMX_BASIC) & (1UL << 55)) != 0;
87bf21cd93STycho Nightingale 
88bf21cd93STycho Nightingale 	val = rdmsr(ctl_reg);
89bf21cd93STycho Nightingale 	if (true_ctls_avail)
90bf21cd93STycho Nightingale 		trueval = rdmsr(true_ctl_reg);		/* step c */
91bf21cd93STycho Nightingale 	else
92bf21cd93STycho Nightingale 		trueval = val;				/* step a */
93bf21cd93STycho Nightingale 
94bf21cd93STycho Nightingale 	for (i = 0; i < 32; i++) {
95bf21cd93STycho Nightingale 		one_allowed = vmx_ctl_allows_one_setting(trueval, i);
96bf21cd93STycho Nightingale 		zero_allowed = vmx_ctl_allows_zero_setting(trueval, i);
97bf21cd93STycho Nightingale 
98bf21cd93STycho Nightingale 		KASSERT(one_allowed || zero_allowed,
992699b94cSPatrick Mooney 		    ("invalid zero/one setting for bit %d of ctl 0x%0x, "
1002699b94cSPatrick Mooney 		    "truectl 0x%0x\n", i, ctl_reg, true_ctl_reg));
101bf21cd93STycho Nightingale 
102bf21cd93STycho Nightingale 		if (zero_allowed && !one_allowed) {		/* b(i),c(i) */
103bf21cd93STycho Nightingale 			if (ones_mask & (1 << i))
104bf21cd93STycho Nightingale 				return (EINVAL);
105bf21cd93STycho Nightingale 			*retval &= ~(1 << i);
106bf21cd93STycho Nightingale 		} else if (one_allowed && !zero_allowed) {	/* b(i),c(i) */
107bf21cd93STycho Nightingale 			if (zeros_mask & (1 << i))
108bf21cd93STycho Nightingale 				return (EINVAL);
109bf21cd93STycho Nightingale 			*retval |= 1 << i;
110bf21cd93STycho Nightingale 		} else {
1112699b94cSPatrick Mooney 			if (zeros_mask & (1 << i)) {
1122699b94cSPatrick Mooney 				/* b(ii),c(ii) */
113bf21cd93STycho Nightingale 				*retval &= ~(1 << i);
1142699b94cSPatrick Mooney 			} else if (ones_mask & (1 << i)) {
1152699b94cSPatrick Mooney 				/* b(ii), c(ii) */
116bf21cd93STycho Nightingale 				*retval |= 1 << i;
1172699b94cSPatrick Mooney 			} else if (!true_ctls_avail) {
1182699b94cSPatrick Mooney 				/* b(iii) */
119bf21cd93STycho Nightingale 				*retval &= ~(1 << i);
1202699b94cSPatrick Mooney 			} else if (vmx_ctl_allows_zero_setting(val, i)) {
1212699b94cSPatrick Mooney 				/* c(iii) */
1222699b94cSPatrick Mooney 				*retval &= ~(1 << i);
1232699b94cSPatrick Mooney 			} else if (vmx_ctl_allows_one_setting(val, i)) {
1242699b94cSPatrick Mooney 				/* c(iv) */
125bf21cd93STycho Nightingale 				*retval |= 1 << i;
1262699b94cSPatrick Mooney 			} else {
127bf21cd93STycho Nightingale 				panic("vmx_set_ctlreg: unable to determine "
1282699b94cSPatrick Mooney 				    "correct value of ctl bit %d for msr "
1292699b94cSPatrick Mooney 				    "0x%0x and true msr 0x%0x", i, ctl_reg,
1302699b94cSPatrick Mooney 				    true_ctl_reg);
131bf21cd93STycho Nightingale 			}
132bf21cd93STycho Nightingale 		}
133bf21cd93STycho Nightingale 	}
134bf21cd93STycho Nightingale 
135bf21cd93STycho Nightingale 	return (0);
136bf21cd93STycho Nightingale }
137bf21cd93STycho Nightingale 
138bf21cd93STycho Nightingale void
vmx_msr_bitmap_initialize(struct vmx * vmx)1396b641d7aSPatrick Mooney vmx_msr_bitmap_initialize(struct vmx *vmx)
140bf21cd93STycho Nightingale {
1416b641d7aSPatrick Mooney 	for (uint_t i = 0; i < VM_MAXCPU; i++) {
1426b641d7aSPatrick Mooney 		uint8_t *bitmap;
143bf21cd93STycho Nightingale 
1446b641d7aSPatrick Mooney 		bitmap = kmem_alloc(PAGESIZE, KM_SLEEP);
1456b641d7aSPatrick Mooney 		VERIFY3U((uintptr_t)bitmap & PAGEOFFSET, ==, 0);
1466b641d7aSPatrick Mooney 		memset(bitmap, 0xff, PAGESIZE);
1476b641d7aSPatrick Mooney 
1486b641d7aSPatrick Mooney 		vmx->msr_bitmap[i] = bitmap;
1496b641d7aSPatrick Mooney 	}
150bf21cd93STycho Nightingale }
151bf21cd93STycho Nightingale 
1526b641d7aSPatrick Mooney void
vmx_msr_bitmap_destroy(struct vmx * vmx)1536b641d7aSPatrick Mooney vmx_msr_bitmap_destroy(struct vmx *vmx)
1546b641d7aSPatrick Mooney {
1556b641d7aSPatrick Mooney 	for (uint_t i = 0; i < VM_MAXCPU; i++) {
1566b641d7aSPatrick Mooney 		VERIFY3P(vmx->msr_bitmap[i], !=, NULL);
1576b641d7aSPatrick Mooney 		kmem_free(vmx->msr_bitmap[i], PAGESIZE);
1586b641d7aSPatrick Mooney 		vmx->msr_bitmap[i] = NULL;
1596b641d7aSPatrick Mooney 	}
1606b641d7aSPatrick Mooney }
1616b641d7aSPatrick Mooney 
1626b641d7aSPatrick Mooney void
vmx_msr_bitmap_change_access(struct vmx * vmx,int vcpuid,uint_t msr,int acc)1636b641d7aSPatrick Mooney vmx_msr_bitmap_change_access(struct vmx *vmx, int vcpuid, uint_t msr, int acc)
164bf21cd93STycho Nightingale {
1656b641d7aSPatrick Mooney 	uint8_t *bitmap = vmx->msr_bitmap[vcpuid];
166bf21cd93STycho Nightingale 	int byte, bit;
167bf21cd93STycho Nightingale 
1686b641d7aSPatrick Mooney 	if (msr <= 0x00001FFF) {
169bf21cd93STycho Nightingale 		byte = msr / 8;
1706b641d7aSPatrick Mooney 	} else if (msr >= 0xC0000000 && msr <= 0xC0001FFF) {
171bf21cd93STycho Nightingale 		byte = 1024 + (msr - 0xC0000000) / 8;
1726b641d7aSPatrick Mooney 	} else {
1736b641d7aSPatrick Mooney 		panic("Invalid MSR for bitmap: %x", msr);
1746b641d7aSPatrick Mooney 	}
175bf21cd93STycho Nightingale 
176bf21cd93STycho Nightingale 	bit = msr & 0x7;
177bf21cd93STycho Nightingale 
1786b641d7aSPatrick Mooney 	if (acc & MSR_BITMAP_ACCESS_READ) {
179bf21cd93STycho Nightingale 		bitmap[byte] &= ~(1 << bit);
1806b641d7aSPatrick Mooney 	} else {
181bf21cd93STycho Nightingale 		bitmap[byte] |= 1 << bit;
1826b641d7aSPatrick Mooney 	}
183bf21cd93STycho Nightingale 
184bf21cd93STycho Nightingale 	byte += 2048;
1856b641d7aSPatrick Mooney 	if (acc & MSR_BITMAP_ACCESS_WRITE) {
186bf21cd93STycho Nightingale 		bitmap[byte] &= ~(1 << bit);
1876b641d7aSPatrick Mooney 	} else {
188bf21cd93STycho Nightingale 		bitmap[byte] |= 1 << bit;
1896b641d7aSPatrick Mooney 	}
190bf21cd93STycho Nightingale }
191bf21cd93STycho Nightingale 
192bf21cd93STycho Nightingale static uint64_t misc_enable;
193bf21cd93STycho Nightingale static uint64_t platform_info;
194bf21cd93STycho Nightingale static uint64_t turbo_ratio_limit;
195bf21cd93STycho Nightingale 
196bf21cd93STycho Nightingale static bool
nehalem_cpu(void)197bf21cd93STycho Nightingale nehalem_cpu(void)
198bf21cd93STycho Nightingale {
1992699b94cSPatrick Mooney 	uint_t family, model;
200bf21cd93STycho Nightingale 
201bf21cd93STycho Nightingale 	/*
202bf21cd93STycho Nightingale 	 * The family:model numbers belonging to the Nehalem microarchitecture
203bf21cd93STycho Nightingale 	 * are documented in Section 35.5, Intel SDM dated Feb 2014.
204bf21cd93STycho Nightingale 	 */
205bf21cd93STycho Nightingale 	family = CPUID_TO_FAMILY(cpu_id);
206bf21cd93STycho Nightingale 	model = CPUID_TO_MODEL(cpu_id);
207bf21cd93STycho Nightingale 	if (family == 0x6) {
208bf21cd93STycho Nightingale 		switch (model) {
209bf21cd93STycho Nightingale 		case 0x1A:
210bf21cd93STycho Nightingale 		case 0x1E:
211bf21cd93STycho Nightingale 		case 0x1F:
212bf21cd93STycho Nightingale 		case 0x2E:
213bf21cd93STycho Nightingale 			return (true);
214bf21cd93STycho Nightingale 		default:
215bf21cd93STycho Nightingale 			break;
216bf21cd93STycho Nightingale 		}
217bf21cd93STycho Nightingale 	}
218bf21cd93STycho Nightingale 	return (false);
219bf21cd93STycho Nightingale }
220bf21cd93STycho Nightingale 
221bf21cd93STycho Nightingale static bool
westmere_cpu(void)222bf21cd93STycho Nightingale westmere_cpu(void)
223bf21cd93STycho Nightingale {
2242699b94cSPatrick Mooney 	uint_t family, model;
225bf21cd93STycho Nightingale 
226bf21cd93STycho Nightingale 	/*
227bf21cd93STycho Nightingale 	 * The family:model numbers belonging to the Westmere microarchitecture
228bf21cd93STycho Nightingale 	 * are documented in Section 35.6, Intel SDM dated Feb 2014.
229bf21cd93STycho Nightingale 	 */
230bf21cd93STycho Nightingale 	family = CPUID_TO_FAMILY(cpu_id);
231bf21cd93STycho Nightingale 	model = CPUID_TO_MODEL(cpu_id);
232bf21cd93STycho Nightingale 	if (family == 0x6) {
233bf21cd93STycho Nightingale 		switch (model) {
234bf21cd93STycho Nightingale 		case 0x25:
235bf21cd93STycho Nightingale 		case 0x2C:
236bf21cd93STycho Nightingale 			return (true);
237bf21cd93STycho Nightingale 		default:
238bf21cd93STycho Nightingale 			break;
239bf21cd93STycho Nightingale 		}
240bf21cd93STycho Nightingale 	}
241bf21cd93STycho Nightingale 	return (false);
242bf21cd93STycho Nightingale }
243bf21cd93STycho Nightingale 
2444c87aefeSPatrick Mooney static bool
pat_valid(uint64_t val)2454c87aefeSPatrick Mooney pat_valid(uint64_t val)
2464c87aefeSPatrick Mooney {
2474c87aefeSPatrick Mooney 	int i, pa;
2484c87aefeSPatrick Mooney 
2494c87aefeSPatrick Mooney 	/*
2504c87aefeSPatrick Mooney 	 * From Intel SDM: Table "Memory Types That Can Be Encoded With PAT"
2514c87aefeSPatrick Mooney 	 *
2524c87aefeSPatrick Mooney 	 * Extract PA0 through PA7 and validate that each one encodes a
2534c87aefeSPatrick Mooney 	 * valid memory type.
2544c87aefeSPatrick Mooney 	 */
2554c87aefeSPatrick Mooney 	for (i = 0; i < 8; i++) {
2564c87aefeSPatrick Mooney 		pa = (val >> (i * 8)) & 0xff;
2574c87aefeSPatrick Mooney 		if (pa == 2 || pa == 3 || pa >= 8)
2584c87aefeSPatrick Mooney 			return (false);
2594c87aefeSPatrick Mooney 	}
2604c87aefeSPatrick Mooney 	return (true);
2614c87aefeSPatrick Mooney }
2624c87aefeSPatrick Mooney 
263bf21cd93STycho Nightingale void
vmx_msr_init(void)264bf21cd93STycho Nightingale vmx_msr_init(void)
265bf21cd93STycho Nightingale {
266bf21cd93STycho Nightingale 	uint64_t bus_freq, ratio;
267bf21cd93STycho Nightingale 	int i;
268bf21cd93STycho Nightingale 
269bf21cd93STycho Nightingale 	/*
270bf21cd93STycho Nightingale 	 * Initialize emulated MSRs
271bf21cd93STycho Nightingale 	 */
272bf21cd93STycho Nightingale 	misc_enable = rdmsr(MSR_IA32_MISC_ENABLE);
273bf21cd93STycho Nightingale 	/*
274bf21cd93STycho Nightingale 	 * Set mandatory bits
275bf21cd93STycho Nightingale 	 *  11:   branch trace disabled
276bf21cd93STycho Nightingale 	 *  12:   PEBS unavailable
277bf21cd93STycho Nightingale 	 * Clear unsupported features
278bf21cd93STycho Nightingale 	 *  16:   SpeedStep enable
279bf21cd93STycho Nightingale 	 *  18:   enable MONITOR FSM
280bf21cd93STycho Nightingale 	 */
281bf21cd93STycho Nightingale 	misc_enable |= (1 << 12) | (1 << 11);
282bf21cd93STycho Nightingale 	misc_enable &= ~((1 << 18) | (1 << 16));
283bf21cd93STycho Nightingale 
284bf21cd93STycho Nightingale 	if (nehalem_cpu() || westmere_cpu())
285bf21cd93STycho Nightingale 		bus_freq = 133330000;		/* 133Mhz */
286bf21cd93STycho Nightingale 	else
287bf21cd93STycho Nightingale 		bus_freq = 100000000;		/* 100Mhz */
288bf21cd93STycho Nightingale 
289bf21cd93STycho Nightingale 	/*
290bf21cd93STycho Nightingale 	 * XXXtime
291bf21cd93STycho Nightingale 	 * The ratio should really be based on the virtual TSC frequency as
292bf21cd93STycho Nightingale 	 * opposed to the host TSC.
293bf21cd93STycho Nightingale 	 */
294bf21cd93STycho Nightingale 	ratio = (tsc_freq / bus_freq) & 0xff;
295bf21cd93STycho Nightingale 
296bf21cd93STycho Nightingale 	/*
297bf21cd93STycho Nightingale 	 * The register definition is based on the micro-architecture
298bf21cd93STycho Nightingale 	 * but the following bits are always the same:
299bf21cd93STycho Nightingale 	 * [15:8]  Maximum Non-Turbo Ratio
300bf21cd93STycho Nightingale 	 * [28]    Programmable Ratio Limit for Turbo Mode
301bf21cd93STycho Nightingale 	 * [29]    Programmable TDC-TDP Limit for Turbo Mode
302bf21cd93STycho Nightingale 	 * [47:40] Maximum Efficiency Ratio
303bf21cd93STycho Nightingale 	 *
304bf21cd93STycho Nightingale 	 * The other bits can be safely set to 0 on all
305bf21cd93STycho Nightingale 	 * micro-architectures up to Haswell.
306bf21cd93STycho Nightingale 	 */
307bf21cd93STycho Nightingale 	platform_info = (ratio << 8) | (ratio << 40);
308bf21cd93STycho Nightingale 
309bf21cd93STycho Nightingale 	/*
310bf21cd93STycho Nightingale 	 * The number of valid bits in the MSR_TURBO_RATIO_LIMITx register is
311bf21cd93STycho Nightingale 	 * dependent on the maximum cores per package supported by the micro-
312bf21cd93STycho Nightingale 	 * architecture. For e.g., Westmere supports 6 cores per package and
313bf21cd93STycho Nightingale 	 * uses the low 48 bits. Sandybridge support 8 cores per package and
314bf21cd93STycho Nightingale 	 * uses up all 64 bits.
315bf21cd93STycho Nightingale 	 *
316bf21cd93STycho Nightingale 	 * However, the unused bits are reserved so we pretend that all bits
317bf21cd93STycho Nightingale 	 * in this MSR are valid.
318bf21cd93STycho Nightingale 	 */
319bf21cd93STycho Nightingale 	for (i = 0; i < 8; i++)
320bf21cd93STycho Nightingale 		turbo_ratio_limit = (turbo_ratio_limit << 8) | ratio;
321bf21cd93STycho Nightingale }
322bf21cd93STycho Nightingale 
323bf21cd93STycho Nightingale void
vmx_msr_guest_init(struct vmx * vmx,int vcpuid)324bf21cd93STycho Nightingale vmx_msr_guest_init(struct vmx *vmx, int vcpuid)
325bf21cd93STycho Nightingale {
3266b641d7aSPatrick Mooney 	uint64_t *guest_msrs = vmx->guest_msrs[vcpuid];
3274c87aefeSPatrick Mooney 
3286b641d7aSPatrick Mooney 	/*
3296b641d7aSPatrick Mooney 	 * It is safe to allow direct access to MSR_GSBASE and
3306b641d7aSPatrick Mooney 	 * MSR_FSBASE.  The guest FSBASE and GSBASE are saved and
3316b641d7aSPatrick Mooney 	 * restored during vm-exit and vm-entry respectively. The host
3326b641d7aSPatrick Mooney 	 * FSBASE and GSBASE are always restored from the vmcs host
3336b641d7aSPatrick Mooney 	 * state area on vm-exit.
3346b641d7aSPatrick Mooney 	 *
3356b641d7aSPatrick Mooney 	 * The SYSENTER_CS/ESP/EIP MSRs are identical to FS/GSBASE in
3366b641d7aSPatrick Mooney 	 * how they are saved/restored so can be directly accessed by
3376b641d7aSPatrick Mooney 	 * the guest.
3386b641d7aSPatrick Mooney 	 *
3396b641d7aSPatrick Mooney 	 * MSR_EFER is saved and restored in the guest VMCS area on a VM
3406b641d7aSPatrick Mooney 	 * exit and entry respectively. It is also restored from the
3416b641d7aSPatrick Mooney 	 * host VMCS area on a VM exit.
3426b641d7aSPatrick Mooney 	 *
3436b641d7aSPatrick Mooney 	 * The TSC MSR is exposed read-only. Writes are disallowed as
3446b641d7aSPatrick Mooney 	 * that will impact the host TSC.  If the guest does a write the
3456b641d7aSPatrick Mooney 	 * "use TSC offsetting" execution control is enabled and the
3466b641d7aSPatrick Mooney 	 * difference between the host TSC and the guest TSC is written
3476b641d7aSPatrick Mooney 	 * into the TSC offset in the VMCS.
3486b641d7aSPatrick Mooney 	 */
3496b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_GSBASE);
3506b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_FSBASE);
3516b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_SYSENTER_CS_MSR);
3526b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_SYSENTER_ESP_MSR);
3536b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_SYSENTER_EIP_MSR);
3546b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_EFER);
3556b641d7aSPatrick Mooney 	guest_msr_ro(vmx, vcpuid, MSR_TSC);
3564c87aefeSPatrick Mooney 
357bf21cd93STycho Nightingale 	/*
3586b641d7aSPatrick Mooney 	 * The guest may have direct access to these MSRs as they are
3596b641d7aSPatrick Mooney 	 * saved/restored in vmx_msr_guest_enter() and vmx_msr_guest_exit().
360bf21cd93STycho Nightingale 	 */
3616b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_LSTAR);
3626b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_CSTAR);
3636b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_STAR);
3646b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_SF_MASK);
3656b641d7aSPatrick Mooney 	guest_msr_rw(vmx, vcpuid, MSR_KGSBASE);
3664c87aefeSPatrick Mooney 
3674c87aefeSPatrick Mooney 	/*
3684c87aefeSPatrick Mooney 	 * Initialize guest IA32_PAT MSR with default value after reset.
3694c87aefeSPatrick Mooney 	 */
3704c87aefeSPatrick Mooney 	guest_msrs[IDX_MSR_PAT] = PAT_VALUE(0, PAT_WRITE_BACK) |
3714c87aefeSPatrick Mooney 	    PAT_VALUE(1, PAT_WRITE_THROUGH)	|
3724c87aefeSPatrick Mooney 	    PAT_VALUE(2, PAT_UNCACHED)		|
3734c87aefeSPatrick Mooney 	    PAT_VALUE(3, PAT_UNCACHEABLE)	|
3744c87aefeSPatrick Mooney 	    PAT_VALUE(4, PAT_WRITE_BACK)	|
3754c87aefeSPatrick Mooney 	    PAT_VALUE(5, PAT_WRITE_THROUGH)	|
3764c87aefeSPatrick Mooney 	    PAT_VALUE(6, PAT_UNCACHED)		|
3774c87aefeSPatrick Mooney 	    PAT_VALUE(7, PAT_UNCACHEABLE);
378bf21cd93STycho Nightingale }
379bf21cd93STycho Nightingale 
380bf21cd93STycho Nightingale void
vmx_msr_guest_enter(struct vmx * vmx,int vcpuid)381bf21cd93STycho Nightingale vmx_msr_guest_enter(struct vmx *vmx, int vcpuid)
382bf21cd93STycho Nightingale {
383bf21cd93STycho Nightingale 	uint64_t *guest_msrs = vmx->guest_msrs[vcpuid];
3844c87aefeSPatrick Mooney 	uint64_t *host_msrs = vmx->host_msrs[vcpuid];
3854c87aefeSPatrick Mooney 
3864c87aefeSPatrick Mooney 	/* Save host MSRs */
3874c87aefeSPatrick Mooney 	host_msrs[IDX_MSR_LSTAR] = rdmsr(MSR_LSTAR);
3884c87aefeSPatrick Mooney 	host_msrs[IDX_MSR_CSTAR] = rdmsr(MSR_CSTAR);
3894c87aefeSPatrick Mooney 	host_msrs[IDX_MSR_STAR] = rdmsr(MSR_STAR);
3904c87aefeSPatrick Mooney 	host_msrs[IDX_MSR_SF_MASK] = rdmsr(MSR_SF_MASK);
3914c87aefeSPatrick Mooney 
3924c87aefeSPatrick Mooney 	/* Save host MSRs (in particular, KGSBASE) and restore guest MSRs */
393bf21cd93STycho Nightingale 	wrmsr(MSR_LSTAR, guest_msrs[IDX_MSR_LSTAR]);
394bf21cd93STycho Nightingale 	wrmsr(MSR_CSTAR, guest_msrs[IDX_MSR_CSTAR]);
395bf21cd93STycho Nightingale 	wrmsr(MSR_STAR, guest_msrs[IDX_MSR_STAR]);
396bf21cd93STycho Nightingale 	wrmsr(MSR_SF_MASK, guest_msrs[IDX_MSR_SF_MASK]);
397bf21cd93STycho Nightingale 	wrmsr(MSR_KGSBASE, guest_msrs[IDX_MSR_KGSBASE]);
398bf21cd93STycho Nightingale }
399bf21cd93STycho Nightingale 
400bf21cd93STycho Nightingale void
vmx_msr_guest_exit(struct vmx * vmx,int vcpuid)401bf21cd93STycho Nightingale vmx_msr_guest_exit(struct vmx *vmx, int vcpuid)
402bf21cd93STycho Nightingale {
403bf21cd93STycho Nightingale 	uint64_t *guest_msrs = vmx->guest_msrs[vcpuid];
4044c87aefeSPatrick Mooney 	uint64_t *host_msrs = vmx->host_msrs[vcpuid];
405bf21cd93STycho Nightingale 
406bf21cd93STycho Nightingale 	/* Save guest MSRs */
407bf21cd93STycho Nightingale 	guest_msrs[IDX_MSR_LSTAR] = rdmsr(MSR_LSTAR);
408bf21cd93STycho Nightingale 	guest_msrs[IDX_MSR_CSTAR] = rdmsr(MSR_CSTAR);
409bf21cd93STycho Nightingale 	guest_msrs[IDX_MSR_STAR] = rdmsr(MSR_STAR);
410bf21cd93STycho Nightingale 	guest_msrs[IDX_MSR_SF_MASK] = rdmsr(MSR_SF_MASK);
411bf21cd93STycho Nightingale 	guest_msrs[IDX_MSR_KGSBASE] = rdmsr(MSR_KGSBASE);
412bf21cd93STycho Nightingale 
413bf21cd93STycho Nightingale 	/* Restore host MSRs */
414bf21cd93STycho Nightingale 	wrmsr(MSR_LSTAR, host_msrs[IDX_MSR_LSTAR]);
415bf21cd93STycho Nightingale 	wrmsr(MSR_CSTAR, host_msrs[IDX_MSR_CSTAR]);
416bf21cd93STycho Nightingale 	wrmsr(MSR_STAR, host_msrs[IDX_MSR_STAR]);
417bf21cd93STycho Nightingale 	wrmsr(MSR_SF_MASK, host_msrs[IDX_MSR_SF_MASK]);
418bf21cd93STycho Nightingale 
419bf21cd93STycho Nightingale 	/* MSR_KGSBASE will be restored on the way back to userspace */
420bf21cd93STycho Nightingale }
421bf21cd93STycho Nightingale 
422d2f938fdSPatrick Mooney vm_msr_result_t
vmx_rdmsr(struct vmx * vmx,int vcpuid,uint32_t num,uint64_t * val)423d2f938fdSPatrick Mooney vmx_rdmsr(struct vmx *vmx, int vcpuid, uint32_t num, uint64_t *val)
424bf21cd93STycho Nightingale {
425d2f938fdSPatrick Mooney 	const uint64_t *guest_msrs = vmx->guest_msrs[vcpuid];
426bf21cd93STycho Nightingale 
427bf21cd93STycho Nightingale 	switch (num) {
428c9b7e76bSJason King 	case MSR_IA32_FEATURE_CONTROL:
429c9b7e76bSJason King 		/*
430c9b7e76bSJason King 		 * We currently don't support SGX support in guests, so
431c9b7e76bSJason King 		 * always report those features as disabled with the MSR
432c9b7e76bSJason King 		 * locked so the guest won't attempt to write to it.
433c9b7e76bSJason King 		 */
434c9b7e76bSJason King 		*val = IA32_FEATURE_CONTROL_LOCK;
435c9b7e76bSJason King 		break;
436bf21cd93STycho Nightingale 	case MSR_IA32_MISC_ENABLE:
437bf21cd93STycho Nightingale 		*val = misc_enable;
438bf21cd93STycho Nightingale 		break;
439bf21cd93STycho Nightingale 	case MSR_PLATFORM_INFO:
440bf21cd93STycho Nightingale 		*val = platform_info;
441bf21cd93STycho Nightingale 		break;
442bf21cd93STycho Nightingale 	case MSR_TURBO_RATIO_LIMIT:
443bf21cd93STycho Nightingale 	case MSR_TURBO_RATIO_LIMIT1:
444bf21cd93STycho Nightingale 		*val = turbo_ratio_limit;
445bf21cd93STycho Nightingale 		break;
4464c87aefeSPatrick Mooney 	case MSR_PAT:
4474c87aefeSPatrick Mooney 		*val = guest_msrs[IDX_MSR_PAT];
4484c87aefeSPatrick Mooney 		break;
449bf21cd93STycho Nightingale 	default:
450d2f938fdSPatrick Mooney 		return (VMR_UNHANLDED);
451bf21cd93STycho Nightingale 	}
452d2f938fdSPatrick Mooney 	return (VMR_OK);
453bf21cd93STycho Nightingale }
454bf21cd93STycho Nightingale 
455d2f938fdSPatrick Mooney vm_msr_result_t
vmx_wrmsr(struct vmx * vmx,int vcpuid,uint32_t num,uint64_t val)456d2f938fdSPatrick Mooney vmx_wrmsr(struct vmx *vmx, int vcpuid, uint32_t num, uint64_t val)
457bf21cd93STycho Nightingale {
458d2f938fdSPatrick Mooney 	uint64_t *guest_msrs = vmx->guest_msrs[vcpuid];
459bf21cd93STycho Nightingale 	uint64_t changed;
4604c87aefeSPatrick Mooney 
461bf21cd93STycho Nightingale 	switch (num) {
462bf21cd93STycho Nightingale 	case MSR_IA32_MISC_ENABLE:
463bf21cd93STycho Nightingale 		changed = val ^ misc_enable;
464bf21cd93STycho Nightingale 		/*
465bf21cd93STycho Nightingale 		 * If the host has disabled the NX feature then the guest
466bf21cd93STycho Nightingale 		 * also cannot use it. However, a Linux guest will try to
467bf21cd93STycho Nightingale 		 * enable the NX feature by writing to the MISC_ENABLE MSR.
468bf21cd93STycho Nightingale 		 *
469bf21cd93STycho Nightingale 		 * This can be safely ignored because the memory management
470bf21cd93STycho Nightingale 		 * code looks at CPUID.80000001H:EDX.NX to check if the
471bf21cd93STycho Nightingale 		 * functionality is actually enabled.
472bf21cd93STycho Nightingale 		 */
473bf21cd93STycho Nightingale 		changed &= ~(1UL << 34);
474bf21cd93STycho Nightingale 
475bf21cd93STycho Nightingale 		/*
476bf21cd93STycho Nightingale 		 * Punt to userspace if any other bits are being modified.
477bf21cd93STycho Nightingale 		 */
478d2f938fdSPatrick Mooney 		if (changed) {
479d2f938fdSPatrick Mooney 			return (VMR_UNHANLDED);
480d2f938fdSPatrick Mooney 		}
481bf21cd93STycho Nightingale 		break;
4824c87aefeSPatrick Mooney 	case MSR_PAT:
483d2f938fdSPatrick Mooney 		if (!pat_valid(val)) {
484d2f938fdSPatrick Mooney 			return (VMR_GP);
485d2f938fdSPatrick Mooney 		}
486d2f938fdSPatrick Mooney 		guest_msrs[IDX_MSR_PAT] = val;
4874c87aefeSPatrick Mooney 		break;
488bf21cd93STycho Nightingale 	default:
489d2f938fdSPatrick Mooney 		return (VMR_UNHANLDED);
490bf21cd93STycho Nightingale 	}
491bf21cd93STycho Nightingale 
492d2f938fdSPatrick Mooney 	return (VMR_OK);
493bf21cd93STycho Nightingale }
494