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 = { |
