vmx_msr.c revision 270159
1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: stable/10/sys/amd64/vmm/intel/vmx_msr.c 270159 2014-08-19 01:20:24Z grehan $ 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/intel/vmx_msr.c 270159 2014-08-19 01:20:24Z grehan $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34 35#include <machine/cpufunc.h> 36#include <machine/specialreg.h> 37 38#include "vmx_msr.h" 39 40static boolean_t 41vmx_ctl_allows_one_setting(uint64_t msr_val, int bitpos) 42{ 43 44 if (msr_val & (1UL << (bitpos + 32))) 45 return (TRUE); 46 else 47 return (FALSE); 48} 49 50static boolean_t 51vmx_ctl_allows_zero_setting(uint64_t msr_val, int bitpos) 52{ 53 54 if ((msr_val & (1UL << bitpos)) == 0) 55 return (TRUE); 56 else 57 return (FALSE); 58} 59 60uint32_t 61vmx_revision(void) 62{ 63 64 return (rdmsr(MSR_VMX_BASIC) & 0xffffffff); 65} 66 67/* 68 * Generate a bitmask to be used for the VMCS execution control fields. 69 * 70 * The caller specifies what bits should be set to one in 'ones_mask' 71 * and what bits should be set to zero in 'zeros_mask'. The don't-care 72 * bits are set to the default value. The default values are obtained 73 * based on "Algorithm 3" in Section 27.5.1 "Algorithms for Determining 74 * VMX Capabilities". 75 * 76 * Returns zero on success and non-zero on error. 77 */ 78int 79vmx_set_ctlreg(int ctl_reg, int true_ctl_reg, uint32_t ones_mask, 80 uint32_t zeros_mask, uint32_t *retval) 81{ 82 int i; 83 uint64_t val, trueval; 84 boolean_t true_ctls_avail, one_allowed, zero_allowed; 85 86 /* We cannot ask the same bit to be set to both '1' and '0' */ 87 if ((ones_mask ^ zeros_mask) != (ones_mask | zeros_mask)) 88 return (EINVAL); 89 90 if (rdmsr(MSR_VMX_BASIC) & (1UL << 55)) 91 true_ctls_avail = TRUE; 92 else 93 true_ctls_avail = FALSE; 94 95 val = rdmsr(ctl_reg); 96 if (true_ctls_avail) 97 trueval = rdmsr(true_ctl_reg); /* step c */ 98 else 99 trueval = val; /* step a */ 100 101 for (i = 0; i < 32; i++) { 102 one_allowed = vmx_ctl_allows_one_setting(trueval, i); 103 zero_allowed = vmx_ctl_allows_zero_setting(trueval, i); 104 105 KASSERT(one_allowed || zero_allowed, 106 ("invalid zero/one setting for bit %d of ctl 0x%0x, " 107 "truectl 0x%0x\n", i, ctl_reg, true_ctl_reg)); 108 109 if (zero_allowed && !one_allowed) { /* b(i),c(i) */ 110 if (ones_mask & (1 << i)) 111 return (EINVAL); 112 *retval &= ~(1 << i); 113 } else if (one_allowed && !zero_allowed) { /* b(i),c(i) */ 114 if (zeros_mask & (1 << i)) 115 return (EINVAL); 116 *retval |= 1 << i; 117 } else { 118 if (zeros_mask & (1 << i)) /* b(ii),c(ii) */ 119 *retval &= ~(1 << i); 120 else if (ones_mask & (1 << i)) /* b(ii), c(ii) */ 121 *retval |= 1 << i; 122 else if (!true_ctls_avail) 123 *retval &= ~(1 << i); /* b(iii) */ 124 else if (vmx_ctl_allows_zero_setting(val, i))/* c(iii)*/ 125 *retval &= ~(1 << i); 126 else if (vmx_ctl_allows_one_setting(val, i)) /* c(iv) */ 127 *retval |= 1 << i; 128 else { 129 panic("vmx_set_ctlreg: unable to determine " 130 "correct value of ctl bit %d for msr " 131 "0x%0x and true msr 0x%0x", i, ctl_reg, 132 true_ctl_reg); 133 } 134 } 135 } 136 137 return (0); 138} 139 140void 141msr_bitmap_initialize(char *bitmap) 142{ 143 144 memset(bitmap, 0xff, PAGE_SIZE); 145} 146 147int 148msr_bitmap_change_access(char *bitmap, u_int msr, int access) 149{ 150 int byte, bit; 151 152 if (msr <= 0x00001FFF) 153 byte = msr / 8; 154 else if (msr >= 0xC0000000 && msr <= 0xC0001FFF) 155 byte = 1024 + (msr - 0xC0000000) / 8; 156 else 157 return (EINVAL); 158 159 bit = msr & 0x7; 160 161 if (access & MSR_BITMAP_ACCESS_READ) 162 bitmap[byte] &= ~(1 << bit); 163 else 164 bitmap[byte] |= 1 << bit; 165 166 byte += 2048; 167 if (access & MSR_BITMAP_ACCESS_WRITE) 168 bitmap[byte] &= ~(1 << bit); 169 else 170 bitmap[byte] |= 1 << bit; 171 172 return (0); 173} 174