Skip to content

Commit

Permalink
BACKPORT: ARM: 8991/1: use VFP assembler mnemonics if available
Browse files Browse the repository at this point in the history
commit 2cbd1cc 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"
            ^
<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: ClangBuiltLinux/linux#905

Signed-off-by: Stefan Agner <[email protected]>
Change-Id: Ibe43b4f40e924759f9a6bca4a7a7ae7cea473077
Signed-off-by: Russell King <[email protected]>
[nd: Adjusted hunk from arch/arm/Kconfig due to missing
     commit 8a90a32 ("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 541ad01 ("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 a47b395 ("ARM: 9030/1: entry: omit FP emulation for UND
     exceptions taken in kernel mode").]
Bug: 141693040
Signed-off-by: Nick Desaulniers <[email protected]>
(cherry picked from commit 5208d4f)
Signed-off-by: TogoFire <[email protected]>
  • Loading branch information
agners authored and TogoFire committed May 19, 2024
1 parent f0fd8f7 commit 5ccca9c
Show file tree
Hide file tree
Showing 12 changed files with 48 additions and 14 deletions.
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2167,3 +2167,4 @@ source "arch/arm/crypto/Kconfig"
endif

source "arch/arm/kvm/Kconfig"
source "arch/arm/Kconfig.assembler"
6 changes: 6 additions & 0 deletions arch/arm/Kconfig.assembler
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 0 additions & 5 deletions arch/arm/include/asm/kvm_hyp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) ({ \
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/include/asm/vfp.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
#ifndef __ASM_VFP_H
#define __ASM_VFP_H

#ifndef CONFIG_AS_VFP_VMRS_FPINST
#define FPSID cr0
#define FPSCR cr1
#define MVFR1 cr6
#define MVFR0 cr7
#define FPEXC cr8
#define FPINST cr9
#define FPINST2 cr10
#endif

/* FPSID bits */
#define FPSID_IMPLEMENTER_BIT (24)
Expand Down
12 changes: 11 additions & 1 deletion arch/arm/include/asm/vfpmacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,24 @@

#include <asm/vfp.h>

@ 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

.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
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions arch/arm/kvm/hyp/switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <asm/kvm_asm.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_mmu.h>
#include "../../vfp/vfpinstr.h"

__asm__(".arch_extension virt");

Expand All @@ -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();
}

Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions arch/arm/kvm/hyp/vfp.S
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <asm/vfpmacros.h>

.text
.fpu vfpv2
.pushsection .hyp.text, "ax"

/* void __vfp_save_state(struct vfp_hard_struct *vfp); */
Expand Down
1 change: 1 addition & 0 deletions arch/arm/kvm/init.S
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
*/

.text
.arch_extension virt
.pushsection .hyp.idmap.text,"ax"
.align 5
__kvm_hyp_init:
Expand Down
1 change: 1 addition & 0 deletions arch/arm/kvm/interrupts.S
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/linkage.h>

.text
.arch_extension virt

/********************************************************************
* Call function in Hyp mode
Expand Down
1 change: 1 addition & 0 deletions arch/arm/vfp/vfphw.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 19 additions & 4 deletions arch/arm/vfp/vfpinstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_) ({ \
Expand All @@ -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);

Expand Down

0 comments on commit 5ccca9c

Please sign in to comment.