diff options
-rw-r--r-- | arch/arm/include/asm/kvm_arm.h | 3 | ||||
-rw-r--r-- | arch/arm/kvm/coproc.c | 74 | ||||
-rw-r--r-- | arch/arm/kvm/coproc.h | 4 | ||||
-rw-r--r-- | arch/arm/kvm/coproc_a15.c | 2 | ||||
-rw-r--r-- | arch/arm/kvm/coproc_a7.c | 2 |
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 | */ | ||
212 | static 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 | */ | ||
232 | bool 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 | ||
156 | bool 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 @@ | |||
34 | static const struct coproc_reg a15_regs[] = { | 34 | static 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 | ||
40 | static struct kvm_coproc_target_table a15_target_table = { | 40 | static 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 @@ | |||
37 | static const struct coproc_reg a7_regs[] = { | 37 | static 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 | ||
43 | static struct kvm_coproc_target_table a7_target_table = { | 43 | static struct kvm_coproc_target_table a7_target_table = { |