aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2014-01-14 13:00:55 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2014-03-02 20:15:24 -0500
commit8034699a42d68043b495c7e0cfafccd920707ec8 (patch)
tree25fbae0371d43ca1a2edd7f876e6c80b5ccbec29
parentaf20814ee927ed888288d98917a766b4179c4fe0 (diff)
ARM: KVM: trap VM system registers until MMU and caches are ON
In order to be able to detect the point where the guest enables its MMU and caches, trap all the VM related system registers. Once we see the guest enabling both the MMU and the caches, we can go back to a saner mode of operation, which is to leave these registers in complete control of the guest. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
-rw-r--r--arch/arm/include/asm/kvm_arm.h3
-rw-r--r--arch/arm/kvm/coproc.c74
-rw-r--r--arch/arm/kvm/coproc.h4
-rw-r--r--arch/arm/kvm/coproc_a15.c2
-rw-r--r--arch/arm/kvm/coproc_a7.c2
5 files changed, 66 insertions, 19 deletions
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index a843e74a384c..816db0bf2dd8 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -55,6 +55,7 @@
55 * The bits we set in HCR: 55 * The bits we set in HCR:
56 * TAC: Trap ACTLR 56 * TAC: Trap ACTLR
57 * TSC: Trap SMC 57 * TSC: Trap SMC
58 * TVM: Trap VM ops (until MMU and caches are on)
58 * TSW: Trap cache operations by set/way 59 * TSW: Trap cache operations by set/way
59 * TWI: Trap WFI 60 * TWI: Trap WFI
60 * TWE: Trap WFE 61 * TWE: Trap WFE
@@ -68,7 +69,7 @@
68 */ 69 */
69#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \ 70#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
70 HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \ 71 HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
71 HCR_TWE | HCR_SWIO | HCR_TIDCP) 72 HCR_TVM | HCR_TWE | HCR_SWIO | HCR_TIDCP)
72 73
73/* System Control Register (SCTLR) bits */ 74/* System Control Register (SCTLR) bits */
74#define SCTLR_TE (1 << 30) 75#define SCTLR_TE (1 << 30)
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index a5a54a48d51b..c58a35116f63 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -23,6 +23,7 @@
23#include <asm/kvm_host.h> 23#include <asm/kvm_host.h>
24#include <asm/kvm_emulate.h> 24#include <asm/kvm_emulate.h>
25#include <asm/kvm_coproc.h> 25#include <asm/kvm_coproc.h>
26#include <asm/kvm_mmu.h>
26#include <asm/cacheflush.h> 27#include <asm/cacheflush.h>
27#include <asm/cputype.h> 28#include <asm/cputype.h>
28#include <trace/events/kvm.h> 29#include <trace/events/kvm.h>
@@ -205,6 +206,44 @@ done:
205} 206}
206 207
207/* 208/*
209 * Generic accessor for VM registers. Only called as long as HCR_TVM
210 * is set.
211 */
212static bool access_vm_reg(struct kvm_vcpu *vcpu,
213 const struct coproc_params *p,
214 const struct coproc_reg *r)
215{
216 BUG_ON(!p->is_write);
217
218 vcpu->arch.cp15[r->reg] = *vcpu_reg(vcpu, p->Rt1);
219 if (p->is_64bit)
220 vcpu->arch.cp15[r->reg + 1] = *vcpu_reg(vcpu, p->Rt2);
221
222 return true;
223}
224
225/*
226 * SCTLR accessor. Only called as long as HCR_TVM is set. If the
227 * guest enables the MMU, we stop trapping the VM sys_regs and leave
228 * it in complete control of the caches.
229 *
230 * Used by the cpu-specific code.
231 */
232bool access_sctlr(struct kvm_vcpu *vcpu,
233 const struct coproc_params *p,
234 const struct coproc_reg *r)
235{
236 access_vm_reg(vcpu, p, r);
237
238 if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */
239 vcpu->arch.hcr &= ~HCR_TVM;
240 stage2_flush_vm(vcpu->kvm);
241 }
242
243 return true;
244}
245
246/*
208 * We could trap ID_DFR0 and tell the guest we don't support performance 247 * We could trap ID_DFR0 and tell the guest we don't support performance
209 * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was 248 * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
210 * NAKed, so it will read the PMCR anyway. 249 * NAKed, so it will read the PMCR anyway.
@@ -261,33 +300,36 @@ static const struct coproc_reg cp15_regs[] = {
261 { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32, 300 { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
262 NULL, reset_val, c1_CPACR, 0x00000000 }, 301 NULL, reset_val, c1_CPACR, 0x00000000 },
263 302
264 /* TTBR0/TTBR1: swapped by interrupt.S. */ 303 /* TTBR0/TTBR1/TTBCR: swapped by interrupt.S. */
265 { CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 }, 304 { CRm64( 2), Op1( 0), is64, access_vm_reg, reset_unknown64, c2_TTBR0 },
266 { CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 }, 305 { CRn(2), CRm( 0), Op1( 0), Op2( 0), is32,
267 306 access_vm_reg, reset_unknown, c2_TTBR0 },
268 /* TTBCR: swapped by interrupt.S. */ 307 { CRn(2), CRm( 0), Op1( 0), Op2( 1), is32,
308 access_vm_reg, reset_unknown, c2_TTBR1 },
269 { CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32, 309 { CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
270 NULL, reset_val, c2_TTBCR, 0x00000000 }, 310 access_vm_reg, reset_val, c2_TTBCR, 0x00000000 },
311 { CRm64( 2), Op1( 1), is64, access_vm_reg, reset_unknown64, c2_TTBR1 },
312
271 313
272 /* DACR: swapped by interrupt.S. */ 314 /* DACR: swapped by interrupt.S. */
273 { CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32, 315 { CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32,
274 NULL, reset_unknown, c3_DACR }, 316 access_vm_reg, reset_unknown, c3_DACR },
275 317
276 /* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */ 318 /* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */
277 { CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32, 319 { CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32,
278 NULL, reset_unknown, c5_DFSR }, 320 access_vm_reg, reset_unknown, c5_DFSR },
279 { CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32, 321 { CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32,
280 NULL, reset_unknown, c5_IFSR }, 322 access_vm_reg, reset_unknown, c5_IFSR },
281 { CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32, 323 { CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32,
282 NULL, reset_unknown, c5_ADFSR }, 324 access_vm_reg, reset_unknown, c5_ADFSR },
283 { CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32, 325 { CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32,
284 NULL, reset_unknown, c5_AIFSR }, 326 access_vm_reg, reset_unknown, c5_AIFSR },
285 327
286 /* DFAR/IFAR: swapped by interrupt.S. */ 328 /* DFAR/IFAR: swapped by interrupt.S. */
287 { CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32, 329 { CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32,
288 NULL, reset_unknown, c6_DFAR }, 330 access_vm_reg, reset_unknown, c6_DFAR },
289 { CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32, 331 { CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
290 NULL, reset_unknown, c6_IFAR }, 332 access_vm_reg, reset_unknown, c6_IFAR },
291 333
292 /* PAR swapped by interrupt.S */ 334 /* PAR swapped by interrupt.S */
293 { CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR }, 335 { CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
@@ -324,9 +366,9 @@ static const struct coproc_reg cp15_regs[] = {
324 366
325 /* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */ 367 /* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */
326 { CRn(10), CRm( 2), Op1( 0), Op2( 0), is32, 368 { CRn(10), CRm( 2), Op1( 0), Op2( 0), is32,
327 NULL, reset_unknown, c10_PRRR}, 369 access_vm_reg, reset_unknown, c10_PRRR},
328 { CRn(10), CRm( 2), Op1( 0), Op2( 1), is32, 370 { CRn(10), CRm( 2), Op1( 0), Op2( 1), is32,
329 NULL, reset_unknown, c10_NMRR}, 371 access_vm_reg, reset_unknown, c10_NMRR},
330 372
331 /* AMAIR0/AMAIR1: swapped by interrupt.S. */ 373 /* AMAIR0/AMAIR1: swapped by interrupt.S. */
332 { CRn(10), CRm( 3), Op1( 0), Op2( 0), is32, 374 { CRn(10), CRm( 3), Op1( 0), Op2( 0), is32,
@@ -340,7 +382,7 @@ static const struct coproc_reg cp15_regs[] = {
340 382
341 /* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */ 383 /* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */
342 { CRn(13), CRm( 0), Op1( 0), Op2( 1), is32, 384 { CRn(13), CRm( 0), Op1( 0), Op2( 1), is32,
343 NULL, reset_val, c13_CID, 0x00000000 }, 385 access_vm_reg, reset_val, c13_CID, 0x00000000 },
344 { CRn(13), CRm( 0), Op1( 0), Op2( 2), is32, 386 { CRn(13), CRm( 0), Op1( 0), Op2( 2), is32,
345 NULL, reset_unknown, c13_TID_URW }, 387 NULL, reset_unknown, c13_TID_URW },
346 { CRn(13), CRm( 0), Op1( 0), Op2( 3), is32, 388 { CRn(13), CRm( 0), Op1( 0), Op2( 3), is32,
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index 8dda870e84f9..1a44bbe39643 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -153,4 +153,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
153#define is64 .is_64 = true 153#define is64 .is_64 = true
154#define is32 .is_64 = false 154#define is32 .is_64 = false
155 155
156bool access_sctlr(struct kvm_vcpu *vcpu,
157 const struct coproc_params *p,
158 const struct coproc_reg *r);
159
156#endif /* __ARM_KVM_COPROC_LOCAL_H__ */ 160#endif /* __ARM_KVM_COPROC_LOCAL_H__ */
diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c
index bb0cac1410cc..e6f4ae48bda9 100644
--- a/arch/arm/kvm/coproc_a15.c
+++ b/arch/arm/kvm/coproc_a15.c
@@ -34,7 +34,7 @@
34static const struct coproc_reg a15_regs[] = { 34static const struct coproc_reg a15_regs[] = {
35 /* SCTLR: swapped by interrupt.S. */ 35 /* SCTLR: swapped by interrupt.S. */
36 { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, 36 { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
37 NULL, reset_val, c1_SCTLR, 0x00C50078 }, 37 access_sctlr, reset_val, c1_SCTLR, 0x00C50078 },
38}; 38};
39 39
40static struct kvm_coproc_target_table a15_target_table = { 40static struct kvm_coproc_target_table a15_target_table = {
diff --git a/arch/arm/kvm/coproc_a7.c b/arch/arm/kvm/coproc_a7.c
index 1df767331588..17fc7cd479d3 100644
--- a/arch/arm/kvm/coproc_a7.c
+++ b/arch/arm/kvm/coproc_a7.c
@@ -37,7 +37,7 @@
37static const struct coproc_reg a7_regs[] = { 37static const struct coproc_reg a7_regs[] = {
38 /* SCTLR: swapped by interrupt.S. */ 38 /* SCTLR: swapped by interrupt.S. */
39 { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, 39 { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
40 NULL, reset_val, c1_SCTLR, 0x00C50878 }, 40 access_sctlr, reset_val, c1_SCTLR, 0x00C50878 },
41}; 41};
42 42
43static struct kvm_coproc_target_table a7_target_table = { 43static struct kvm_coproc_target_table a7_target_table = {