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 <zephyr/kernel.h>
9 #include <cmsis_core.h>
10 #include <zephyr/arch/arm/cortex_m/fpu.h>
11 
12 /**
13  * @file @brief Helper functions for saving and restoring the FP context.
14  *
15  */
16 
z_arm_save_fp_context(struct fpu_ctx_full * buffer)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 
z_arm_restore_fp_context(const struct fpu_ctx_full * buffer)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 }
66