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

ARM: 8991/1: use VFP assembler mnemonics if available

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"
^
<inline asm>: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 <stefan@agner.ch>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

authored by

Stefan Agner and committed by
Russell King
2cbd1cc3 ee440336

+41 -5
+2
arch/arm/Kconfig
··· 2097 2097 if CRYPTO 2098 2098 source "arch/arm/crypto/Kconfig" 2099 2099 endif 2100 + 2101 + source "arch/arm/Kconfig.assembler"
+6
arch/arm/Kconfig.assembler
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + config AS_VFP_VMRS_FPINST 4 + def_bool $(as-instr,.fpu vfpv2\nvmrs r0$(comma)FPINST) 5 + help 6 + Supported by binutils >= 2.24 and LLVM integrated assembler.
+2
arch/arm/include/asm/vfp.h
··· 9 9 #ifndef __ASM_VFP_H 10 10 #define __ASM_VFP_H 11 11 12 + #ifndef CONFIG_AS_VFP_VMRS_FPINST 12 13 #define FPSID cr0 13 14 #define FPSCR cr1 14 15 #define MVFR1 cr6 ··· 17 16 #define FPEXC cr8 18 17 #define FPINST cr9 19 18 #define FPINST2 cr10 19 + #endif 20 20 21 21 /* FPSID bits */ 22 22 #define FPSID_IMPLEMENTER_BIT (24)
+11 -1
arch/arm/include/asm/vfpmacros.h
··· 8 8 9 9 #include <asm/vfp.h> 10 10 11 - @ Macros to allow building with old toolkits (with no VFP support) 11 + #ifdef CONFIG_AS_VFP_VMRS_FPINST 12 + .macro VFPFMRX, rd, sysreg, cond 13 + vmrs\cond \rd, \sysreg 14 + .endm 15 + 16 + .macro VFPFMXR, sysreg, rd, cond 17 + vmsr\cond \sysreg, \rd 18 + .endm 19 + #else 20 + @ Macros to allow building with old toolkits (with no VFP support) 12 21 .macro VFPFMRX, rd, sysreg, cond 13 22 MRC\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMRX \rd, \sysreg 14 23 .endm ··· 25 16 .macro VFPFMXR, sysreg, rd, cond 26 17 MCR\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMXR \sysreg, \rd 27 18 .endm 19 + #endif 28 20 29 21 @ read all the working registers back into the VFP 30 22 .macro VFPFLDMIA, base, tmp
+1
arch/arm/vfp/vfphw.S
··· 78 78 ENTRY(vfp_support_entry) 79 79 DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 80 80 81 + .fpu vfpv2 81 82 ldr r3, [sp, #S_PSR] @ Neither lazy restore nor FP exceptions 82 83 and r3, r3, #MODE_MASK @ are supported in kernel mode 83 84 teq r3, #USR_MODE
+19 -4
arch/arm/vfp/vfpinstr.h
··· 62 62 #define FPSCR_C (1 << 29) 63 63 #define FPSCR_V (1 << 28) 64 64 65 - /* 66 - * Since we aren't building with -mfpu=vfp, we need to code 67 - * these instructions using their MRC/MCR equivalents. 68 - */ 65 + #ifdef CONFIG_AS_VFP_VMRS_FPINST 66 + 67 + #define fmrx(_vfp_) ({ \ 68 + u32 __v; \ 69 + asm(".fpu vfpv2\n" \ 70 + "vmrs %0, " #_vfp_ \ 71 + : "=r" (__v) : : "cc"); \ 72 + __v; \ 73 + }) 74 + 75 + #define fmxr(_vfp_,_var_) \ 76 + asm(".fpu vfpv2\n" \ 77 + "vmsr " #_vfp_ ", %0" \ 78 + : : "r" (_var_) : "cc") 79 + 80 + #else 81 + 69 82 #define vfpreg(_vfp_) #_vfp_ 70 83 71 84 #define fmrx(_vfp_) ({ \ ··· 91 78 #define fmxr(_vfp_,_var_) \ 92 79 asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \ 93 80 : : "r" (_var_) : "cc") 81 + 82 + #endif 94 83 95 84 u32 vfp_single_cpdo(u32 inst, u32 fpscr); 96 85 u32 vfp_single_cprt(u32 inst, u32 fpscr, struct pt_regs *regs);