Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: KVM: Add VFP save/restore

This is almost a copy/paste of the existing version, with a couple
of subtle differences:
- Only write to FPEXC once on the save path
- Add an isb when enabling VFP access

The patch also defines a few sysreg accessors and a __vfp_enabled
predicate that test the VFP trapping state.

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+82
+1
arch/arm/kvm/hyp/Makefile
··· 6 6 obj-$(CONFIG_KVM_ARM_HOST) += cp15-sr.o 7 7 obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o 8 8 obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o 9 + obj-$(CONFIG_KVM_ARM_HOST) += vfp.o
+13
arch/arm/kvm/hyp/hyp.h
··· 21 21 #include <linux/compiler.h> 22 22 #include <linux/kvm_host.h> 23 23 #include <asm/kvm_mmu.h> 24 + #include <asm/vfp.h> 24 25 25 26 #define __hyp_text __section(.hyp.text) notrace 26 27 ··· 32 31 "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32 33 32 #define __ACCESS_CP15_64(Op1, CRm) \ 34 33 "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64 34 + #define __ACCESS_VFP(CRn) \ 35 + "mrc", "mcr", __stringify(p10, 7, %0, CRn, cr0, 0), u32 35 36 36 37 #define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v))) 37 38 #define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__) ··· 56 53 #define VMPIDR __ACCESS_CP15(c0, 4, c0, 5) 57 54 #define SCTLR __ACCESS_CP15(c1, 0, c0, 0) 58 55 #define CPACR __ACCESS_CP15(c1, 0, c0, 2) 56 + #define HCPTR __ACCESS_CP15(c1, 4, c1, 2) 59 57 #define TTBCR __ACCESS_CP15(c2, 0, c0, 2) 60 58 #define DACR __ACCESS_CP15(c3, 0, c0, 0) 61 59 #define DFSR __ACCESS_CP15(c5, 0, c0, 0) ··· 81 77 #define CNTV_CTL __ACCESS_CP15(c14, 0, c3, 1) 82 78 #define CNTHCTL __ACCESS_CP15(c14, 4, c1, 0) 83 79 80 + #define VFP_FPEXC __ACCESS_VFP(FPEXC) 81 + 84 82 void __timer_save_state(struct kvm_vcpu *vcpu); 85 83 void __timer_restore_state(struct kvm_vcpu *vcpu); 86 84 ··· 91 85 92 86 void __sysreg_save_state(struct kvm_cpu_context *ctxt); 93 87 void __sysreg_restore_state(struct kvm_cpu_context *ctxt); 88 + 89 + void asmlinkage __vfp_save_state(struct vfp_hard_struct *vfp); 90 + void asmlinkage __vfp_restore_state(struct vfp_hard_struct *vfp); 91 + static inline bool __vfp_enabled(void) 92 + { 93 + return !(read_sysreg(HCPTR) & (HCPTR_TCP(11) | HCPTR_TCP(10))); 94 + } 94 95 95 96 #endif /* __ARM_KVM_HYP_H__ */
+68
arch/arm/kvm/hyp/vfp.S
··· 1 + /* 2 + * Copyright (C) 2012 - Virtual Open Systems and Columbia University 3 + * Author: Christoffer Dall <c.dall@virtualopensystems.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #include <linux/linkage.h> 19 + #include <asm/vfpmacros.h> 20 + 21 + .text 22 + .pushsection .hyp.text, "ax" 23 + 24 + /* void __vfp_save_state(struct vfp_hard_struct *vfp); */ 25 + ENTRY(__vfp_save_state) 26 + push {r4, r5} 27 + VFPFMRX r1, FPEXC 28 + 29 + @ Make sure *really* VFP is enabled so we can touch the registers. 30 + orr r5, r1, #FPEXC_EN 31 + tst r5, #FPEXC_EX @ Check for VFP Subarchitecture 32 + bic r5, r5, #FPEXC_EX @ FPEXC_EX disable 33 + VFPFMXR FPEXC, r5 34 + isb 35 + 36 + VFPFMRX r2, FPSCR 37 + beq 1f 38 + 39 + @ If FPEXC_EX is 0, then FPINST/FPINST2 reads are upredictable, so 40 + @ we only need to save them if FPEXC_EX is set. 41 + VFPFMRX r3, FPINST 42 + tst r5, #FPEXC_FP2V 43 + VFPFMRX r4, FPINST2, ne @ vmrsne 44 + 1: 45 + VFPFSTMIA r0, r5 @ Save VFP registers 46 + stm r0, {r1-r4} @ Save FPEXC, FPSCR, FPINST, FPINST2 47 + pop {r4, r5} 48 + bx lr 49 + ENDPROC(__vfp_save_state) 50 + 51 + /* void __vfp_restore_state(struct vfp_hard_struct *vfp); 52 + * Assume FPEXC_EN is on and FPEXC_EX is off */ 53 + ENTRY(__vfp_restore_state) 54 + VFPFLDMIA r0, r1 @ Load VFP registers 55 + ldm r0, {r0-r3} @ Load FPEXC, FPSCR, FPINST, FPINST2 56 + 57 + VFPFMXR FPSCR, r1 58 + tst r0, #FPEXC_EX @ Check for VFP Subarchitecture 59 + beq 1f 60 + VFPFMXR FPINST, r2 61 + tst r0, #FPEXC_FP2V 62 + VFPFMXR FPINST2, r3, ne 63 + 1: 64 + VFPFMXR FPEXC, r0 @ FPEXC (last, in case !EN) 65 + bx lr 66 + ENDPROC(__vfp_restore_state) 67 + 68 + .popsection