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:21 -0500
commit4d44923b17bff283c002ed961373848284aaff1b (patch)
tree47a84336cf900f8cefbfa66785664a950aa36ec3
parent2072d29c46b73e39b3c6c56c6027af77086f45fd (diff)
arm64: 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> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
-rw-r--r--arch/arm64/include/asm/kvm_arm.h3
-rw-r--r--arch/arm64/include/asm/kvm_asm.h3
-rw-r--r--arch/arm64/kvm/sys_regs.c90
3 files changed, 82 insertions, 14 deletions
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 0eb398655378..00fbaa75dc7b 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -62,6 +62,7 @@
62 * RW: 64bit by default, can be overriden for 32bit VMs 62 * RW: 64bit by default, can be overriden for 32bit VMs
63 * TAC: Trap ACTLR 63 * TAC: Trap ACTLR
64 * TSC: Trap SMC 64 * TSC: Trap SMC
65 * TVM: Trap VM ops (until M+C set in SCTLR_EL1)
65 * TSW: Trap cache operations by set/way 66 * TSW: Trap cache operations by set/way
66 * TWE: Trap WFE 67 * TWE: Trap WFE
67 * TWI: Trap WFI 68 * TWI: Trap WFI
@@ -74,7 +75,7 @@
74 * SWIO: Turn set/way invalidates into set/way clean+invalidate 75 * SWIO: Turn set/way invalidates into set/way clean+invalidate
75 */ 76 */
76#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \ 77#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
77 HCR_BSU_IS | HCR_FB | HCR_TAC | \ 78 HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
78 HCR_AMO | HCR_IMO | HCR_FMO | \ 79 HCR_AMO | HCR_IMO | HCR_FMO | \
79 HCR_SWIO | HCR_TIDCP | HCR_RW) 80 HCR_SWIO | HCR_TIDCP | HCR_RW)
80#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) 81#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index b25763bc0ec4..9fcd54b1e16d 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -79,7 +79,8 @@
79#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */ 79#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */
80#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */ 80#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
81#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */ 81#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */
82#define c10_AMAIR (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */ 82#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
83#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
83#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */ 84#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
84#define NR_CP15_REGS (NR_SYS_REGS * 2) 85#define NR_CP15_REGS (NR_SYS_REGS * 2)
85 86
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index bf03e0fadf1f..2097e5ecba42 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -121,6 +121,46 @@ done:
121} 121}
122 122
123/* 123/*
124 * Generic accessor for VM registers. Only called as long as HCR_TVM
125 * is set.
126 */
127static bool access_vm_reg(struct kvm_vcpu *vcpu,
128 const struct sys_reg_params *p,
129 const struct sys_reg_desc *r)
130{
131 unsigned long val;
132
133 BUG_ON(!p->is_write);
134
135 val = *vcpu_reg(vcpu, p->Rt);
136 if (!p->is_aarch32) {
137 vcpu_sys_reg(vcpu, r->reg) = val;
138 } else {
139 vcpu_cp15(vcpu, r->reg) = val & 0xffffffffUL;
140 if (!p->is_32bit)
141 vcpu_cp15(vcpu, r->reg + 1) = val >> 32;
142 }
143 return true;
144}
145
146/*
147 * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set. If the
148 * guest enables the MMU, we stop trapping the VM sys_regs and leave
149 * it in complete control of the caches.
150 */
151static bool access_sctlr(struct kvm_vcpu *vcpu,
152 const struct sys_reg_params *p,
153 const struct sys_reg_desc *r)
154{
155 access_vm_reg(vcpu, p, r);
156
157 if (vcpu_has_cache_enabled(vcpu)) /* MMU+Caches enabled? */
158 vcpu->arch.hcr_el2 &= ~HCR_TVM;
159
160 return true;
161}
162
163/*
124 * We could trap ID_DFR0 and tell the guest we don't support performance 164 * We could trap ID_DFR0 and tell the guest we don't support performance
125 * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was 165 * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
126 * NAKed, so it will read the PMCR anyway. 166 * NAKed, so it will read the PMCR anyway.
@@ -185,32 +225,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
185 NULL, reset_mpidr, MPIDR_EL1 }, 225 NULL, reset_mpidr, MPIDR_EL1 },
186 /* SCTLR_EL1 */ 226 /* SCTLR_EL1 */
187 { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000), 227 { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
188 NULL, reset_val, SCTLR_EL1, 0x00C50078 }, 228 access_sctlr, reset_val, SCTLR_EL1, 0x00C50078 },
189 /* CPACR_EL1 */ 229 /* CPACR_EL1 */
190 { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010), 230 { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),
191 NULL, reset_val, CPACR_EL1, 0 }, 231 NULL, reset_val, CPACR_EL1, 0 },
192 /* TTBR0_EL1 */ 232 /* TTBR0_EL1 */
193 { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000), 233 { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000),
194 NULL, reset_unknown, TTBR0_EL1 }, 234 access_vm_reg, reset_unknown, TTBR0_EL1 },
195 /* TTBR1_EL1 */ 235 /* TTBR1_EL1 */
196 { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001), 236 { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001),
197 NULL, reset_unknown, TTBR1_EL1 }, 237 access_vm_reg, reset_unknown, TTBR1_EL1 },
198 /* TCR_EL1 */ 238 /* TCR_EL1 */
199 { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010), 239 { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010),
200 NULL, reset_val, TCR_EL1, 0 }, 240 access_vm_reg, reset_val, TCR_EL1, 0 },
201 241
202 /* AFSR0_EL1 */ 242 /* AFSR0_EL1 */
203 { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000), 243 { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000),
204 NULL, reset_unknown, AFSR0_EL1 }, 244 access_vm_reg, reset_unknown, AFSR0_EL1 },
205 /* AFSR1_EL1 */ 245 /* AFSR1_EL1 */
206 { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001), 246 { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001),
207 NULL, reset_unknown, AFSR1_EL1 }, 247 access_vm_reg, reset_unknown, AFSR1_EL1 },
208 /* ESR_EL1 */ 248 /* ESR_EL1 */
209 { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000), 249 { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000),
210 NULL, reset_unknown, ESR_EL1 }, 250 access_vm_reg, reset_unknown, ESR_EL1 },
211 /* FAR_EL1 */ 251 /* FAR_EL1 */
212 { Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000), 252 { Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
213 NULL, reset_unknown, FAR_EL1 }, 253 access_vm_reg, reset_unknown, FAR_EL1 },
214 /* PAR_EL1 */ 254 /* PAR_EL1 */
215 { Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000), 255 { Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000),
216 NULL, reset_unknown, PAR_EL1 }, 256 NULL, reset_unknown, PAR_EL1 },
@@ -224,17 +264,17 @@ static const struct sys_reg_desc sys_reg_descs[] = {
224 264
225 /* MAIR_EL1 */ 265 /* MAIR_EL1 */
226 { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000), 266 { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
227 NULL, reset_unknown, MAIR_EL1 }, 267 access_vm_reg, reset_unknown, MAIR_EL1 },
228 /* AMAIR_EL1 */ 268 /* AMAIR_EL1 */
229 { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000), 269 { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000),
230 NULL, reset_amair_el1, AMAIR_EL1 }, 270 access_vm_reg, reset_amair_el1, AMAIR_EL1 },
231 271
232 /* VBAR_EL1 */ 272 /* VBAR_EL1 */
233 { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000), 273 { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
234 NULL, reset_val, VBAR_EL1, 0 }, 274 NULL, reset_val, VBAR_EL1, 0 },
235 /* CONTEXTIDR_EL1 */ 275 /* CONTEXTIDR_EL1 */
236 { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001), 276 { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
237 NULL, reset_val, CONTEXTIDR_EL1, 0 }, 277 access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
238 /* TPIDR_EL1 */ 278 /* TPIDR_EL1 */
239 { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100), 279 { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100),
240 NULL, reset_unknown, TPIDR_EL1 }, 280 NULL, reset_unknown, TPIDR_EL1 },
@@ -305,14 +345,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
305 NULL, reset_val, FPEXC32_EL2, 0x70 }, 345 NULL, reset_val, FPEXC32_EL2, 0x70 },
306}; 346};
307 347
308/* Trapped cp15 registers */ 348/*
349 * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
350 * depending on the way they are accessed (as a 32bit or a 64bit
351 * register).
352 */
309static const struct sys_reg_desc cp15_regs[] = { 353static const struct sys_reg_desc cp15_regs[] = {
354 { Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
355 { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR },
356 { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
357 { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
358 { Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR },
359 { Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, c3_DACR },
360 { Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, c5_DFSR },
361 { Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, c5_IFSR },
362 { Op1( 0), CRn( 5), CRm( 1), Op2( 0), access_vm_reg, NULL, c5_ADFSR },
363 { Op1( 0), CRn( 5), CRm( 1), Op2( 1), access_vm_reg, NULL, c5_AIFSR },
364 { Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, c6_DFAR },
365 { Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, c6_IFAR },
366
310 /* 367 /*
311 * DC{C,I,CI}SW operations: 368 * DC{C,I,CI}SW operations:
312 */ 369 */
313 { Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw }, 370 { Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw },
314 { Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw }, 371 { Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw },
315 { Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw }, 372 { Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
373
316 { Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake }, 374 { Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake },
317 { Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake }, 375 { Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake },
318 { Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake }, 376 { Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake },
@@ -326,6 +384,14 @@ static const struct sys_reg_desc cp15_regs[] = {
326 { Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake }, 384 { Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake },
327 { Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake }, 385 { Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake },
328 { Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake }, 386 { Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake },
387
388 { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
389 { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
390 { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 },
391 { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 },
392 { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
393
394 { Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
329}; 395};
330 396
331/* Target specific emulation tables */ 397/* Target specific emulation tables */