C Microkernel Realtime eXecutive
Realtime Operating System for Cortex-M based microcontrollers
 
Loading...
Searching...
No Matches
cortex.h
1#pragma once
2
3#include <stdbool.h>
4#include <stdint.h>
5#include <RTE_Components.h>
6#include CMSIS_device_header
7
19typedef struct {
20 uint32_t r0123[4];
21/* uint32_t r1;
22 uint32_t r2;
23 uint32_t r3;*/
24 uint32_t r12;
25 void (*lr)(void);
26 void *pc;
27 uint32_t xpsr;
28/* uint32_t arg4;
29 uint32_t arg5;
30 uint32_t arg6;
31 uint32_t arg7;*/
33
34_Static_assert(sizeof(ExceptionFrame) % 8 == 0, "The size of ExceptionFrame structure is not divisible by 8!");
35
38typedef struct {
39 uint32_t r0123[4];
40 uint32_t r12;
41 void (*lr)(void);
42 void *pc;
43 uint32_t xpsr;
44 uint32_t fpu_regs[16];
45 uint32_t fpscr;
46 uint32_t __spacer;
48
49_Static_assert(sizeof(ExceptionFrameFP) % 8 == 0, "The size of ExceptionFrameFP structure is not divisible by 8!");
50
52#define EXCEPTION_FRAME_ENTRIES (sizeof(ExceptionFrame) / sizeof(uint32_t))
54#define EXCEPTION_FRAME_FP_ENTRIES (sizeof(ExceptionFrameFP) / sizeof(uint32_t))
55
56#define ALWAYS_INLINE __STATIC_FORCEINLINE
57
64#if defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)
65
66/* ARMv6M and ARMv8M-Baseline: limited register access */
68{
69 asm volatile(
70 "POP {R0, R1, R2, R3}\n\t"
71 "POP {R6, R7}\n\t"
72 "MOV R12, R6\n\t"
73 "MOV LR, R7\n\t"
74 "POP {R6, R7}\n\t"
75 "BX R6\n\t"
76 );
77}
78
79#else
80
81/* ARMv7M, ARMv7EM, ARMv8M-Mainline: full register access */
82// TODO: Test this
84{
85 asm volatile(
86 "POP {R0, R1, R2, R3}\n\t"
87 "POP {R12, LR}\n\t"
88 "POP {R6, R7}\n\t"
89 "BX R6\n\t"
90 );
91}
92
93#endif
94
102#define SAVE_CONTEXT() \
103asm volatile( \
104 ".syntax unified\n\t" \
105 "MRS r0, PSP\n\t" \
106 "SUBS r0, #16\n\t" \
107 "STMEA r0!, {r4 - r7}\n\t" \
108 "SUBS r0, #32\n\t" \
109 "MOV r4, r8\n\t" \
110 "MOV r5, r9\n\t" \
111 "MOV r6, r10\n\t" \
112 "MOV r7, r11\n\t" \
113 "STMEA r0!, {r4 - r7}\n\t" \
114 "SUBS r0, #16\n\t" \
115 "MSR PSP, r0\n\t" \
116 : : : "r0", "r4", "r5", "r6", "r7", "memory" \
117)
118
119
129#define LOAD_CONTEXT() \
130asm ( \
131 ".syntax unified\n\t" \
132 "MRS r0, PSP\n\t" \
133 "LDMFD r0!, {r4 - r7}\n\t" \
134 "MOV r8, r4\n\t" \
135 "MOV r9, r5\n\t" \
136 "MOV r10, r6\n\t" \
137 "MOV r11, r7\n\t" \
138 "LDMFD r0!, {r4 - r7}\n\t" \
139 "MSR PSP, r0\n\t" \
140 : : : "r0", "r4", "r5", "r6", "r7", "memory" \
141)
142
153uint32_t * get_exception_arg_addr(ExceptionFrame * frame, unsigned argno, bool fp_active);
154
162static inline unsigned get_exception_argument(ExceptionFrame * frame, unsigned argno, bool fp_active)
163{
164 uint32_t * arg_addr = get_exception_arg_addr(frame, argno, fp_active);
165 return *arg_addr;
166}
167
175static inline void set_exception_argument(ExceptionFrame * frame, unsigned argno, unsigned value, bool fp_active)
176{
177 uint32_t * arg_addr = get_exception_arg_addr(frame, argno, fp_active);
178 *arg_addr = value;
179}
180
188static inline void set_exception_pc_lr(ExceptionFrame * frame, void * pc, void (* lr)(void))
189{
190 frame->pc = pc;
191 frame->lr = lr;
192}
193
200ExceptionFrame * push_exception_frame(ExceptionFrame * frame, unsigned args, bool fp_active);
201
212ExceptionFrame * shim_exception_frame(ExceptionFrame * frame, unsigned args, bool fp_active);
213
223ExceptionFrame * pop_exception_frame(ExceptionFrame * frame, unsigned args, bool fp_active);
224
229{
230 void * lr;
231 asm volatile(
232 ".syntax unified\n\t"
233 "MOV %0, LR\n\t"
234 : "=r" (lr)
235 );
236
237 return lr;
238}
239
243ALWAYS_INLINE void __set_LR(void * lr)
244{
245 asm volatile(
246 ".syntax unified\n\t"
247 "MOV LR, %0\n\t"
248 :
249 : "r" (lr)
250 );
251}
252
262#if defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)
263
264/* ARMv6M and ARMv8M-Baseline: limited immediate support, use LDR */
265ALWAYS_INLINE void __forge_shutdown_exception_frame(void (*continue_here)(void))
266{
267 asm volatile(
268 ".syntax unified\n\t"
269 "LDR R0, =0xFFFFFFF9\n\t" // return to thread mode with MSP
270 "MOV LR, R0\n\t"
271 "LDR R0, =0x01000000\n\t"
272 "MOV R1, %0\n\t"
273 "LDR R2, =0\n\t"
274 "PUSH {R0}\n\t" // xPSR
275 "PUSH {R1}\n\t" // PC
276 "PUSH {R2}\n\t" // LR - NULL, point of no return
277 "PUSH {R2}\n\t" // R12
278 "PUSH {R2}\n\t" // R3
279 "PUSH {R2}\n\t" // R2
280 "PUSH {R2}\n\t" // R1
281 "PUSH {R2}\n\t" // R0
282 "BX LR"
283 :
284 : "r" (continue_here)
285 );
286}
287
288#else
289
290/* ARMv7M, ARMv7EM, ARMv8M-Mainline: modified immediate support */
291ALWAYS_INLINE __attribute__((noreturn)) void __forge_shutdown_exception_frame(void (*continue_here)(void))
292{
293 asm volatile(
294 ".syntax unified\n\t"
295 "MOV R0, #0x01000000\n\t"
296 "MOV R1, %0\n\t"
297 "MOV R2, #0\n\t"
298 "MOV LR, #0xFFFFFFF9\n\t" // return to thread mode with MSP
299 "PUSH {R0}\n\t" // xPSR
300 "PUSH {R1}\n\t" // PC
301 "PUSH {R2}\n\t" // LR - NULL, point of no return
302 "PUSH {R2}\n\t" // R12
303 "PUSH {R2}\n\t" // R3
304 "PUSH {R2}\n\t" // R2
305 "PUSH {R2}\n\t" // R1
306 "PUSH {R2}\n\t" // R0
307 "BX LR"
308 :
309 : "r" (continue_here)
310 );
311}
312
313#endif
314
315static inline bool cortex_is_fpu_used(uint32_t return_addr)
316{
317#if defined(__ARM_ARCH_8M_BASE__) || defined(__ARM_ARCH_8M_MAIN__)
318 return (return_addr & EXC_RETURN_FTYPE) == 0;
319#elif defined(__ARM_ARCH_6M__)
320 return false;
321#else
322 return return_addr == EXC_RETURN_THREAD_PSP_FPU;
323#endif
324}
325
326static inline bool cortex_is_thread_psp_used(uint32_t return_addr)
327{
328#if defined(__ARM_ARCH_8M_BASE__) || defined(__ARM_ARCH_8M_MAIN__)
329 return (return_addr & (EXC_RETURN_MODE | EXC_RETURN_SPSEL)) == (EXC_RETURN_MODE | EXC_RETURN_SPSEL);
330#elif defined(__ARM_ARCH_6M__)
331 return return_addr == EXC_RETURN_THREAD_PSP;
332#else
333 return return_addr == EXC_RETURN_THREAD_PSP || return_addr == EXC_RETURN_THREAD_PSP_FPU;
334#endif
335}
336
uint32_t * get_exception_arg_addr(ExceptionFrame *frame, unsigned argno, bool fp_active)
Retrieve address of n-th argument from exception frame.
Definition cortex.c:47
static void set_exception_pc_lr(ExceptionFrame *frame, void *pc, void(*lr)(void))
Configure PC and LR register values in exception frame.
Definition cortex.h:188
static unsigned get_exception_argument(ExceptionFrame *frame, unsigned argno, bool fp_active)
Retrieve value of exception frame function call argument.
Definition cortex.h:162
ALWAYS_INLINE void __set_LR(void *lr)
Set value of process LR.
Definition cortex.h:243
static bool cortex_is_thread_psp_used(uint32_t return_addr)
Definition cortex.h:326
static void set_exception_argument(ExceptionFrame *frame, unsigned argno, unsigned value, bool fp_active)
Set value of exception frame function call argument.
Definition cortex.h:175
#define ALWAYS_INLINE
Definition cortex.h:56
static bool cortex_is_fpu_used(uint32_t return_addr)
Definition cortex.h:315
ALWAYS_INLINE void __ISR_return()
Perform same actions as normal ISR return does.
Definition cortex.h:83
ExceptionFrame * shim_exception_frame(ExceptionFrame *frame, unsigned args, bool fp_active)
Creates space for additional arguments under exception frame.
Definition cortex.c:319
ALWAYS_INLINE void * __get_LR(void)
Get value of process LR.
Definition cortex.h:228
ExceptionFrame * pop_exception_frame(ExceptionFrame *frame, unsigned args, bool fp_active)
Remove exception frame from thread's stack.
Definition cortex.c:341
ALWAYS_INLINE void __forge_shutdown_exception_frame(void(*continue_here)(void))
Forges shutdown exception frame.
Definition cortex.h:291
ExceptionFrame * push_exception_frame(ExceptionFrame *frame, unsigned args, bool fp_active)
Duplicate exception frame on thread's stack.
Definition cortex.c:286
Exception frame with FPU context saved.
Definition cortex.h:38
uint32_t xpsr
Definition cortex.h:43
void * pc
Definition cortex.h:42
uint32_t r12
Definition cortex.h:40
uint32_t fpscr
Definition cortex.h:45
uint32_t __spacer
Definition cortex.h:46
Full RISC-V trap context frame.
Definition exception_frame.h:176
void(* lr)(void)
Definition cortex.h:25
void * pc
Definition cortex.h:26
uint32_t xpsr
Definition cortex.h:27
uint32_t r12
Definition cortex.h:24