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