Skip to content

Commit e22d8bb

Browse files
oyvindronningstadmbolivar-nordic
authored andcommitted
[nrf fromtree] tfm: Put saving of FPU context into its own file so ...
... it can be reused Also, this eases readability. The new API can be used any time all FP registers must be manually saved and restored for an operation. This also fixes a bug where the FPU context was not restored correctly. The first 16 register values were restored into the last 16 registers as well. Signed-off-by: Øyvind Rønningstad <[email protected]> (cherry picked from commit b75c7d4)
1 parent a53f4eb commit e22d8bb

File tree

4 files changed

+95
-44
lines changed

4 files changed

+95
-44
lines changed

arch/arm/core/aarch32/cortex_m/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ zephyr_library_sources(
88
fault_s.S
99
fault.c
1010
exc_exit.S
11+
fpu.c
1112
scb.c
1213
irq_init.c
1314
thread_abort.c

arch/arm/core/aarch32/cortex_m/fpu.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2019,2020 Linaro Limited
3+
* Copyright (c) 2021 Nordic Semiconductor ASA
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <kernel.h>
9+
#include <arch/arm/aarch32/cortex_m/cmsis.h>
10+
#include <arch/arm/aarch32/cortex_m/fpu.h>
11+
12+
/**
13+
* @file @brief Helper functions for saving and restoring the FP context.
14+
*
15+
*/
16+
17+
void z_arm_save_fp_context(struct fpu_ctx_full *buffer)
18+
{
19+
#if defined(CONFIG_FPU_SHARING)
20+
__ASSERT_NO_MSG(buffer != NULL);
21+
22+
uint32_t CONTROL = __get_CONTROL();
23+
24+
if (CONTROL & CONTROL_FPCA_Msk) {
25+
/* Store caller-saved and callee-saved FP registers. */
26+
__asm__ volatile(
27+
"vstmia %0, {s0-s15}\n"
28+
"vstmia %1, {s16-s31}\n"
29+
:: "r" (buffer->caller_saved), "r" (buffer->callee_saved) :
30+
);
31+
32+
buffer->fpscr = __get_FPSCR();
33+
buffer->ctx_saved = true;
34+
35+
/* Disable FPCA so no stacking of FP registers happens in TFM. */
36+
__set_CONTROL(CONTROL & ~CONTROL_FPCA_Msk);
37+
38+
/* ISB is recommended after setting CONTROL. It's not needed
39+
* here though, since FPCA should have no impact on instruction
40+
* fetching.
41+
*/
42+
}
43+
#endif
44+
}
45+
46+
void z_arm_restore_fp_context(const struct fpu_ctx_full *buffer)
47+
{
48+
#if defined(CONFIG_FPU_SHARING)
49+
if (buffer->ctx_saved) {
50+
/* Set FPCA first so it is set even if an interrupt happens
51+
* during restoration.
52+
*/
53+
__set_CONTROL(__get_CONTROL() | CONTROL_FPCA_Msk);
54+
55+
/* Restore FP state. */
56+
__set_FPSCR(buffer->fpscr);
57+
58+
__asm__ volatile(
59+
"vldmia %0, {s0-s15}\n"
60+
"vldmia %1, {s16-s31}\n"
61+
:: "r" (buffer->caller_saved), "r" (buffer->callee_saved) :
62+
);
63+
}
64+
#endif
65+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2021, Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_
8+
#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_
9+
10+
struct fpu_ctx_full {
11+
uint32_t caller_saved[16];
12+
uint32_t callee_saved[16];
13+
uint32_t fpscr;
14+
bool ctx_saved;
15+
};
16+
17+
void z_arm_save_fp_context(struct fpu_ctx_full *buffer);
18+
void z_arm_restore_fp_context(const struct fpu_ctx_full *buffer);
19+
20+
#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_ */

modules/trusted-firmware-m/interface/interface.c

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <init.h>
1010
#include <kernel.h>
1111
#include <arch/arm/aarch32/cortex_m/cmsis.h>
12+
#include <arch/arm/aarch32/cortex_m/fpu.h>
1213

1314
#include <tfm_ns_interface.h>
1415

@@ -45,53 +46,17 @@ int32_t tfm_ns_interface_dispatch(veneer_fn fn,
4546
k_sched_lock();
4647
#endif
4748

48-
#if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING)
49-
uint32_t fp_ctx_caller_saved[16];
50-
uint32_t fp_ctx_callee_saved[16];
51-
uint32_t fp_ctx_FPSCR;
52-
bool context_saved = false;
53-
uint32_t CONTROL = __get_CONTROL();
54-
55-
if (CONTROL & CONTROL_FPCA_Msk) {
56-
/* Store caller-saved and callee-saved FP registers. */
57-
__asm__ volatile(
58-
"vstmia %0, {s0-s15}\n"
59-
"vstmia %1, {s16-s31}\n"
60-
:: "r" (fp_ctx_caller_saved), "r" (fp_ctx_callee_saved) :
61-
);
62-
63-
fp_ctx_FPSCR = __get_FPSCR();
64-
context_saved = true;
65-
66-
/* Disable FPCA so no stacking of FP registers happens in TFM. */
67-
__set_CONTROL(CONTROL & ~CONTROL_FPCA_Msk);
68-
69-
/* ISB is recommended after setting CONTROL. It's not needed
70-
* here though, since FPCA should have no impact on instruction
71-
* fetching.
72-
*/
73-
}
74-
#endif /* defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING) */
49+
#if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
50+
struct fpu_ctx_full context_buffer;
51+
52+
z_arm_save_fp_context(&context_buffer);
53+
#endif
7554

7655
result = fn(arg0, arg1, arg2, arg3);
7756

78-
#if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING)
79-
if (context_saved) {
80-
/* Set FPCA first so it is set even if an interrupt happens
81-
* during restoration.
82-
*/
83-
__set_CONTROL(__get_CONTROL() | CONTROL_FPCA_Msk);
84-
85-
/* Restore FP state. */
86-
__set_FPSCR(fp_ctx_FPSCR);
87-
88-
__asm__ volatile(
89-
"vldmia %0, {s0-s15}\n"
90-
"vldmia %1, {s16-s31}\n"
91-
:: "r" (fp_ctx_caller_saved), "r" (fp_ctx_callee_saved) :
92-
);
93-
}
94-
#endif /* defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) && defined(CONFIG_FPU_SHARING) */
57+
#if defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
58+
z_arm_restore_fp_context(&context_buffer);
59+
#endif
9560

9661
#if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS)
9762
/* Unlock the scheduler, to allow the thread to be preempted. */

0 commit comments

Comments
 (0)