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("vstmia %0, {s0-s15}\n"
27 				 "vstmia %1, {s16-s31}\n" ::"r"(buffer->caller_saved),
28 				 "r"(buffer->callee_saved)
29 				 :);
30 
31 		buffer->fpscr = __get_FPSCR();
32 		buffer->ctx_saved = true;
33 
34 		/* Disable FPCA so no stacking of FP registers happens in TFM. */
35 		__set_CONTROL(CONTROL & ~CONTROL_FPCA_Msk);
36 
37 		/* ISB is recommended after setting CONTROL. It's not needed
38 		 * here though, since FPCA should have no impact on instruction
39 		 * fetching.
40 		 */
41 	}
42 #endif
43 }
44 
z_arm_restore_fp_context(const struct fpu_ctx_full * buffer)45 void z_arm_restore_fp_context(const struct fpu_ctx_full *buffer)
46 {
47 #if defined(CONFIG_FPU_SHARING)
48 	if (buffer->ctx_saved) {
49 		/* Set FPCA first so it is set even if an interrupt happens
50 		 * during restoration.
51 		 */
52 		__set_CONTROL(__get_CONTROL() | CONTROL_FPCA_Msk);
53 
54 		/* Restore FP state. */
55 		__set_FPSCR(buffer->fpscr);
56 
57 		__asm__ volatile("vldmia %0, {s0-s15}\n"
58 				 "vldmia %1, {s16-s31}\n" ::"r"(buffer->caller_saved),
59 				 "r"(buffer->callee_saved)
60 				 :);
61 	}
62 #endif
63 }
64