1*ff53604bSXiao Guangrong /* 2*ff53604bSXiao Guangrong * vMTRR implementation 3*ff53604bSXiao Guangrong * 4*ff53604bSXiao Guangrong * Copyright (C) 2006 Qumranet, Inc. 5*ff53604bSXiao Guangrong * Copyright 2010 Red Hat, Inc. and/or its affiliates. 6*ff53604bSXiao Guangrong * Copyright(C) 2015 Intel Corporation. 7*ff53604bSXiao Guangrong * 8*ff53604bSXiao Guangrong * Authors: 9*ff53604bSXiao Guangrong * Yaniv Kamay <yaniv@qumranet.com> 10*ff53604bSXiao Guangrong * Avi Kivity <avi@qumranet.com> 11*ff53604bSXiao Guangrong * Marcelo Tosatti <mtosatti@redhat.com> 12*ff53604bSXiao Guangrong * Paolo Bonzini <pbonzini@redhat.com> 13*ff53604bSXiao Guangrong * Xiao Guangrong <guangrong.xiao@linux.intel.com> 14*ff53604bSXiao Guangrong * 15*ff53604bSXiao Guangrong * This work is licensed under the terms of the GNU GPL, version 2. See 16*ff53604bSXiao Guangrong * the COPYING file in the top-level directory. 17*ff53604bSXiao Guangrong */ 18*ff53604bSXiao Guangrong 19*ff53604bSXiao Guangrong #include <linux/kvm_host.h> 20*ff53604bSXiao Guangrong #include <asm/mtrr.h> 21*ff53604bSXiao Guangrong 22*ff53604bSXiao Guangrong #include "cpuid.h" 23*ff53604bSXiao Guangrong #include "mmu.h" 24*ff53604bSXiao Guangrong 25*ff53604bSXiao Guangrong static bool msr_mtrr_valid(unsigned msr) 26*ff53604bSXiao Guangrong { 27*ff53604bSXiao Guangrong switch (msr) { 28*ff53604bSXiao Guangrong case 0x200 ... 0x200 + 2 * KVM_NR_VAR_MTRR - 1: 29*ff53604bSXiao Guangrong case MSR_MTRRfix64K_00000: 30*ff53604bSXiao Guangrong case MSR_MTRRfix16K_80000: 31*ff53604bSXiao Guangrong case MSR_MTRRfix16K_A0000: 32*ff53604bSXiao Guangrong case MSR_MTRRfix4K_C0000: 33*ff53604bSXiao Guangrong case MSR_MTRRfix4K_C8000: 34*ff53604bSXiao Guangrong case MSR_MTRRfix4K_D0000: 35*ff53604bSXiao Guangrong case MSR_MTRRfix4K_D8000: 36*ff53604bSXiao Guangrong case MSR_MTRRfix4K_E0000: 37*ff53604bSXiao Guangrong case MSR_MTRRfix4K_E8000: 38*ff53604bSXiao Guangrong case MSR_MTRRfix4K_F0000: 39*ff53604bSXiao Guangrong case MSR_MTRRfix4K_F8000: 40*ff53604bSXiao Guangrong case MSR_MTRRdefType: 41*ff53604bSXiao Guangrong case MSR_IA32_CR_PAT: 42*ff53604bSXiao Guangrong return true; 43*ff53604bSXiao Guangrong case 0x2f8: 44*ff53604bSXiao Guangrong return true; 45*ff53604bSXiao Guangrong } 46*ff53604bSXiao Guangrong return false; 47*ff53604bSXiao Guangrong } 48*ff53604bSXiao Guangrong 49*ff53604bSXiao Guangrong static bool valid_pat_type(unsigned t) 50*ff53604bSXiao Guangrong { 51*ff53604bSXiao Guangrong return t < 8 && (1 << t) & 0xf3; /* 0, 1, 4, 5, 6, 7 */ 52*ff53604bSXiao Guangrong } 53*ff53604bSXiao Guangrong 54*ff53604bSXiao Guangrong static bool valid_mtrr_type(unsigned t) 55*ff53604bSXiao Guangrong { 56*ff53604bSXiao Guangrong return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */ 57*ff53604bSXiao Guangrong } 58*ff53604bSXiao Guangrong 59*ff53604bSXiao Guangrong bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data) 60*ff53604bSXiao Guangrong { 61*ff53604bSXiao Guangrong int i; 62*ff53604bSXiao Guangrong u64 mask; 63*ff53604bSXiao Guangrong 64*ff53604bSXiao Guangrong if (!msr_mtrr_valid(msr)) 65*ff53604bSXiao Guangrong return false; 66*ff53604bSXiao Guangrong 67*ff53604bSXiao Guangrong if (msr == MSR_IA32_CR_PAT) { 68*ff53604bSXiao Guangrong for (i = 0; i < 8; i++) 69*ff53604bSXiao Guangrong if (!valid_pat_type((data >> (i * 8)) & 0xff)) 70*ff53604bSXiao Guangrong return false; 71*ff53604bSXiao Guangrong return true; 72*ff53604bSXiao Guangrong } else if (msr == MSR_MTRRdefType) { 73*ff53604bSXiao Guangrong if (data & ~0xcff) 74*ff53604bSXiao Guangrong return false; 75*ff53604bSXiao Guangrong return valid_mtrr_type(data & 0xff); 76*ff53604bSXiao Guangrong } else if (msr >= MSR_MTRRfix64K_00000 && msr <= MSR_MTRRfix4K_F8000) { 77*ff53604bSXiao Guangrong for (i = 0; i < 8 ; i++) 78*ff53604bSXiao Guangrong if (!valid_mtrr_type((data >> (i * 8)) & 0xff)) 79*ff53604bSXiao Guangrong return false; 80*ff53604bSXiao Guangrong return true; 81*ff53604bSXiao Guangrong } 82*ff53604bSXiao Guangrong 83*ff53604bSXiao Guangrong /* variable MTRRs */ 84*ff53604bSXiao Guangrong WARN_ON(!(msr >= 0x200 && msr < 0x200 + 2 * KVM_NR_VAR_MTRR)); 85*ff53604bSXiao Guangrong 86*ff53604bSXiao Guangrong mask = (~0ULL) << cpuid_maxphyaddr(vcpu); 87*ff53604bSXiao Guangrong if ((msr & 1) == 0) { 88*ff53604bSXiao Guangrong /* MTRR base */ 89*ff53604bSXiao Guangrong if (!valid_mtrr_type(data & 0xff)) 90*ff53604bSXiao Guangrong return false; 91*ff53604bSXiao Guangrong mask |= 0xf00; 92*ff53604bSXiao Guangrong } else 93*ff53604bSXiao Guangrong /* MTRR mask */ 94*ff53604bSXiao Guangrong mask |= 0x7ff; 95*ff53604bSXiao Guangrong if (data & mask) { 96*ff53604bSXiao Guangrong kvm_inject_gp(vcpu, 0); 97*ff53604bSXiao Guangrong return false; 98*ff53604bSXiao Guangrong } 99*ff53604bSXiao Guangrong 100*ff53604bSXiao Guangrong return true; 101*ff53604bSXiao Guangrong } 102*ff53604bSXiao Guangrong EXPORT_SYMBOL_GPL(kvm_mtrr_valid); 103*ff53604bSXiao Guangrong 104*ff53604bSXiao Guangrong static void update_mtrr(struct kvm_vcpu *vcpu, u32 msr) 105*ff53604bSXiao Guangrong { 106*ff53604bSXiao Guangrong struct mtrr_state_type *mtrr_state = &vcpu->arch.mtrr_state; 107*ff53604bSXiao Guangrong unsigned char mtrr_enabled = mtrr_state->enabled; 108*ff53604bSXiao Guangrong gfn_t start, end, mask; 109*ff53604bSXiao Guangrong int index; 110*ff53604bSXiao Guangrong bool is_fixed = true; 111*ff53604bSXiao Guangrong 112*ff53604bSXiao Guangrong if (msr == MSR_IA32_CR_PAT || !tdp_enabled || 113*ff53604bSXiao Guangrong !kvm_arch_has_noncoherent_dma(vcpu->kvm)) 114*ff53604bSXiao Guangrong return; 115*ff53604bSXiao Guangrong 116*ff53604bSXiao Guangrong if (!(mtrr_enabled & 0x2) && msr != MSR_MTRRdefType) 117*ff53604bSXiao Guangrong return; 118*ff53604bSXiao Guangrong 119*ff53604bSXiao Guangrong switch (msr) { 120*ff53604bSXiao Guangrong case MSR_MTRRfix64K_00000: 121*ff53604bSXiao Guangrong start = 0x0; 122*ff53604bSXiao Guangrong end = 0x80000; 123*ff53604bSXiao Guangrong break; 124*ff53604bSXiao Guangrong case MSR_MTRRfix16K_80000: 125*ff53604bSXiao Guangrong start = 0x80000; 126*ff53604bSXiao Guangrong end = 0xa0000; 127*ff53604bSXiao Guangrong break; 128*ff53604bSXiao Guangrong case MSR_MTRRfix16K_A0000: 129*ff53604bSXiao Guangrong start = 0xa0000; 130*ff53604bSXiao Guangrong end = 0xc0000; 131*ff53604bSXiao Guangrong break; 132*ff53604bSXiao Guangrong case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000: 133*ff53604bSXiao Guangrong index = msr - MSR_MTRRfix4K_C0000; 134*ff53604bSXiao Guangrong start = 0xc0000 + index * (32 << 10); 135*ff53604bSXiao Guangrong end = start + (32 << 10); 136*ff53604bSXiao Guangrong break; 137*ff53604bSXiao Guangrong case MSR_MTRRdefType: 138*ff53604bSXiao Guangrong is_fixed = false; 139*ff53604bSXiao Guangrong start = 0x0; 140*ff53604bSXiao Guangrong end = ~0ULL; 141*ff53604bSXiao Guangrong break; 142*ff53604bSXiao Guangrong default: 143*ff53604bSXiao Guangrong /* variable range MTRRs. */ 144*ff53604bSXiao Guangrong is_fixed = false; 145*ff53604bSXiao Guangrong index = (msr - 0x200) / 2; 146*ff53604bSXiao Guangrong start = (((u64)mtrr_state->var_ranges[index].base_hi) << 32) + 147*ff53604bSXiao Guangrong (mtrr_state->var_ranges[index].base_lo & PAGE_MASK); 148*ff53604bSXiao Guangrong mask = (((u64)mtrr_state->var_ranges[index].mask_hi) << 32) + 149*ff53604bSXiao Guangrong (mtrr_state->var_ranges[index].mask_lo & PAGE_MASK); 150*ff53604bSXiao Guangrong mask |= ~0ULL << cpuid_maxphyaddr(vcpu); 151*ff53604bSXiao Guangrong 152*ff53604bSXiao Guangrong end = ((start & mask) | ~mask) + 1; 153*ff53604bSXiao Guangrong } 154*ff53604bSXiao Guangrong 155*ff53604bSXiao Guangrong if (is_fixed && !(mtrr_enabled & 0x1)) 156*ff53604bSXiao Guangrong return; 157*ff53604bSXiao Guangrong 158*ff53604bSXiao Guangrong kvm_zap_gfn_range(vcpu->kvm, gpa_to_gfn(start), gpa_to_gfn(end)); 159*ff53604bSXiao Guangrong } 160*ff53604bSXiao Guangrong 161*ff53604bSXiao Guangrong int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data) 162*ff53604bSXiao Guangrong { 163*ff53604bSXiao Guangrong u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges; 164*ff53604bSXiao Guangrong 165*ff53604bSXiao Guangrong if (!kvm_mtrr_valid(vcpu, msr, data)) 166*ff53604bSXiao Guangrong return 1; 167*ff53604bSXiao Guangrong 168*ff53604bSXiao Guangrong if (msr == MSR_MTRRdefType) { 169*ff53604bSXiao Guangrong vcpu->arch.mtrr_state.def_type = data; 170*ff53604bSXiao Guangrong vcpu->arch.mtrr_state.enabled = (data & 0xc00) >> 10; 171*ff53604bSXiao Guangrong } else if (msr == MSR_MTRRfix64K_00000) 172*ff53604bSXiao Guangrong p[0] = data; 173*ff53604bSXiao Guangrong else if (msr == MSR_MTRRfix16K_80000 || msr == MSR_MTRRfix16K_A0000) 174*ff53604bSXiao Guangrong p[1 + msr - MSR_MTRRfix16K_80000] = data; 175*ff53604bSXiao Guangrong else if (msr >= MSR_MTRRfix4K_C0000 && msr <= MSR_MTRRfix4K_F8000) 176*ff53604bSXiao Guangrong p[3 + msr - MSR_MTRRfix4K_C0000] = data; 177*ff53604bSXiao Guangrong else if (msr == MSR_IA32_CR_PAT) 178*ff53604bSXiao Guangrong vcpu->arch.pat = data; 179*ff53604bSXiao Guangrong else { /* Variable MTRRs */ 180*ff53604bSXiao Guangrong int idx, is_mtrr_mask; 181*ff53604bSXiao Guangrong u64 *pt; 182*ff53604bSXiao Guangrong 183*ff53604bSXiao Guangrong idx = (msr - 0x200) / 2; 184*ff53604bSXiao Guangrong is_mtrr_mask = msr - 0x200 - 2 * idx; 185*ff53604bSXiao Guangrong if (!is_mtrr_mask) 186*ff53604bSXiao Guangrong pt = 187*ff53604bSXiao Guangrong (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].base_lo; 188*ff53604bSXiao Guangrong else 189*ff53604bSXiao Guangrong pt = 190*ff53604bSXiao Guangrong (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].mask_lo; 191*ff53604bSXiao Guangrong *pt = data; 192*ff53604bSXiao Guangrong } 193*ff53604bSXiao Guangrong 194*ff53604bSXiao Guangrong update_mtrr(vcpu, msr); 195*ff53604bSXiao Guangrong return 0; 196*ff53604bSXiao Guangrong } 197*ff53604bSXiao Guangrong 198*ff53604bSXiao Guangrong int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 199*ff53604bSXiao Guangrong { 200*ff53604bSXiao Guangrong u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges; 201*ff53604bSXiao Guangrong 202*ff53604bSXiao Guangrong if (!msr_mtrr_valid(msr)) 203*ff53604bSXiao Guangrong return 1; 204*ff53604bSXiao Guangrong 205*ff53604bSXiao Guangrong if (msr == MSR_MTRRdefType) 206*ff53604bSXiao Guangrong *pdata = vcpu->arch.mtrr_state.def_type + 207*ff53604bSXiao Guangrong (vcpu->arch.mtrr_state.enabled << 10); 208*ff53604bSXiao Guangrong else if (msr == MSR_MTRRfix64K_00000) 209*ff53604bSXiao Guangrong *pdata = p[0]; 210*ff53604bSXiao Guangrong else if (msr == MSR_MTRRfix16K_80000 || msr == MSR_MTRRfix16K_A0000) 211*ff53604bSXiao Guangrong *pdata = p[1 + msr - MSR_MTRRfix16K_80000]; 212*ff53604bSXiao Guangrong else if (msr >= MSR_MTRRfix4K_C0000 && msr <= MSR_MTRRfix4K_F8000) 213*ff53604bSXiao Guangrong *pdata = p[3 + msr - MSR_MTRRfix4K_C0000]; 214*ff53604bSXiao Guangrong else if (msr == MSR_IA32_CR_PAT) 215*ff53604bSXiao Guangrong *pdata = vcpu->arch.pat; 216*ff53604bSXiao Guangrong else { /* Variable MTRRs */ 217*ff53604bSXiao Guangrong int idx, is_mtrr_mask; 218*ff53604bSXiao Guangrong u64 *pt; 219*ff53604bSXiao Guangrong 220*ff53604bSXiao Guangrong idx = (msr - 0x200) / 2; 221*ff53604bSXiao Guangrong is_mtrr_mask = msr - 0x200 - 2 * idx; 222*ff53604bSXiao Guangrong if (!is_mtrr_mask) 223*ff53604bSXiao Guangrong pt = 224*ff53604bSXiao Guangrong (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].base_lo; 225*ff53604bSXiao Guangrong else 226*ff53604bSXiao Guangrong pt = 227*ff53604bSXiao Guangrong (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].mask_lo; 228*ff53604bSXiao Guangrong *pdata = *pt; 229*ff53604bSXiao Guangrong } 230*ff53604bSXiao Guangrong 231*ff53604bSXiao Guangrong return 0; 232*ff53604bSXiao Guangrong } 233*ff53604bSXiao Guangrong 234*ff53604bSXiao Guangrong /* 235*ff53604bSXiao Guangrong * The function is based on mtrr_type_lookup() in 236*ff53604bSXiao Guangrong * arch/x86/kernel/cpu/mtrr/generic.c 237*ff53604bSXiao Guangrong */ 238*ff53604bSXiao Guangrong static int get_mtrr_type(struct mtrr_state_type *mtrr_state, 239*ff53604bSXiao Guangrong u64 start, u64 end) 240*ff53604bSXiao Guangrong { 241*ff53604bSXiao Guangrong u64 base, mask; 242*ff53604bSXiao Guangrong u8 prev_match, curr_match; 243*ff53604bSXiao Guangrong int i, num_var_ranges = KVM_NR_VAR_MTRR; 244*ff53604bSXiao Guangrong 245*ff53604bSXiao Guangrong /* MTRR is completely disabled, use UC for all of physical memory. */ 246*ff53604bSXiao Guangrong if (!(mtrr_state->enabled & 0x2)) 247*ff53604bSXiao Guangrong return MTRR_TYPE_UNCACHABLE; 248*ff53604bSXiao Guangrong 249*ff53604bSXiao Guangrong /* Make end inclusive end, instead of exclusive */ 250*ff53604bSXiao Guangrong end--; 251*ff53604bSXiao Guangrong 252*ff53604bSXiao Guangrong /* Look in fixed ranges. Just return the type as per start */ 253*ff53604bSXiao Guangrong if (mtrr_state->have_fixed && (mtrr_state->enabled & 0x1) && 254*ff53604bSXiao Guangrong (start < 0x100000)) { 255*ff53604bSXiao Guangrong int idx; 256*ff53604bSXiao Guangrong 257*ff53604bSXiao Guangrong if (start < 0x80000) { 258*ff53604bSXiao Guangrong idx = 0; 259*ff53604bSXiao Guangrong idx += (start >> 16); 260*ff53604bSXiao Guangrong return mtrr_state->fixed_ranges[idx]; 261*ff53604bSXiao Guangrong } else if (start < 0xC0000) { 262*ff53604bSXiao Guangrong idx = 1 * 8; 263*ff53604bSXiao Guangrong idx += ((start - 0x80000) >> 14); 264*ff53604bSXiao Guangrong return mtrr_state->fixed_ranges[idx]; 265*ff53604bSXiao Guangrong } else if (start < 0x1000000) { 266*ff53604bSXiao Guangrong idx = 3 * 8; 267*ff53604bSXiao Guangrong idx += ((start - 0xC0000) >> 12); 268*ff53604bSXiao Guangrong return mtrr_state->fixed_ranges[idx]; 269*ff53604bSXiao Guangrong } 270*ff53604bSXiao Guangrong } 271*ff53604bSXiao Guangrong 272*ff53604bSXiao Guangrong /* 273*ff53604bSXiao Guangrong * Look in variable ranges 274*ff53604bSXiao Guangrong * Look of multiple ranges matching this address and pick type 275*ff53604bSXiao Guangrong * as per MTRR precedence 276*ff53604bSXiao Guangrong */ 277*ff53604bSXiao Guangrong prev_match = 0xFF; 278*ff53604bSXiao Guangrong for (i = 0; i < num_var_ranges; ++i) { 279*ff53604bSXiao Guangrong unsigned short start_state, end_state; 280*ff53604bSXiao Guangrong 281*ff53604bSXiao Guangrong if (!(mtrr_state->var_ranges[i].mask_lo & (1 << 11))) 282*ff53604bSXiao Guangrong continue; 283*ff53604bSXiao Guangrong 284*ff53604bSXiao Guangrong base = (((u64)mtrr_state->var_ranges[i].base_hi) << 32) + 285*ff53604bSXiao Guangrong (mtrr_state->var_ranges[i].base_lo & PAGE_MASK); 286*ff53604bSXiao Guangrong mask = (((u64)mtrr_state->var_ranges[i].mask_hi) << 32) + 287*ff53604bSXiao Guangrong (mtrr_state->var_ranges[i].mask_lo & PAGE_MASK); 288*ff53604bSXiao Guangrong 289*ff53604bSXiao Guangrong start_state = ((start & mask) == (base & mask)); 290*ff53604bSXiao Guangrong end_state = ((end & mask) == (base & mask)); 291*ff53604bSXiao Guangrong if (start_state != end_state) 292*ff53604bSXiao Guangrong return 0xFE; 293*ff53604bSXiao Guangrong 294*ff53604bSXiao Guangrong if ((start & mask) != (base & mask)) 295*ff53604bSXiao Guangrong continue; 296*ff53604bSXiao Guangrong 297*ff53604bSXiao Guangrong curr_match = mtrr_state->var_ranges[i].base_lo & 0xff; 298*ff53604bSXiao Guangrong if (prev_match == 0xFF) { 299*ff53604bSXiao Guangrong prev_match = curr_match; 300*ff53604bSXiao Guangrong continue; 301*ff53604bSXiao Guangrong } 302*ff53604bSXiao Guangrong 303*ff53604bSXiao Guangrong if (prev_match == MTRR_TYPE_UNCACHABLE || 304*ff53604bSXiao Guangrong curr_match == MTRR_TYPE_UNCACHABLE) 305*ff53604bSXiao Guangrong return MTRR_TYPE_UNCACHABLE; 306*ff53604bSXiao Guangrong 307*ff53604bSXiao Guangrong if ((prev_match == MTRR_TYPE_WRBACK && 308*ff53604bSXiao Guangrong curr_match == MTRR_TYPE_WRTHROUGH) || 309*ff53604bSXiao Guangrong (prev_match == MTRR_TYPE_WRTHROUGH && 310*ff53604bSXiao Guangrong curr_match == MTRR_TYPE_WRBACK)) { 311*ff53604bSXiao Guangrong prev_match = MTRR_TYPE_WRTHROUGH; 312*ff53604bSXiao Guangrong curr_match = MTRR_TYPE_WRTHROUGH; 313*ff53604bSXiao Guangrong } 314*ff53604bSXiao Guangrong 315*ff53604bSXiao Guangrong if (prev_match != curr_match) 316*ff53604bSXiao Guangrong return MTRR_TYPE_UNCACHABLE; 317*ff53604bSXiao Guangrong } 318*ff53604bSXiao Guangrong 319*ff53604bSXiao Guangrong if (prev_match != 0xFF) 320*ff53604bSXiao Guangrong return prev_match; 321*ff53604bSXiao Guangrong 322*ff53604bSXiao Guangrong return mtrr_state->def_type; 323*ff53604bSXiao Guangrong } 324*ff53604bSXiao Guangrong 325*ff53604bSXiao Guangrong u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn) 326*ff53604bSXiao Guangrong { 327*ff53604bSXiao Guangrong u8 mtrr; 328*ff53604bSXiao Guangrong 329*ff53604bSXiao Guangrong mtrr = get_mtrr_type(&vcpu->arch.mtrr_state, gfn << PAGE_SHIFT, 330*ff53604bSXiao Guangrong (gfn << PAGE_SHIFT) + PAGE_SIZE); 331*ff53604bSXiao Guangrong if (mtrr == 0xfe || mtrr == 0xff) 332*ff53604bSXiao Guangrong mtrr = MTRR_TYPE_WRBACK; 333*ff53604bSXiao Guangrong return mtrr; 334*ff53604bSXiao Guangrong } 335*ff53604bSXiao Guangrong EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type); 336