aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 = {