[v3] arm: Enable FPU for M-profile

Message ID 20260619130401.130409-1-christophe.lyon@arm.com
State New
Headers
Series [v3] arm: Enable FPU for M-profile |

Commit Message

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

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

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

	* libgloss/arm/cpu-init/rdimon-aem.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.S | 28 +++++++++++++++++++++++++---
 libgloss/arm/crt0.S                |  4 ++--
 2 files changed, 27 insertions(+), 5 deletions(-)
  

Comments

Richard Earnshaw June 22, 2026, 11:08 a.m. UTC | #1
On 19/06/2026 14:04, Christophe Lyon wrote:
> Before using the FPU, we must grant access to it.  This helps when
> running the GCC testsuite on a simluator where FPU access is not
> granted by default.
> 
> This patch grants full access, we may want to consider granting only
> unpriviledged access later.
> 
> 2026-05-29  Christophe Lyon  <christophe.lyon@arm.com>
> 
> 	* libgloss/arm/cpu-init/rdimon-aem.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.S | 28 +++++++++++++++++++++++++---
>   libgloss/arm/crt0.S                |  4 ++--
>   2 files changed, 27 insertions(+), 5 deletions(-)
> 
> diff --git a/libgloss/arm/cpu-init/rdimon-aem.S b/libgloss/arm/cpu-init/rdimon-aem.S
> index c960924d4..c8640632a 100644
> --- a/libgloss/arm/cpu-init/rdimon-aem.S
> +++ b/libgloss/arm/cpu-init/rdimon-aem.S
> @@ -25,9 +25,10 @@
>   
>   /* This file gives a basic initialisation of a Cortex-A series core.  It is
>      the bare minimum required to get Cortex-A core running with a semihosting
> -   interface.  For M-profile we only define a hardfault handler, required to
> -   prevent the simulator from entering into an infinite loop.  The comments
> -   below apply to A-profile only.
> +   interface.  For M-profile we define a hardfault handler, required to
> +   prevent the simulator from entering into an infinite loop and we enable
> +   the FPU when __ARM_FP is set.
> +   The comments below apply to A-profile only.
>   

Isn't this comment part of your other patch series?

>      It sets up a basic 1:1 phsyical address to virtual address mapping;
>      turns the MMU on; enables branch prediction; activates any integrated
> @@ -542,6 +543,27 @@ page_tables:
>        PT7(0x1c0e)
>   
>   #elif  (__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]
> +    dsb
> +    isb

What about the NS version of this register (@0xE002ED88) when starting 
in secure state?  Even if we don't want to set it here, I think we 
should note that in a comment and explain why.

> +#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.  */
>       .section .hardfault_handler_addr, "a"
> diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S
> index b9e768007..d355405e3 100644
> --- a/libgloss/arm/crt0.S
> +++ b/libgloss/arm/crt0.S
> @@ -253,9 +253,9 @@
>   	/* __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
> +	file to be built with older compilers.  We only call this for A and M profile
>   	cores.  */
> -#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A')
> +#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A') || (__ARM_ARCH_PROFILE == 'M')

We should include arm-acle-compat.h and drop the __ARM_ARCH_7A__ test now.

>   /*  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

R.
  
Christophe Lyon June 22, 2026, 1:40 p.m. UTC | #2
On 6/22/26 13:08, Richard Earnshaw wrote:
> On 19/06/2026 14:04, Christophe Lyon wrote:
>> Before using the FPU, we must grant access to it.  This helps when
>> running the GCC testsuite on a simluator where FPU access is not
>> granted by default.
>>
>> This patch grants full access, we may want to consider granting only
>> unpriviledged access later.
>>
>> 2026-05-29  Christophe Lyon  <christophe.lyon@arm.com>
>>
>>     * libgloss/arm/cpu-init/rdimon-aem.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.S | 28 +++++++++++++++++++++++++---
>>   libgloss/arm/crt0.S                |  4 ++--
>>   2 files changed, 27 insertions(+), 5 deletions(-)
>>
>> diff --git a/libgloss/arm/cpu-init/rdimon-aem.S b/libgloss/arm/cpu- 
>> init/rdimon-aem.S
>> index c960924d4..c8640632a 100644
>> --- a/libgloss/arm/cpu-init/rdimon-aem.S
>> +++ b/libgloss/arm/cpu-init/rdimon-aem.S
>> @@ -25,9 +25,10 @@
>>   /* This file gives a basic initialisation of a Cortex-A series 
>> core.  It is
>>      the bare minimum required to get Cortex-A core running with a 
>> semihosting
>> -   interface.  For M-profile we only define a hardfault handler, 
>> required to
>> -   prevent the simulator from entering into an infinite loop.  The 
>> comments
>> -   below apply to A-profile only.
>> +   interface.  For M-profile we define a hardfault handler, required to
>> +   prevent the simulator from entering into an infinite loop and we 
>> enable
>> +   the FPU when __ARM_FP is set.
>> +   The comments below apply to A-profile only.
> 
> Isn't this comment part of your other patch series?

The other patch adds the hardfault handler. This patch adds the code to 
enable the PFU, so it updates the comment accordingly.

> 
>>      It sets up a basic 1:1 phsyical address to virtual address mapping;
>>      turns the MMU on; enables branch prediction; activates any 
>> integrated
>> @@ -542,6 +543,27 @@ page_tables:
>>        PT7(0x1c0e)
>>   #elif  (__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]
>> +    dsb
>> +    isb
> 
> What about the NS version of this register (@0xE002ED88) when starting 
> in secure state?  Even if we don't want to set it here, I think we 
> should note that in a comment and explain why.

I didn't think of it.... TBH I have been using this code in a different 
context for a very long time, I wrote it before NS/S existed ;-)

So keep the above code unchanged and add something like
#if __ARM_ARCH >= 800
ldr    r0, =0xE020ED88
str    r1, [R0]
#endif

Not sure how to test it, though.

> 
>> +#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.  */
>>       .section .hardfault_handler_addr, "a"
>> diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S
>> index b9e768007..d355405e3 100644
>> --- a/libgloss/arm/crt0.S
>> +++ b/libgloss/arm/crt0.S
>> @@ -253,9 +253,9 @@
>>       /* __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
>> +    file to be built with older compilers.  We only call this for A 
>> and M profile
>>       cores.  */
>> -#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A')
>> +#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A') || 
>> (__ARM_ARCH_PROFILE == 'M')
> 
> We should include arm-acle-compat.h and drop the __ARM_ARCH_7A__ test now.

Ack

Thanks,

Christophe

> 
>>   /*  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
> 
> R.
  
Christophe Lyon June 24, 2026, 8:04 p.m. UTC | #3
I have sent an updated version as part of a new series (now 3 patches):
https://sourceware.org/pipermail/newlib/2026/022515.html

On 6/22/26 15:40, Christophe Lyon wrote:
> 
> 
> On 6/22/26 13:08, Richard Earnshaw wrote:
>> On 19/06/2026 14:04, Christophe Lyon wrote:
>>> Before using the FPU, we must grant access to it.  This helps when
>>> running the GCC testsuite on a simluator where FPU access is not
>>> granted by default.
>>>
>>> This patch grants full access, we may want to consider granting only
>>> unpriviledged access later.
>>>
>>> 2026-05-29  Christophe Lyon  <christophe.lyon@arm.com>
>>>
>>>     * libgloss/arm/cpu-init/rdimon-aem.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.S | 28 +++++++++++++++++++++++++---
>>>   libgloss/arm/crt0.S                |  4 ++--
>>>   2 files changed, 27 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/libgloss/arm/cpu-init/rdimon-aem.S b/libgloss/arm/cpu- 
>>> init/rdimon-aem.S
>>> index c960924d4..c8640632a 100644
>>> --- a/libgloss/arm/cpu-init/rdimon-aem.S
>>> +++ b/libgloss/arm/cpu-init/rdimon-aem.S
>>> @@ -25,9 +25,10 @@
>>>   /* This file gives a basic initialisation of a Cortex-A series 
>>> core.  It is
>>>      the bare minimum required to get Cortex-A core running with a 
>>> semihosting
>>> -   interface.  For M-profile we only define a hardfault handler, 
>>> required to
>>> -   prevent the simulator from entering into an infinite loop.  The 
>>> comments
>>> -   below apply to A-profile only.
>>> +   interface.  For M-profile we define a hardfault handler, required to
>>> +   prevent the simulator from entering into an infinite loop and we 
>>> enable
>>> +   the FPU when __ARM_FP is set.
>>> +   The comments below apply to A-profile only.
>>
>> Isn't this comment part of your other patch series?
> 
> The other patch adds the hardfault handler. This patch adds the code to 
> enable the PFU, so it updates the comment accordingly.
> 
>>
>>>      It sets up a basic 1:1 phsyical address to virtual address mapping;
>>>      turns the MMU on; enables branch prediction; activates any 
>>> integrated
>>> @@ -542,6 +543,27 @@ page_tables:
>>>        PT7(0x1c0e)
>>>   #elif  (__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]
>>> +    dsb
>>> +    isb
>>
>> What about the NS version of this register (@0xE002ED88) when starting 
>> in secure state?  Even if we don't want to set it here, I think we 
>> should note that in a comment and explain why.
> 
> I didn't think of it.... TBH I have been using this code in a different 
> context for a very long time, I wrote it before NS/S existed ;-)
> 
> So keep the above code unchanged and add something like
> #if __ARM_ARCH >= 800
> ldr    r0, =0xE020ED88
> str    r1, [R0]
> #endif
> 
> Not sure how to test it, though.
> 
>>
>>> +#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.  */
>>>       .section .hardfault_handler_addr, "a"
>>> diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S
>>> index b9e768007..d355405e3 100644
>>> --- a/libgloss/arm/crt0.S
>>> +++ b/libgloss/arm/crt0.S
>>> @@ -253,9 +253,9 @@
>>>       /* __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
>>> +    file to be built with older compilers.  We only call this for A 
>>> and M profile
>>>       cores.  */
>>> -#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A')
>>> +#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A') || 
>>> (__ARM_ARCH_PROFILE == 'M')
>>
>> We should include arm-acle-compat.h and drop the __ARM_ARCH_7A__ test 
>> now.
> 
> Ack
> 
> Thanks,
> 
> Christophe
> 
>>
>>>   /*  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
>>
>> R.
>
  

Patch

diff --git a/libgloss/arm/cpu-init/rdimon-aem.S b/libgloss/arm/cpu-init/rdimon-aem.S
index c960924d4..c8640632a 100644
--- a/libgloss/arm/cpu-init/rdimon-aem.S
+++ b/libgloss/arm/cpu-init/rdimon-aem.S
@@ -25,9 +25,10 @@ 
 
 /* This file gives a basic initialisation of a Cortex-A series core.  It is
    the bare minimum required to get Cortex-A core running with a semihosting
-   interface.  For M-profile we only define a hardfault handler, required to
-   prevent the simulator from entering into an infinite loop.  The comments
-   below apply to A-profile only.
+   interface.  For M-profile we define a hardfault handler, required to
+   prevent the simulator from entering into an infinite loop and we enable
+   the FPU when __ARM_FP is set.
+   The comments below apply to A-profile only.
 
    It sets up a basic 1:1 phsyical address to virtual address mapping;
    turns the MMU on; enables branch prediction; activates any integrated
@@ -542,6 +543,27 @@  page_tables:
      PT7(0x1c0e)
 
 #elif  (__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]
+    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.  */
     .section .hardfault_handler_addr, "a"
diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S
index b9e768007..d355405e3 100644
--- a/libgloss/arm/crt0.S
+++ b/libgloss/arm/crt0.S
@@ -253,9 +253,9 @@ 
 	/* __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
+	file to be built with older compilers.  We only call this for A and M profile
 	cores.  */
-#if defined (__ARM_ARCH_7A__) || (__ARM_ARCH_PROFILE == 'A')
+#if defined (__ARM_ARCH_7A__) || (__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