[v4,3/3] arm: Enable FPU for M-profile

Message ID 20260624195835.206509-3-christophe.lyon@arm.com
State New
Headers
Series [v4,1/3] libgloss: arm: Reorganize rdimon-aem.S |

Commit Message

Christophe Lyon June 24, 2026, 7:58 p.m. UTC
  Before using the FPU, we must grant access to it.  This helps when
running the GCC testsuite on a simulator where FPU access is not
granted by default.

This patch grants full access, we may want to consider granting only
unprivileged access later.

While updating crt0.S, include arm-acle-compat.h and stop using
__ARM_ARCH_7A__.

2026-05-29  Christophe Lyon  <christophe.lyon@arm.com>

	* libgloss/arm/cpu-init/rdimon-aem-m.S: Enable full FPU access on
	M-profile.
	* libgloss/arm/crt0.S: Call _rdimon_hw_init_hook for M profile
	too.
---
 libgloss/arm/cpu-init/rdimon-aem-m.S | 29 +++++++++++++++++++++++++++-
 libgloss/arm/crt0.S                  |  9 +++------
 2 files changed, 31 insertions(+), 7 deletions(-)
  

Comments

Torbjorn SVENSSON June 25, 2026, 7:08 p.m. UTC | #1
On 2026-06-24 21:58, Christophe Lyon wrote:
> Before using the FPU, we must grant access to it.  This helps when
> running the GCC testsuite on a simulator where FPU access is not
> granted by default.
> 
> This patch grants full access, we may want to consider granting only
> unprivileged access later.
> 
> While updating crt0.S, include arm-acle-compat.h and stop using
> __ARM_ARCH_7A__.
> 
> 2026-05-29  Christophe Lyon  <christophe.lyon@arm.com>
> 
> 	* libgloss/arm/cpu-init/rdimon-aem-m.S: Enable full FPU access on
> 	M-profile.
> 	* libgloss/arm/crt0.S: Call _rdimon_hw_init_hook for M profile
> 	too.
> ---
>   libgloss/arm/cpu-init/rdimon-aem-m.S | 29 +++++++++++++++++++++++++++-
>   libgloss/arm/crt0.S                  |  9 +++------
>   2 files changed, 31 insertions(+), 7 deletions(-)
> 
> diff --git a/libgloss/arm/cpu-init/rdimon-aem-m.S b/libgloss/arm/cpu-init/rdimon-aem-m.S
> index 611849077..c495efc2d 100644
> --- a/libgloss/arm/cpu-init/rdimon-aem-m.S
> +++ b/libgloss/arm/cpu-init/rdimon-aem-m.S
> @@ -28,9 +28,36 @@
>      We define a hardfault handler, required to prevent the simulator
>      from entering into an infinite loop.  This handler is located at
>      address 0xc by default when linking with mprofile-mps2.specs which
> -   uses --section-start=.hardfault_handler_addr=0xc.  */
> +   uses --section-start=.hardfault_handler_addr=0xc.
> +
> +   Enable the FPU when __ARM_FP is set.  */
>   
>   #if  (__ARM_ARCH_PROFILE == 'M')
> +    .syntax    unified
> +    .thumb
> +
> +    @ CPU Initialisation
> +    .globl     _rdimon_hw_init_hook
> +    .type      _rdimon_hw_init_hook, %function
> +
> +_rdimon_hw_init_hook:
> +    /* Enable FPU for M-profile only .  */
> +#if __ARM_FP
> +    /* Read CPACR */
> +    ldr        r0, =0xE000ED88
> +    ldr        r1, [R0]
> +    /* Enable full access to CP10 and CP11.  */
> +    orr        r1, r1, #(0xFF << 20)
> +    str        r1, [R0]
> +#if __ARM_ARCH >= 800
> +    ldr        r0, =0xE002ED88
> +    str        r1, [R0]

Is this okay to do?
Are we sure that this rdimon-aem-m.S is never included in a non-secure application? What happens if it is included in a non-secure application, secure fault?

Kind regards,
Torbjörn

> +#endif
> +    dsb
> +    isb
> +#endif
> +    bx lr
> +
>       /* On M-profile, call abort in case of hardfault: this causes the
>          simulator to abort execution instead of going into an infinite
>          loop.  */
> diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S
> index b9e768007..cad002d2b 100644
> --- a/libgloss/arm/crt0.S
> +++ b/libgloss/arm/crt0.S
> @@ -1,6 +1,7 @@
>   #include "newlib.h"
>   #include "arm.h"
>   #include "swi.h"
> +#include "arm-acle-compat.h"
>   
>   /* ANSI concatenation macros.  */
>   #define CONCAT(a, b) CONCAT2(a, b)
> @@ -250,12 +251,8 @@
>   	FUNC_START	_start
>   	FN_EH_START
>   
> -	/* __ARM_ARCH_PROFILE is defined from GCC 4.8 onwards, however __ARM_ARCH_7A
> -	has been defined since 4.2 onwards, which is when v7-a support was added
> -	and hence 'A' profile support was added in the compiler.  Allow for this
> -	file to be built with older compilers.  We only call this for A profile
> -	cores.  */
> -#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A')
> +	/* We only call this for A and M profile cores.  */
> +#if (__ARM_ARCH_PROFILE == 'A') || (__ARM_ARCH_PROFILE == 'M')
>   /*  The init hook does not use the stack and is called before the stack has been set up.  */
>   #ifdef ARM_RDI_MONITOR
>   	bl	_rdimon_hw_init_hook
  
Christophe Lyon June 30, 2026, 9:52 a.m. UTC | #2
On 6/25/26 21:08, Torbjorn SVENSSON wrote:
> 
> 
> On 2026-06-24 21:58, Christophe Lyon wrote:
>> Before using the FPU, we must grant access to it.  This helps when
>> running the GCC testsuite on a simulator where FPU access is not
>> granted by default.
>>
>> This patch grants full access, we may want to consider granting only
>> unprivileged access later.
>>
>> While updating crt0.S, include arm-acle-compat.h and stop using
>> __ARM_ARCH_7A__.
>>
>> 2026-05-29  Christophe Lyon  <christophe.lyon@arm.com>
>>
>>     * libgloss/arm/cpu-init/rdimon-aem-m.S: Enable full FPU access on
>>     M-profile.
>>     * libgloss/arm/crt0.S: Call _rdimon_hw_init_hook for M profile
>>     too.
>> ---
>>   libgloss/arm/cpu-init/rdimon-aem-m.S | 29 +++++++++++++++++++++++++++-
>>   libgloss/arm/crt0.S                  |  9 +++------
>>   2 files changed, 31 insertions(+), 7 deletions(-)
>>
>> diff --git a/libgloss/arm/cpu-init/rdimon-aem-m.S b/libgloss/arm/cpu- 
>> init/rdimon-aem-m.S
>> index 611849077..c495efc2d 100644
>> --- a/libgloss/arm/cpu-init/rdimon-aem-m.S
>> +++ b/libgloss/arm/cpu-init/rdimon-aem-m.S
>> @@ -28,9 +28,36 @@
>>      We define a hardfault handler, required to prevent the simulator
>>      from entering into an infinite loop.  This handler is located at
>>      address 0xc by default when linking with mprofile-mps2.specs which
>> -   uses --section-start=.hardfault_handler_addr=0xc.  */
>> +   uses --section-start=.hardfault_handler_addr=0xc.
>> +
>> +   Enable the FPU when __ARM_FP is set.  */
>>   #if  (__ARM_ARCH_PROFILE == 'M')
>> +    .syntax    unified
>> +    .thumb
>> +
>> +    @ CPU Initialisation
>> +    .globl     _rdimon_hw_init_hook
>> +    .type      _rdimon_hw_init_hook, %function
>> +
>> +_rdimon_hw_init_hook:
>> +    /* Enable FPU for M-profile only .  */
>> +#if __ARM_FP
>> +    /* Read CPACR */
>> +    ldr        r0, =0xE000ED88
>> +    ldr        r1, [R0]
>> +    /* Enable full access to CP10 and CP11.  */
>> +    orr        r1, r1, #(0xFF << 20)
>> +    str        r1, [R0]
>> +#if __ARM_ARCH >= 800
>> +    ldr        r0, =0xE002ED88
>> +    str        r1, [R0]
> 
> Is this okay to do?
> Are we sure that this rdimon-aem-m.S is never included in a non-secure 
> application? What happens if it is included in a non-secure application, 
> secure fault?
> 

Hi Torbjorn,

We can't quite ever be sure of how bootcode is used, the onus is on the 
developer to make sure they have the appropriate bootcode for their 
application. To be clear, this bootcode is only used when the user 
specifies --specs=mprofile-mps2.specs.

The fact is that all M-profile cores boot in a mode for which, if FP is 
present, the registers we write to here are accessible, regardless of 
whether CMSE is available or not.  In other words, the more general 
use-case for AEM models emulating MPS2 M-profile CPUs is covered.

The only concern is if a user uses this bootcode to build an image that 
is loaded onto non-secure memory, with FPU enabled. In that case there 
HAS to be another image that is loaded onto secure and calls into the 
entry point for the non-secure image, it also requires some setup on the 
secure side for the non-secure code to boot. All this requires a 
non-standard linker script and more complex bootcode. All this to say, 
the user needs to be well aware of what they are doing and they should 
know not to use this bootcode for that scenario as it will never work.

One could also argue that this bootcode is used when the user specifies 
--specs=aprofile*.specs but is actually targeting M-profile: again, the 
user needs to be aware of what they are doing.

Thanks,

Christophe


> Kind regards,
> Torbjörn
> 
>> +#endif
>> +    dsb
>> +    isb
>> +#endif
>> +    bx lr
>> +
>>       /* On M-profile, call abort in case of hardfault: this causes the
>>          simulator to abort execution instead of going into an infinite
>>          loop.  */
>> diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S
>> index b9e768007..cad002d2b 100644
>> --- a/libgloss/arm/crt0.S
>> +++ b/libgloss/arm/crt0.S
>> @@ -1,6 +1,7 @@
>>   #include "newlib.h"
>>   #include "arm.h"
>>   #include "swi.h"
>> +#include "arm-acle-compat.h"
>>   /* ANSI concatenation macros.  */
>>   #define CONCAT(a, b) CONCAT2(a, b)
>> @@ -250,12 +251,8 @@
>>       FUNC_START    _start
>>       FN_EH_START
>> -    /* __ARM_ARCH_PROFILE is defined from GCC 4.8 onwards, however 
>> __ARM_ARCH_7A
>> -    has been defined since 4.2 onwards, which is when v7-a support 
>> was added
>> -    and hence 'A' profile support was added in the compiler.  Allow 
>> for this
>> -    file to be built with older compilers.  We only call this for A 
>> profile
>> -    cores.  */
>> -#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A')
>> +    /* We only call this for A and M profile cores.  */
>> +#if (__ARM_ARCH_PROFILE == 'A') || (__ARM_ARCH_PROFILE == 'M')
>>   /*  The init hook does not use the stack and is called before the 
>> stack has been set up.  */
>>   #ifdef ARM_RDI_MONITOR
>>       bl    _rdimon_hw_init_hook
>
  

Patch

diff --git a/libgloss/arm/cpu-init/rdimon-aem-m.S b/libgloss/arm/cpu-init/rdimon-aem-m.S
index 611849077..c495efc2d 100644
--- a/libgloss/arm/cpu-init/rdimon-aem-m.S
+++ b/libgloss/arm/cpu-init/rdimon-aem-m.S
@@ -28,9 +28,36 @@ 
    We define a hardfault handler, required to prevent the simulator
    from entering into an infinite loop.  This handler is located at
    address 0xc by default when linking with mprofile-mps2.specs which
-   uses --section-start=.hardfault_handler_addr=0xc.  */
+   uses --section-start=.hardfault_handler_addr=0xc.
+
+   Enable the FPU when __ARM_FP is set.  */
 
 #if  (__ARM_ARCH_PROFILE == 'M')
+    .syntax    unified
+    .thumb
+
+    @ CPU Initialisation
+    .globl     _rdimon_hw_init_hook
+    .type      _rdimon_hw_init_hook, %function
+
+_rdimon_hw_init_hook:
+    /* Enable FPU for M-profile only .  */
+#if __ARM_FP
+    /* Read CPACR */
+    ldr        r0, =0xE000ED88
+    ldr        r1, [R0]
+    /* Enable full access to CP10 and CP11.  */
+    orr        r1, r1, #(0xFF << 20)
+    str        r1, [R0]
+#if __ARM_ARCH >= 800
+    ldr        r0, =0xE002ED88
+    str        r1, [R0]
+#endif
+    dsb
+    isb
+#endif
+    bx lr
+
     /* On M-profile, call abort in case of hardfault: this causes the
        simulator to abort execution instead of going into an infinite
        loop.  */
diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S
index b9e768007..cad002d2b 100644
--- a/libgloss/arm/crt0.S
+++ b/libgloss/arm/crt0.S
@@ -1,6 +1,7 @@ 
 #include "newlib.h"
 #include "arm.h"
 #include "swi.h"
+#include "arm-acle-compat.h"
 
 /* ANSI concatenation macros.  */
 #define CONCAT(a, b) CONCAT2(a, b)
@@ -250,12 +251,8 @@ 
 	FUNC_START	_start
 	FN_EH_START
 
-	/* __ARM_ARCH_PROFILE is defined from GCC 4.8 onwards, however __ARM_ARCH_7A
-	has been defined since 4.2 onwards, which is when v7-a support was added
-	and hence 'A' profile support was added in the compiler.  Allow for this
-	file to be built with older compilers.  We only call this for A profile
-	cores.  */
-#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A')
+	/* We only call this for A and M profile cores.  */
+#if (__ARM_ARCH_PROFILE == 'A') || (__ARM_ARCH_PROFILE == 'M')
 /*  The init hook does not use the stack and is called before the stack has been set up.  */
 #ifdef ARM_RDI_MONITOR
 	bl	_rdimon_hw_init_hook