Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59cbcdb5 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

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: default avatarChristoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent c0c2cdbf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,3 +6,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
obj-$(CONFIG_KVM_ARM_HOST) += cp15-sr.o
obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
obj-$(CONFIG_KVM_ARM_HOST) += vfp.o
+13 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/compiler.h>
#include <linux/kvm_host.h>
#include <asm/kvm_mmu.h>
#include <asm/vfp.h>

#define __hyp_text __section(.hyp.text) notrace

@@ -31,6 +32,8 @@
	"mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32
#define __ACCESS_CP15_64(Op1, CRm)		\
	"mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64
#define __ACCESS_VFP(CRn)			\
	"mrc", "mcr", __stringify(p10, 7, %0, CRn, cr0, 0), u32

#define __write_sysreg(v, r, w, c, t)	asm volatile(w " " c : : "r" ((t)(v)))
#define write_sysreg(v, ...)		__write_sysreg(v, __VA_ARGS__)
@@ -53,6 +56,7 @@
#define VMPIDR		__ACCESS_CP15(c0, 4, c0, 5)
#define SCTLR		__ACCESS_CP15(c1, 0, c0, 0)
#define CPACR		__ACCESS_CP15(c1, 0, c0, 2)
#define HCPTR		__ACCESS_CP15(c1, 4, c1, 2)
#define TTBCR		__ACCESS_CP15(c2, 0, c0, 2)
#define DACR		__ACCESS_CP15(c3, 0, c0, 0)
#define DFSR		__ACCESS_CP15(c5, 0, c0, 0)
@@ -77,6 +81,8 @@
#define CNTV_CTL	__ACCESS_CP15(c14, 0, c3, 1)
#define CNTHCTL		__ACCESS_CP15(c14, 4, c1, 0)

#define VFP_FPEXC	__ACCESS_VFP(FPEXC)

void __timer_save_state(struct kvm_vcpu *vcpu);
void __timer_restore_state(struct kvm_vcpu *vcpu);

@@ -86,4 +92,11 @@ void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
void __sysreg_save_state(struct kvm_cpu_context *ctxt);
void __sysreg_restore_state(struct kvm_cpu_context *ctxt);

void asmlinkage __vfp_save_state(struct vfp_hard_struct *vfp);
void asmlinkage __vfp_restore_state(struct vfp_hard_struct *vfp);
static inline bool __vfp_enabled(void)
{
	return !(read_sysreg(HCPTR) & (HCPTR_TCP(11) | HCPTR_TCP(10)));
}

#endif /* __ARM_KVM_HYP_H__ */

arch/arm/kvm/hyp/vfp.S

0 → 100644
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 - Virtual Open Systems and Columbia University
 * Author: Christoffer Dall <c.dall@virtualopensystems.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/linkage.h>
#include <asm/vfpmacros.h>

	.text
	.pushsection	.hyp.text, "ax"

/* void __vfp_save_state(struct vfp_hard_struct *vfp); */
ENTRY(__vfp_save_state)
	push	{r4, r5}
	VFPFMRX	r1, FPEXC

	@ Make sure *really* VFP is enabled so we can touch the registers.
	orr	r5, r1, #FPEXC_EN
	tst	r5, #FPEXC_EX		@ Check for VFP Subarchitecture
	bic	r5, r5, #FPEXC_EX	@ FPEXC_EX disable
	VFPFMXR	FPEXC, r5
	isb

	VFPFMRX	r2, FPSCR
	beq	1f

	@ If FPEXC_EX is 0, then FPINST/FPINST2 reads are upredictable, so
	@ we only need to save them if FPEXC_EX is set.
	VFPFMRX r3, FPINST
	tst	r5, #FPEXC_FP2V
	VFPFMRX r4, FPINST2, ne		@ vmrsne
1:
	VFPFSTMIA r0, r5		@ Save VFP registers
	stm	r0, {r1-r4}		@ Save FPEXC, FPSCR, FPINST, FPINST2
	pop	{r4, r5}
	bx	lr
ENDPROC(__vfp_save_state)

/* void __vfp_restore_state(struct vfp_hard_struct *vfp);
 * Assume FPEXC_EN is on and FPEXC_EX is off */
ENTRY(__vfp_restore_state)
	VFPFLDMIA r0, r1		@ Load VFP registers
	ldm	r0, {r0-r3}		@ Load FPEXC, FPSCR, FPINST, FPINST2

	VFPFMXR FPSCR, r1
	tst	r0, #FPEXC_EX		@ Check for VFP Subarchitecture
	beq	1f
	VFPFMXR FPINST, r2
	tst	r0, #FPEXC_FP2V
	VFPFMXR FPINST2, r3, ne
1:
	VFPFMXR FPEXC, r0		@ FPEXC	(last, in case !EN)
	bx	lr
ENDPROC(__vfp_restore_state)

	.popsection