aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-03-16 06:59:43 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-10 12:49:34 -0400
commitc8bdf091472978ecfc884148b50be5f93761fdf9 (patch)
tree767a44d60201a06671fd0c541a4b4380bad718b0 /arch
parent805f18e0bcbf894c4412e3069c7ac4c3e1feb9bf (diff)
arm: KVM: force execution of HCPTR access on VM exit
commit 85e84ba31039595995dae80b277378213602891b upstream. On VM entry, we disable access to the VFP registers in order to perform a lazy save/restore of these registers. On VM exit, we restore access, test if we did enable them before, and save/restore the guest/host registers if necessary. In this sequence, the FPEXC register is always accessed, irrespective of the trapping configuration. If the guest didn't touch the VFP registers, then the HCPTR access has now enabled such access, but we're missing a barrier to ensure architectural execution of the new HCPTR configuration. If the HCPTR access has been delayed/reordered, the subsequent access to FPEXC will cause a trap, which we aren't prepared to handle at all. The same condition exists when trapping to enable VFP for the guest. The fix is to introduce a barrier after enabling VFP access. In the vmexit case, it can be relaxed to only takes place if the guest hasn't accessed its view of the VFP registers, making the access to FPEXC safe. The set_hcptr macro is modified to deal with both vmenter/vmexit and vmtrap operations, and now takes an optional label that is branched to when the guest hasn't touched the VFP registers. Reported-by: Vikram Sethi <vikrams@codeaurora.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kvm/interrupts.S10
-rw-r--r--arch/arm/kvm/interrupts_head.S20
2 files changed, 22 insertions, 8 deletions
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index 79caf79b304a..f7db3a5d80e3 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -170,13 +170,9 @@ __kvm_vcpu_return:
170 @ Don't trap coprocessor accesses for host kernel 170 @ Don't trap coprocessor accesses for host kernel
171 set_hstr vmexit 171 set_hstr vmexit
172 set_hdcr vmexit 172 set_hdcr vmexit
173 set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11)) 173 set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11)), after_vfp_restore
174 174
175#ifdef CONFIG_VFPv3 175#ifdef CONFIG_VFPv3
176 @ Save floating point registers we if let guest use them.
177 tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11))
178 bne after_vfp_restore
179
180 @ Switch VFP/NEON hardware state to the host's 176 @ Switch VFP/NEON hardware state to the host's
181 add r7, vcpu, #VCPU_VFP_GUEST 177 add r7, vcpu, #VCPU_VFP_GUEST
182 store_vfp_state r7 178 store_vfp_state r7
@@ -188,6 +184,8 @@ after_vfp_restore:
188 @ Restore FPEXC_EN which we clobbered on entry 184 @ Restore FPEXC_EN which we clobbered on entry
189 pop {r2} 185 pop {r2}
190 VFPFMXR FPEXC, r2 186 VFPFMXR FPEXC, r2
187#else
188after_vfp_restore:
191#endif 189#endif
192 190
193 @ Reset Hyp-role 191 @ Reset Hyp-role
@@ -483,7 +481,7 @@ switch_to_guest_vfp:
483 push {r3-r7} 481 push {r3-r7}
484 482
485 @ NEON/VFP used. Turn on VFP access. 483 @ NEON/VFP used. Turn on VFP access.
486 set_hcptr vmexit, (HCPTR_TCP(10) | HCPTR_TCP(11)) 484 set_hcptr vmtrap, (HCPTR_TCP(10) | HCPTR_TCP(11))
487 485
488 @ Switch VFP/NEON hardware state to the guest's 486 @ Switch VFP/NEON hardware state to the guest's
489 add r7, r0, #VCPU_VFP_HOST 487 add r7, r0, #VCPU_VFP_HOST
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 35e4a3a0c476..48efe2ee452c 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -591,8 +591,13 @@ ARM_BE8(rev r6, r6 )
591.endm 591.endm
592 592
593/* Configures the HCPTR (Hyp Coprocessor Trap Register) on entry/return 593/* Configures the HCPTR (Hyp Coprocessor Trap Register) on entry/return
594 * (hardware reset value is 0). Keep previous value in r2. */ 594 * (hardware reset value is 0). Keep previous value in r2.
595.macro set_hcptr operation, mask 595 * An ISB is emited on vmexit/vmtrap, but executed on vmexit only if
596 * VFP wasn't already enabled (always executed on vmtrap).
597 * If a label is specified with vmexit, it is branched to if VFP wasn't
598 * enabled.
599 */
600.macro set_hcptr operation, mask, label = none
596 mrc p15, 4, r2, c1, c1, 2 601 mrc p15, 4, r2, c1, c1, 2
597 ldr r3, =\mask 602 ldr r3, =\mask
598 .if \operation == vmentry 603 .if \operation == vmentry
@@ -601,6 +606,17 @@ ARM_BE8(rev r6, r6 )
601 bic r3, r2, r3 @ Don't trap defined coproc-accesses 606 bic r3, r2, r3 @ Don't trap defined coproc-accesses
602 .endif 607 .endif
603 mcr p15, 4, r3, c1, c1, 2 608 mcr p15, 4, r3, c1, c1, 2
609 .if \operation != vmentry
610 .if \operation == vmexit
611 tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11))
612 beq 1f
613 .endif
614 isb
615 .if \label != none
616 b \label
617 .endif
6181:
619 .endif
604.endm 620.endm
605 621
606/* Configures the HDCR (Hyp Debug Configuration Register) on entry/return 622/* Configures the HDCR (Hyp Debug Configuration Register) on entry/return