1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * vMTRR implementation 4 * 5 * Copyright (C) 2006 Qumranet, Inc. 6 * Copyright 2010 Red Hat, Inc. and/or its affiliates. 7 * Copyright(C) 2015 Intel Corporation. 8 * 9 * Authors: 10 * Yaniv Kamay <yaniv@qumranet.com> 11 * Avi Kivity <avi@qumranet.com> 12 * Marcelo Tosatti <mtosatti@redhat.com> 13 * Paolo Bonzini <pbonzini@redhat.com> 14 * Xiao Guangrong <guangrong.xiao@linux.intel.com> 15 */ 16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 17 18 #include <linux/kvm_host.h> 19 #include <asm/mtrr.h> 20 21 #include "cpuid.h" 22 #include "x86.h" 23 24 static u64 *find_mtrr(struct kvm_vcpu *vcpu, unsigned int msr) 25 { 26 int index; 27 28 switch (msr) { 29 case MTRRphysBase_MSR(0) ... MTRRphysMask_MSR(KVM_NR_VAR_MTRR - 1): 30 index = msr - MTRRphysBase_MSR(0); 31 return &vcpu->arch.mtrr_state.var[index]; 32 case MSR_MTRRfix64K_00000: 33 return &vcpu->arch.mtrr_state.fixed_64k; 34 case MSR_MTRRfix16K_80000: 35 case MSR_MTRRfix16K_A0000: 36 index = msr - MSR_MTRRfix16K_80000; 37 return &vcpu->arch.mtrr_state.fixed_16k[index]; 38 case MSR_MTRRfix4K_C0000: 39 case MSR_MTRRfix4K_C8000: 40 case MSR_MTRRfix4K_D0000: 41 case MSR_MTRRfix4K_D8000: 42 case MSR_MTRRfix4K_E0000: 43 case MSR_MTRRfix4K_E8000: 44 case MSR_MTRRfix4K_F0000: 45 case MSR_MTRRfix4K_F8000: 46 index = msr - MSR_MTRRfix4K_C0000; 47 return &vcpu->arch.mtrr_state.fixed_4k[index]; 48 case MSR_MTRRdefType: 49 return &vcpu->arch.mtrr_state.deftype; 50 default: 51 break; 52 } 53 return NULL; 54 } 55 56 static bool valid_mtrr_type(unsigned t) 57 { 58 return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */ 59 } 60 61 static bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data) 62 { 63 int i; 64 u64 mask; 65 66 if (msr == MSR_MTRRdefType) { 67 if (data & ~0xcff) 68 return false; 69 return valid_mtrr_type(data & 0xff); 70 } else if (msr >= MSR_MTRRfix64K_00000 && msr <= MSR_MTRRfix4K_F8000) { 71 for (i = 0; i < 8 ; i++) 72 if (!valid_mtrr_type((data >> (i * 8)) & 0xff)) 73 return false; 74 return true; 75 } 76 77 /* variable MTRRs */ 78 if (WARN_ON_ONCE(!(msr >= MTRRphysBase_MSR(0) && 79 msr <= MTRRphysMask_MSR(KVM_NR_VAR_MTRR - 1)))) 80 return false; 81 82 mask = kvm_vcpu_reserved_gpa_bits_raw(vcpu); 83 if ((msr & 1) == 0) { 84 /* MTRR base */ 85 if (!valid_mtrr_type(data & 0xff)) 86 return false; 87 mask |= 0xf00; 88 } else { 89 /* MTRR mask */ 90 mask |= 0x7ff; 91 } 92 93 return (data & mask) == 0; 94 } 95 96 int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data) 97 { 98 u64 *mtrr; 99 100 mtrr = find_mtrr(vcpu, msr); 101 if (!mtrr) 102 return 1; 103 104 if (!kvm_mtrr_valid(vcpu, msr, data)) 105 return 1; 106 107 *mtrr = data; 108 return 0; 109 } 110 111 int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 112 { 113 u64 *mtrr; 114 115 /* MSR_MTRRcap is a readonly MSR. */ 116 if (msr == MSR_MTRRcap) { 117 /* 118 * SMRR = 0 119 * WC = 1 120 * FIX = 1 121 * VCNT = KVM_NR_VAR_MTRR 122 */ 123 *pdata = 0x500 | KVM_NR_VAR_MTRR; 124 return 0; 125 } 126 127 mtrr = find_mtrr(vcpu, msr); 128 if (!mtrr) 129 return 1; 130 131 *pdata = *mtrr; 132 return 0; 133 } 134