123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731 |
- /*
- * vMTRR implementation
- *
- * Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affiliates.
- * Copyright(C) 2015 Intel Corporation.
- *
- * Authors:
- * Yaniv Kamay <yaniv@qumranet.com>
- * Avi Kivity <avi@qumranet.com>
- * Marcelo Tosatti <mtosatti@redhat.com>
- * Paolo Bonzini <pbonzini@redhat.com>
- * Xiao Guangrong <guangrong.xiao@linux.intel.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
- #include <linux/kvm_host.h>
- #include <asm/mtrr.h>
- #include "cpuid.h"
- #include "mmu.h"
- #define IA32_MTRR_DEF_TYPE_E (1ULL << 11)
- #define IA32_MTRR_DEF_TYPE_FE (1ULL << 10)
- #define IA32_MTRR_DEF_TYPE_TYPE_MASK (0xff)
- static bool msr_mtrr_valid(unsigned msr)
- {
- switch (msr) {
- case 0x200 ... 0x200 + 2 * KVM_NR_VAR_MTRR - 1:
- case MSR_MTRRfix64K_00000:
- case MSR_MTRRfix16K_80000:
- case MSR_MTRRfix16K_A0000:
- case MSR_MTRRfix4K_C0000:
- case MSR_MTRRfix4K_C8000:
- case MSR_MTRRfix4K_D0000:
- case MSR_MTRRfix4K_D8000:
- case MSR_MTRRfix4K_E0000:
- case MSR_MTRRfix4K_E8000:
- case MSR_MTRRfix4K_F0000:
- case MSR_MTRRfix4K_F8000:
- case MSR_MTRRdefType:
- case MSR_IA32_CR_PAT:
- return true;
- }
- return false;
- }
- static bool valid_pat_type(unsigned t)
- {
- return t < 8 && (1 << t) & 0xf3; /* 0, 1, 4, 5, 6, 7 */
- }
- static bool valid_mtrr_type(unsigned t)
- {
- return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */
- }
- bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
- {
- int i;
- u64 mask;
- if (!msr_mtrr_valid(msr))
- return false;
- if (msr == MSR_IA32_CR_PAT) {
- for (i = 0; i < 8; i++)
- if (!valid_pat_type((data >> (i * 8)) & 0xff))
- return false;
- return true;
- } else if (msr == MSR_MTRRdefType) {
- if (data & ~0xcff)
- return false;
- return valid_mtrr_type(data & 0xff);
- } else if (msr >= MSR_MTRRfix64K_00000 && msr <= MSR_MTRRfix4K_F8000) {
- for (i = 0; i < 8 ; i++)
- if (!valid_mtrr_type((data >> (i * 8)) & 0xff))
- return false;
- return true;
- }
- /* variable MTRRs */
- WARN_ON(!(msr >= 0x200 && msr < 0x200 + 2 * KVM_NR_VAR_MTRR));
- mask = (~0ULL) << cpuid_maxphyaddr(vcpu);
- if ((msr & 1) == 0) {
- /* MTRR base */
- if (!valid_mtrr_type(data & 0xff))
- return false;
- mask |= 0xf00;
- } else
- /* MTRR mask */
- mask |= 0x7ff;
- if (data & mask) {
- kvm_inject_gp(vcpu, 0);
- return false;
- }
- return true;
- }
- EXPORT_SYMBOL_GPL(kvm_mtrr_valid);
- static bool mtrr_is_enabled(struct kvm_mtrr *mtrr_state)
- {
- return !!(mtrr_state->deftype & IA32_MTRR_DEF_TYPE_E);
- }
- static bool fixed_mtrr_is_enabled(struct kvm_mtrr *mtrr_state)
- {
- return !!(mtrr_state->deftype & IA32_MTRR_DEF_TYPE_FE);
- }
- static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state)
- {
- return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK;
- }
- static u8 mtrr_disabled_type(struct kvm_vcpu *vcpu)
- {
- /*
- * Intel SDM 11.11.2.2: all MTRRs are disabled when
- * IA32_MTRR_DEF_TYPE.E bit is cleared, and the UC
- * memory type is applied to all of physical memory.
- *
- * However, virtual machines can be run with CPUID such that
- * there are no MTRRs. In that case, the firmware will never
- * enable MTRRs and it is obviously undesirable to run the
- * guest entirely with UC memory and we use WB.
- */
- if (guest_cpuid_has_mtrr(vcpu))
- return MTRR_TYPE_UNCACHABLE;
- else
- return MTRR_TYPE_WRBACK;
- }
- /*
- * Three terms are used in the following code:
- * - segment, it indicates the address segments covered by fixed MTRRs.
- * - unit, it corresponds to the MSR entry in the segment.
- * - range, a range is covered in one memory cache type.
- */
- struct fixed_mtrr_segment {
- u64 start;
- u64 end;
- int range_shift;
- /* the start position in kvm_mtrr.fixed_ranges[]. */
- int range_start;
- };
- static struct fixed_mtrr_segment fixed_seg_table[] = {
- /* MSR_MTRRfix64K_00000, 1 unit. 64K fixed mtrr. */
- {
- .start = 0x0,
- .end = 0x80000,
- .range_shift = 16, /* 64K */
- .range_start = 0,
- },
- /*
- * MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000, 2 units,
- * 16K fixed mtrr.
- */
- {
- .start = 0x80000,
- .end = 0xc0000,
- .range_shift = 14, /* 16K */
- .range_start = 8,
- },
- /*
- * MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000, 8 units,
- * 4K fixed mtrr.
- */
- {
- .start = 0xc0000,
- .end = 0x100000,
- .range_shift = 12, /* 12K */
- .range_start = 24,
- }
- };
- /*
- * The size of unit is covered in one MSR, one MSR entry contains
- * 8 ranges so that unit size is always 8 * 2^range_shift.
- */
- static u64 fixed_mtrr_seg_unit_size(int seg)
- {
- return 8 << fixed_seg_table[seg].range_shift;
- }
- static bool fixed_msr_to_seg_unit(u32 msr, int *seg, int *unit)
- {
- switch (msr) {
- case MSR_MTRRfix64K_00000:
- *seg = 0;
- *unit = 0;
- break;
- case MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000:
- *seg = 1;
- *unit = msr - MSR_MTRRfix16K_80000;
- break;
- case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000:
- *seg = 2;
- *unit = msr - MSR_MTRRfix4K_C0000;
- break;
- default:
- return false;
- }
- return true;
- }
- static void fixed_mtrr_seg_unit_range(int seg, int unit, u64 *start, u64 *end)
- {
- struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
- u64 unit_size = fixed_mtrr_seg_unit_size(seg);
- *start = mtrr_seg->start + unit * unit_size;
- *end = *start + unit_size;
- WARN_ON(*end > mtrr_seg->end);
- }
- static int fixed_mtrr_seg_unit_range_index(int seg, int unit)
- {
- struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
- WARN_ON(mtrr_seg->start + unit * fixed_mtrr_seg_unit_size(seg)
- > mtrr_seg->end);
- /* each unit has 8 ranges. */
- return mtrr_seg->range_start + 8 * unit;
- }
- static int fixed_mtrr_seg_end_range_index(int seg)
- {
- struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
- int n;
- n = (mtrr_seg->end - mtrr_seg->start) >> mtrr_seg->range_shift;
- return mtrr_seg->range_start + n - 1;
- }
- static bool fixed_msr_to_range(u32 msr, u64 *start, u64 *end)
- {
- int seg, unit;
- if (!fixed_msr_to_seg_unit(msr, &seg, &unit))
- return false;
- fixed_mtrr_seg_unit_range(seg, unit, start, end);
- return true;
- }
- static int fixed_msr_to_range_index(u32 msr)
- {
- int seg, unit;
- if (!fixed_msr_to_seg_unit(msr, &seg, &unit))
- return -1;
- return fixed_mtrr_seg_unit_range_index(seg, unit);
- }
- static int fixed_mtrr_addr_to_seg(u64 addr)
- {
- struct fixed_mtrr_segment *mtrr_seg;
- int seg, seg_num = ARRAY_SIZE(fixed_seg_table);
- for (seg = 0; seg < seg_num; seg++) {
- mtrr_seg = &fixed_seg_table[seg];
- if (mtrr_seg->start <= addr && addr < mtrr_seg->end)
- return seg;
- }
- return -1;
- }
- static int fixed_mtrr_addr_seg_to_range_index(u64 addr, int seg)
- {
- struct fixed_mtrr_segment *mtrr_seg;
- int index;
- mtrr_seg = &fixed_seg_table[seg];
- index = mtrr_seg->range_start;
- index += (addr - mtrr_seg->start) >> mtrr_seg->range_shift;
- return index;
- }
- static u64 fixed_mtrr_range_end_addr(int seg, int index)
- {
- struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
- int pos = index - mtrr_seg->range_start;
- return mtrr_seg->start + ((pos + 1) << mtrr_seg->range_shift);
- }
- static void var_mtrr_range(struct kvm_mtrr_range *range, u64 *start, u64 *end)
- {
- u64 mask;
- *start = range->base & PAGE_MASK;
- mask = range->mask & PAGE_MASK;
- /* This cannot overflow because writing to the reserved bits of
- * variable MTRRs causes a #GP.
- */
- *end = (*start | ~mask) + 1;
- }
- static void update_mtrr(struct kvm_vcpu *vcpu, u32 msr)
- {
- struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
- gfn_t start, end;
- int index;
- if (msr == MSR_IA32_CR_PAT || !tdp_enabled ||
- !kvm_arch_has_noncoherent_dma(vcpu->kvm))
- return;
- if (!mtrr_is_enabled(mtrr_state) && msr != MSR_MTRRdefType)
- return;
- /* fixed MTRRs. */
- if (fixed_msr_to_range(msr, &start, &end)) {
- if (!fixed_mtrr_is_enabled(mtrr_state))
- return;
- } else if (msr == MSR_MTRRdefType) {
- start = 0x0;
- end = ~0ULL;
- } else {
- /* variable range MTRRs. */
- index = (msr - 0x200) / 2;
- var_mtrr_range(&mtrr_state->var_ranges[index], &start, &end);
- }
- kvm_zap_gfn_range(vcpu->kvm, gpa_to_gfn(start), gpa_to_gfn(end));
- }
- static bool var_mtrr_range_is_valid(struct kvm_mtrr_range *range)
- {
- return (range->mask & (1 << 11)) != 0;
- }
- static void set_var_mtrr_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
- {
- struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
- struct kvm_mtrr_range *tmp, *cur;
- int index, is_mtrr_mask;
- index = (msr - 0x200) / 2;
- is_mtrr_mask = msr - 0x200 - 2 * index;
- cur = &mtrr_state->var_ranges[index];
- /* remove the entry if it's in the list. */
- if (var_mtrr_range_is_valid(cur))
- list_del(&mtrr_state->var_ranges[index].node);
- /* Extend the mask with all 1 bits to the left, since those
- * bits must implicitly be 0. The bits are then cleared
- * when reading them.
- */
- if (!is_mtrr_mask)
- cur->base = data;
- else
- cur->mask = data | (-1LL << cpuid_maxphyaddr(vcpu));
- /* add it to the list if it's enabled. */
- if (var_mtrr_range_is_valid(cur)) {
- list_for_each_entry(tmp, &mtrr_state->head, node)
- if (cur->base >= tmp->base)
- break;
- list_add_tail(&cur->node, &tmp->node);
- }
- }
- int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
- {
- int index;
- if (!kvm_mtrr_valid(vcpu, msr, data))
- return 1;
- index = fixed_msr_to_range_index(msr);
- if (index >= 0)
- *(u64 *)&vcpu->arch.mtrr_state.fixed_ranges[index] = data;
- else if (msr == MSR_MTRRdefType)
- vcpu->arch.mtrr_state.deftype = data;
- else if (msr == MSR_IA32_CR_PAT)
- vcpu->arch.pat = data;
- else
- set_var_mtrr_msr(vcpu, msr, data);
- update_mtrr(vcpu, msr);
- return 0;
- }
- int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
- {
- int index;
- /* MSR_MTRRcap is a readonly MSR. */
- if (msr == MSR_MTRRcap) {
- /*
- * SMRR = 0
- * WC = 1
- * FIX = 1
- * VCNT = KVM_NR_VAR_MTRR
- */
- *pdata = 0x500 | KVM_NR_VAR_MTRR;
- return 0;
- }
- if (!msr_mtrr_valid(msr))
- return 1;
- index = fixed_msr_to_range_index(msr);
- if (index >= 0)
- *pdata = *(u64 *)&vcpu->arch.mtrr_state.fixed_ranges[index];
- else if (msr == MSR_MTRRdefType)
- *pdata = vcpu->arch.mtrr_state.deftype;
- else if (msr == MSR_IA32_CR_PAT)
- *pdata = vcpu->arch.pat;
- else { /* Variable MTRRs */
- int is_mtrr_mask;
- index = (msr - 0x200) / 2;
- is_mtrr_mask = msr - 0x200 - 2 * index;
- if (!is_mtrr_mask)
- *pdata = vcpu->arch.mtrr_state.var_ranges[index].base;
- else
- *pdata = vcpu->arch.mtrr_state.var_ranges[index].mask;
- *pdata &= (1ULL << cpuid_maxphyaddr(vcpu)) - 1;
- }
- return 0;
- }
- void kvm_vcpu_mtrr_init(struct kvm_vcpu *vcpu)
- {
- INIT_LIST_HEAD(&vcpu->arch.mtrr_state.head);
- }
- struct mtrr_iter {
- /* input fields. */
- struct kvm_mtrr *mtrr_state;
- u64 start;
- u64 end;
- /* output fields. */
- int mem_type;
- /* mtrr is completely disabled? */
- bool mtrr_disabled;
- /* [start, end) is not fully covered in MTRRs? */
- bool partial_map;
- /* private fields. */
- union {
- /* used for fixed MTRRs. */
- struct {
- int index;
- int seg;
- };
- /* used for var MTRRs. */
- struct {
- struct kvm_mtrr_range *range;
- /* max address has been covered in var MTRRs. */
- u64 start_max;
- };
- };
- bool fixed;
- };
- static bool mtrr_lookup_fixed_start(struct mtrr_iter *iter)
- {
- int seg, index;
- if (!fixed_mtrr_is_enabled(iter->mtrr_state))
- return false;
- seg = fixed_mtrr_addr_to_seg(iter->start);
- if (seg < 0)
- return false;
- iter->fixed = true;
- index = fixed_mtrr_addr_seg_to_range_index(iter->start, seg);
- iter->index = index;
- iter->seg = seg;
- return true;
- }
- static bool match_var_range(struct mtrr_iter *iter,
- struct kvm_mtrr_range *range)
- {
- u64 start, end;
- var_mtrr_range(range, &start, &end);
- if (!(start >= iter->end || end <= iter->start)) {
- iter->range = range;
- /*
- * the function is called when we do kvm_mtrr.head walking.
- * Range has the minimum base address which interleaves
- * [looker->start_max, looker->end).
- */
- iter->partial_map |= iter->start_max < start;
- /* update the max address has been covered. */
- iter->start_max = max(iter->start_max, end);
- return true;
- }
- return false;
- }
- static void __mtrr_lookup_var_next(struct mtrr_iter *iter)
- {
- struct kvm_mtrr *mtrr_state = iter->mtrr_state;
- list_for_each_entry_continue(iter->range, &mtrr_state->head, node)
- if (match_var_range(iter, iter->range))
- return;
- iter->range = NULL;
- iter->partial_map |= iter->start_max < iter->end;
- }
- static void mtrr_lookup_var_start(struct mtrr_iter *iter)
- {
- struct kvm_mtrr *mtrr_state = iter->mtrr_state;
- iter->fixed = false;
- iter->start_max = iter->start;
- iter->range = NULL;
- iter->range = list_prepare_entry(iter->range, &mtrr_state->head, node);
- __mtrr_lookup_var_next(iter);
- }
- static void mtrr_lookup_fixed_next(struct mtrr_iter *iter)
- {
- /* terminate the lookup. */
- if (fixed_mtrr_range_end_addr(iter->seg, iter->index) >= iter->end) {
- iter->fixed = false;
- iter->range = NULL;
- return;
- }
- iter->index++;
- /* have looked up for all fixed MTRRs. */
- if (iter->index >= ARRAY_SIZE(iter->mtrr_state->fixed_ranges))
- return mtrr_lookup_var_start(iter);
- /* switch to next segment. */
- if (iter->index > fixed_mtrr_seg_end_range_index(iter->seg))
- iter->seg++;
- }
- static void mtrr_lookup_var_next(struct mtrr_iter *iter)
- {
- __mtrr_lookup_var_next(iter);
- }
- static void mtrr_lookup_start(struct mtrr_iter *iter)
- {
- if (!mtrr_is_enabled(iter->mtrr_state)) {
- iter->mtrr_disabled = true;
- return;
- }
- if (!mtrr_lookup_fixed_start(iter))
- mtrr_lookup_var_start(iter);
- }
- static void mtrr_lookup_init(struct mtrr_iter *iter,
- struct kvm_mtrr *mtrr_state, u64 start, u64 end)
- {
- iter->mtrr_state = mtrr_state;
- iter->start = start;
- iter->end = end;
- iter->mtrr_disabled = false;
- iter->partial_map = false;
- iter->fixed = false;
- iter->range = NULL;
- mtrr_lookup_start(iter);
- }
- static bool mtrr_lookup_okay(struct mtrr_iter *iter)
- {
- if (iter->fixed) {
- iter->mem_type = iter->mtrr_state->fixed_ranges[iter->index];
- return true;
- }
- if (iter->range) {
- iter->mem_type = iter->range->base & 0xff;
- return true;
- }
- return false;
- }
- static void mtrr_lookup_next(struct mtrr_iter *iter)
- {
- if (iter->fixed)
- mtrr_lookup_fixed_next(iter);
- else
- mtrr_lookup_var_next(iter);
- }
- #define mtrr_for_each_mem_type(_iter_, _mtrr_, _gpa_start_, _gpa_end_) \
- for (mtrr_lookup_init(_iter_, _mtrr_, _gpa_start_, _gpa_end_); \
- mtrr_lookup_okay(_iter_); mtrr_lookup_next(_iter_))
- u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
- {
- struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
- struct mtrr_iter iter;
- u64 start, end;
- int type = -1;
- const int wt_wb_mask = (1 << MTRR_TYPE_WRBACK)
- | (1 << MTRR_TYPE_WRTHROUGH);
- start = gfn_to_gpa(gfn);
- end = start + PAGE_SIZE;
- mtrr_for_each_mem_type(&iter, mtrr_state, start, end) {
- int curr_type = iter.mem_type;
- /*
- * Please refer to Intel SDM Volume 3: 11.11.4.1 MTRR
- * Precedences.
- */
- if (type == -1) {
- type = curr_type;
- continue;
- }
- /*
- * If two or more variable memory ranges match and the
- * memory types are identical, then that memory type is
- * used.
- */
- if (type == curr_type)
- continue;
- /*
- * If two or more variable memory ranges match and one of
- * the memory types is UC, the UC memory type used.
- */
- if (curr_type == MTRR_TYPE_UNCACHABLE)
- return MTRR_TYPE_UNCACHABLE;
- /*
- * If two or more variable memory ranges match and the
- * memory types are WT and WB, the WT memory type is used.
- */
- if (((1 << type) & wt_wb_mask) &&
- ((1 << curr_type) & wt_wb_mask)) {
- type = MTRR_TYPE_WRTHROUGH;
- continue;
- }
- /*
- * For overlaps not defined by the above rules, processor
- * behavior is undefined.
- */
- /* We use WB for this undefined behavior. :( */
- return MTRR_TYPE_WRBACK;
- }
- if (iter.mtrr_disabled)
- return mtrr_disabled_type(vcpu);
- /* not contained in any MTRRs. */
- if (type == -1)
- return mtrr_default_type(mtrr_state);
- /*
- * We just check one page, partially covered by MTRRs is
- * impossible.
- */
- WARN_ON(iter.partial_map);
- return type;
- }
- EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type);
- bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
- int page_num)
- {
- struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
- struct mtrr_iter iter;
- u64 start, end;
- int type = -1;
- start = gfn_to_gpa(gfn);
- end = gfn_to_gpa(gfn + page_num);
- mtrr_for_each_mem_type(&iter, mtrr_state, start, end) {
- if (type == -1) {
- type = iter.mem_type;
- continue;
- }
- if (type != iter.mem_type)
- return false;
- }
- if (iter.mtrr_disabled)
- return true;
- if (!iter.partial_map)
- return true;
- if (type == -1)
- return true;
- return type == mtrr_default_type(mtrr_state);
- }
|