From 191870e16d730be4d8679b5e97db5c849b24a82e Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 9 Jul 2020 11:21:27 +0100 Subject: [PATCH] BACKPORT: ARM: 8991/1: use VFP assembler mnemonics if available commit 2cbd1cc3dcd3e84be1fc1987da24b190ddf24a70 upstream. The integrated assembler of Clang 10 and earlier do not allow to access the VFP registers through the coprocessor load/store instructions: arch/arm/vfp/vfpmodule.c:342:2: error: invalid operand for instruction fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK)); ^ arch/arm/vfp/vfpinstr.h:79:6: note: expanded from macro 'fmxr' asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" ^ :1:6: note: instantiated into assembly here mcr p10, 7, r0, cr8, cr0, 0 @ fmxr FPEXC, r0 ^ This has been addressed with Clang 11 [0]. However, to support earlier versions of Clang and for better readability use of VFP assembler mnemonics still is preferred. Ideally we would replace this code with the unified assembler language mnemonics vmrs/vmsr on call sites along with .fpu assembler directives. The GNU assembler supports the .fpu directive at least since 2.17 (when documentation has been added). Since Linux requires binutils 2.21 it is safe to use .fpu directive. However, binutils does not allow to use FPINST or FPINST2 as an argument to vmrs/vmsr instructions up to binutils 2.24 (see binutils commit 16d02dc907c5): arch/arm/vfp/vfphw.S: Assembler messages: arch/arm/vfp/vfphw.S:162: Error: operand 0 must be FPSID or FPSCR pr FPEXC -- `vmsr FPINST,r6' arch/arm/vfp/vfphw.S:165: Error: operand 0 must be FPSID or FPSCR pr FPEXC -- `vmsr FPINST2,r8' arch/arm/vfp/vfphw.S:235: Error: operand 1 must be a VFP extension System Register -- `vmrs r3,FPINST' arch/arm/vfp/vfphw.S:238: Error: operand 1 must be a VFP extension System Register -- `vmrs r12,FPINST2' Use as-instr in Kconfig to check if FPINST/FPINST2 can be used. If they can be used make use of .fpu directives and UAL VFP mnemonics for register access. This allows to build vfpmodule.c with Clang and its integrated assembler. [0] https://reviews.llvm.org/D59733 Link: https://github.com/ClangBuiltLinux/linux/issues/905 Signed-off-by: Stefan Agner Change-Id: Id03aac1781c4ff992c87d696cd9b3e8b9716505b Signed-off-by: Russell King [nd: Adjusted hunk from arch/arm/Kconfig due to missing commit 8a90a3228b6a ("arm: Unplug KVM from the build system"). Replace __ACCESS_VFP with fmrx/fmxr for arch/arm/kvm/switch.c. CONFIG_KVM was removed in commit 541ad0150ca4 ("arm: Remove 32bit KVM host support") in v5.7.1. CONFIG_KVM is not enabled as part of allmodconfig or alldefconfig, but axm55xx_defconfig explicitly does enable it. Adjusted arch/arm/vfp/vfphw.S due to conflict with commit a47b395d441d ("ARM: 9030/1: entry: omit FP emulation for UND exceptions taken in kernel mode").] Bug: 141693040 Signed-off-by: Nick Desaulniers (cherry picked from commit 5208d4f108cff264abc2cc968c3c91d76e08a301) Signed-off-by: TogoFire --- arch/arm/Kconfig | 1 + arch/arm/Kconfig.assembler | 6 ++++++ arch/arm/include/asm/kvm_hyp.h | 5 ----- arch/arm/include/asm/vfp.h | 2 ++ arch/arm/include/asm/vfpmacros.h | 12 +++++++++++- arch/arm/kvm/Makefile | 2 +- arch/arm/kvm/hyp/switch.c | 7 ++++--- arch/arm/kvm/hyp/vfp.S | 1 + arch/arm/kvm/init.S | 1 + arch/arm/kvm/interrupts.S | 1 + arch/arm/vfp/vfphw.S | 1 + arch/arm/vfp/vfpinstr.h | 23 +++++++++++++++++++---- 12 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 arch/arm/Kconfig.assembler diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2e6cd7abed6ef..6ebd99010f0e3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2167,3 +2167,4 @@ source "arch/arm/crypto/Kconfig" endif source "arch/arm/kvm/Kconfig" +source "arch/arm/Kconfig.assembler" diff --git a/arch/arm/Kconfig.assembler b/arch/arm/Kconfig.assembler new file mode 100644 index 0000000000000..5cb31aae1188b --- /dev/null +++ b/arch/arm/Kconfig.assembler @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +config AS_VFP_VMRS_FPINST + def_bool $(as-instr,.fpu vfpv2\nvmrs r0$(comma)FPINST) + help + Supported by binutils >= 2.24 and LLVM integrated assembler. diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h index 40e9034db6013..316320684ea7d 100644 --- a/arch/arm/include/asm/kvm_hyp.h +++ b/arch/arm/include/asm/kvm_hyp.h @@ -14,9 +14,6 @@ #define __hyp_text __section(.hyp.text) notrace -#define __ACCESS_VFP(CRn) \ - "mrc", "mcr", __stringify(p10, 7, %0, CRn, cr0, 0), u32 - #define write_special(v, r) \ asm volatile("msr " __stringify(r) ", %0" : : "r" (v)) #define read_special(r) ({ \ @@ -79,8 +76,6 @@ #define CNTV_CTL __ACCESS_CP15(c14, 0, c3, 1) #define CNTHCTL __ACCESS_CP15(c14, 4, c1, 0) -#define VFP_FPEXC __ACCESS_VFP(FPEXC) - /* AArch64 compatibility macros, only for the timer so far */ #define read_sysreg_el0(r) read_sysreg(r##_EL0) #define write_sysreg_el0(v, r) write_sysreg(v, r##_EL0) diff --git a/arch/arm/include/asm/vfp.h b/arch/arm/include/asm/vfp.h index 7157d2a30a49d..19928bfb4f9cd 100644 --- a/arch/arm/include/asm/vfp.h +++ b/arch/arm/include/asm/vfp.h @@ -9,6 +9,7 @@ #ifndef __ASM_VFP_H #define __ASM_VFP_H +#ifndef CONFIG_AS_VFP_VMRS_FPINST #define FPSID cr0 #define FPSCR cr1 #define MVFR1 cr6 @@ -16,6 +17,7 @@ #define FPEXC cr8 #define FPINST cr9 #define FPINST2 cr10 +#endif /* FPSID bits */ #define FPSID_IMPLEMENTER_BIT (24) diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index 947ee5395e1fb..ba0d4cb5377e0 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h @@ -8,7 +8,16 @@ #include -@ Macros to allow building with old toolkits (with no VFP support) +#ifdef CONFIG_AS_VFP_VMRS_FPINST + .macro VFPFMRX, rd, sysreg, cond + vmrs\cond \rd, \sysreg + .endm + + .macro VFPFMXR, sysreg, rd, cond + vmsr\cond \sysreg, \rd + .endm +#else + @ Macros to allow building with old toolkits (with no VFP support) .macro VFPFMRX, rd, sysreg, cond MRC\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMRX \rd, \sysreg .endm @@ -16,6 +25,7 @@ .macro VFPFMXR, sysreg, rd, cond MCR\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMXR \sysreg, \rd .endm +#endif @ read all the working registers back into the VFP .macro VFPFLDMIA, base, tmp diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile index b76b75bd9e005..5df9dbd5bf207 100644 --- a/arch/arm/kvm/Makefile +++ b/arch/arm/kvm/Makefile @@ -3,7 +3,7 @@ # Makefile for Kernel-based Virtual Machine module # -plus_virt := $(call as-instr,.arch_extension virt,+virt) +plus_virt := $(call as-instr,".cpu cortex-a7\n\n.arch_extension virt",+virt) ifeq ($(plus_virt),+virt) plus_virt_def := -DREQUIRES_VIRT=1 endif diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c index 1efeef3fd0ee9..f5b27694ece28 100644 --- a/arch/arm/kvm/hyp/switch.c +++ b/arch/arm/kvm/hyp/switch.c @@ -8,6 +8,7 @@ #include #include #include +#include "../../vfp/vfpinstr.h" __asm__(".arch_extension virt"); @@ -26,10 +27,10 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu, u32 *fpexc_host) * trap to SVC. Therefore, always make sure that for 32-bit guests, * we set FPEXC.EN to prevent traps to SVC, when setting the TCP bits. */ - val = read_sysreg(VFP_FPEXC); + val = fmrx(FPEXC); *fpexc_host = val; if (!(val & FPEXC_EN)) { - write_sysreg(val | FPEXC_EN, VFP_FPEXC); + fmxr(FPEXC, val | FPEXC_EN); isb(); } @@ -196,7 +197,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu) __vfp_restore_state(&host_ctxt->vfp); } - write_sysreg(fpexc, VFP_FPEXC); + fmxr(FPEXC, fpexc); return exit_code; } diff --git a/arch/arm/kvm/hyp/vfp.S b/arch/arm/kvm/hyp/vfp.S index 675a52348d8dc..0870dfe93e939 100644 --- a/arch/arm/kvm/hyp/vfp.S +++ b/arch/arm/kvm/hyp/vfp.S @@ -8,6 +8,7 @@ #include .text + .fpu vfpv2 .pushsection .hyp.text, "ax" /* void __vfp_save_state(struct vfp_hard_struct *vfp); */ diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S index 33e34b6d24b24..4a8b25f3a6b64 100644 --- a/arch/arm/kvm/init.S +++ b/arch/arm/kvm/init.S @@ -35,6 +35,7 @@ */ .text + .arch_extension virt .pushsection .hyp.idmap.text,"ax" .align 5 __kvm_hyp_init: diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S index 064f4f118ca73..76416521e06b5 100644 --- a/arch/arm/kvm/interrupts.S +++ b/arch/arm/kvm/interrupts.S @@ -7,6 +7,7 @@ #include .text + .arch_extension virt /******************************************************************** * Call function in Hyp mode diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 772c6a3b1f724..d5837bf05a9a5 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -78,6 +78,7 @@ ENTRY(vfp_support_entry) DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 + .fpu vfpv2 VFPFMRX r1, FPEXC @ Is the VFP enabled? DBGSTR1 "fpexc %08x", r1 tst r1, #FPEXC_EN diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h index 38dc154e39ffc..3c7938fd40aad 100644 --- a/arch/arm/vfp/vfpinstr.h +++ b/arch/arm/vfp/vfpinstr.h @@ -62,10 +62,23 @@ #define FPSCR_C (1 << 29) #define FPSCR_V (1 << 28) -/* - * Since we aren't building with -mfpu=vfp, we need to code - * these instructions using their MRC/MCR equivalents. - */ +#ifdef CONFIG_AS_VFP_VMRS_FPINST + +#define fmrx(_vfp_) ({ \ + u32 __v; \ + asm(".fpu vfpv2\n" \ + "vmrs %0, " #_vfp_ \ + : "=r" (__v) : : "cc"); \ + __v; \ + }) + +#define fmxr(_vfp_,_var_) \ + asm(".fpu vfpv2\n" \ + "vmsr " #_vfp_ ", %0" \ + : : "r" (_var_) : "cc") + +#else + #define vfpreg(_vfp_) #_vfp_ #define fmrx(_vfp_) ({ \ @@ -79,6 +92,8 @@ asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \ : : "r" (_var_) : "cc") +#endif + u32 vfp_single_cpdo(u32 inst, u32 fpscr); u32 vfp_single_cprt(u32 inst, u32 fpscr, struct pt_regs *regs);