]> begriffs open source - freertos/blob - portable/GCC/MicroBlazeV9/portasm.S
Implement MicroBlazeV9 stack protection (#523)
[freertos] / portable / GCC / MicroBlazeV9 / portasm.S
1 /*\r
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>\r
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * SPDX-License-Identifier: MIT\r
6  *\r
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
8  * this software and associated documentation files (the "Software"), to deal in\r
9  * the Software without restriction, including without limitation the rights to\r
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
11  * the Software, and to permit persons to whom the Software is furnished to do so,\r
12  * subject to the following conditions:\r
13  *\r
14  * The above copyright notice and this permission notice shall be included in all\r
15  * copies or substantial portions of the Software.\r
16  *\r
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
23  *\r
24  * https://www.FreeRTOS.org\r
25  * https://github.com/FreeRTOS\r
26  *\r
27  */\r
28 \r
29 /* FreeRTOS includes. */\r
30 #include "FreeRTOSConfig.h"\r
31 \r
32 /* Xilinx library includes. */\r
33 #include "microblaze_exceptions_g.h"\r
34 #include "xparameters.h"\r
35 \r
36 /* Offsets from the stack pointer at which saved registers are placed. */\r
37 #define portR31_OFFSET  4\r
38 #define portR30_OFFSET  8\r
39 #define portR29_OFFSET  12\r
40 #define portR28_OFFSET  16\r
41 #define portR27_OFFSET  20\r
42 #define portR26_OFFSET  24\r
43 #define portR25_OFFSET  28\r
44 #define portR24_OFFSET  32\r
45 #define portR23_OFFSET  36\r
46 #define portR22_OFFSET  40\r
47 #define portR21_OFFSET  44\r
48 #define portR20_OFFSET  48\r
49 #define portR19_OFFSET  52\r
50 #define portR18_OFFSET  56\r
51 #define portR17_OFFSET  60\r
52 #define portR16_OFFSET  64\r
53 #define portR15_OFFSET  68\r
54 #define portR14_OFFSET  72\r
55 #define portR13_OFFSET  76\r
56 #define portR12_OFFSET  80\r
57 #define portR11_OFFSET  84\r
58 #define portR10_OFFSET  88\r
59 #define portR9_OFFSET   92\r
60 #define portR8_OFFSET   96\r
61 #define portR7_OFFSET   100\r
62 #define portR6_OFFSET   104\r
63 #define portR5_OFFSET   108\r
64 #define portR4_OFFSET   112\r
65 #define portR3_OFFSET   116\r
66 #define portR2_OFFSET   120\r
67 #define portCRITICAL_NESTING_OFFSET 124\r
68 #define portMSR_OFFSET 128\r
69 \r
70 #if( XPAR_MICROBLAZE_USE_FPU != 0 )\r
71         #define portFSR_OFFSET 132\r
72         #if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )\r
73                 #define portSLR_OFFSET 136\r
74                 #define portSHR_OFFSET 140\r
75 \r
76                 #define portCONTEXT_SIZE 144\r
77                 #define portMINUS_CONTEXT_SIZE -144\r
78         #else\r
79                 #define portCONTEXT_SIZE 136\r
80                 #define portMINUS_CONTEXT_SIZE -136\r
81         #endif\r
82 #else\r
83         #if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )\r
84                 #define portSLR_OFFSET 132\r
85                 #define portSHR_OFFSET 136\r
86 \r
87                 #define portCONTEXT_SIZE 140\r
88                 #define portMINUS_CONTEXT_SIZE -140\r
89         #else\r
90                 #define portCONTEXT_SIZE 132\r
91                 #define portMINUS_CONTEXT_SIZE -132\r
92         #endif\r
93 #endif\r
94 \r
95         .extern pxCurrentTCB\r
96         .extern XIntc_DeviceInterruptHandler\r
97         .extern vTaskSwitchContext\r
98         .extern uxCriticalNesting\r
99         .extern pulISRStack\r
100         .extern ulTaskSwitchRequested\r
101         .extern vPortExceptionHandler\r
102         .extern pulStackPointerOnFunctionEntry\r
103 \r
104         .global _interrupt_handler\r
105         .global VPortYieldASM\r
106         .global vPortStartFirstTask\r
107         .global vPortExceptionHandlerEntry\r
108 \r
109 \r
110 .macro portSAVE_CONTEXT\r
111 \r
112         /* Make room for the context on the stack. */\r
113         addik r1, r1, portMINUS_CONTEXT_SIZE\r
114 \r
115         /* Stack general registers. */\r
116         swi r31, r1, portR31_OFFSET\r
117         swi r30, r1, portR30_OFFSET\r
118         swi r29, r1, portR29_OFFSET\r
119         swi r28, r1, portR28_OFFSET\r
120         swi r27, r1, portR27_OFFSET\r
121         swi r26, r1, portR26_OFFSET\r
122         swi r25, r1, portR25_OFFSET\r
123         swi r24, r1, portR24_OFFSET\r
124         swi r23, r1, portR23_OFFSET\r
125         swi r22, r1, portR22_OFFSET\r
126         swi r21, r1, portR21_OFFSET\r
127         swi r20, r1, portR20_OFFSET\r
128         swi r19, r1, portR19_OFFSET\r
129         swi r18, r1, portR18_OFFSET\r
130         swi r17, r1, portR17_OFFSET\r
131         swi r16, r1, portR16_OFFSET\r
132         swi r15, r1, portR15_OFFSET\r
133         /* R14 is saved later as it needs adjustment if a yield is performed. */\r
134         swi r13, r1, portR13_OFFSET\r
135         swi r12, r1, portR12_OFFSET\r
136         swi r11, r1, portR11_OFFSET\r
137         swi r10, r1, portR10_OFFSET\r
138         swi r9, r1, portR9_OFFSET\r
139         swi r8, r1, portR8_OFFSET\r
140         swi r7, r1, portR7_OFFSET\r
141         swi r6, r1, portR6_OFFSET\r
142         swi r5, r1, portR5_OFFSET\r
143         swi r4, r1, portR4_OFFSET\r
144         swi r3, r1, portR3_OFFSET\r
145         swi r2, r1, portR2_OFFSET\r
146 \r
147         /* Stack the critical section nesting value. */\r
148         lwi r18, r0, uxCriticalNesting\r
149         swi r18, r1, portCRITICAL_NESTING_OFFSET\r
150 \r
151         /* Stack MSR. */\r
152         mfs r18, rmsr\r
153         swi r18, r1, portMSR_OFFSET\r
154 \r
155         #if( XPAR_MICROBLAZE_USE_FPU != 0 )\r
156                 /* Stack FSR. */\r
157                 mfs r18, rfsr\r
158                 swi r18, r1, portFSR_OFFSET\r
159         #endif\r
160 \r
161 #if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )\r
162         /* Save the stack limits */\r
163         mfs r18, rslr\r
164         swi r18, r1, portSLR_OFFSET\r
165         mfs r18, rshr\r
166         swi r18, r1, portSHR_OFFSET\r
167 #endif\r
168 \r
169         /* Save the top of stack value to the TCB. */\r
170         lwi r3, r0, pxCurrentTCB\r
171         sw      r1, r0, r3\r
172 \r
173         .endm\r
174 \r
175 .macro portRESTORE_CONTEXT\r
176 \r
177         /* Load the top of stack value from the TCB. */\r
178         lwi r18, r0, pxCurrentTCB\r
179         lw      r1, r0, r18\r
180 \r
181 #if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )\r
182         /* Restore the stack limits -- must not load from r1 (Stack Pointer)\r
183         because if the address of load or store instruction is out of range,\r
184         it will trigger Stack Protection Violation exception. */\r
185         or      r18, r0, r1\r
186         lwi     r12, r18, portSLR_OFFSET\r
187         mts     rslr, r12\r
188         lwi     r12, r18, portSHR_OFFSET\r
189         mts     rshr, r12\r
190 #endif\r
191 \r
192         /* Restore the general registers. */\r
193         lwi r31, r1, portR31_OFFSET\r
194         lwi r30, r1, portR30_OFFSET\r
195         lwi r29, r1, portR29_OFFSET\r
196         lwi r28, r1, portR28_OFFSET\r
197         lwi r27, r1, portR27_OFFSET\r
198         lwi r26, r1, portR26_OFFSET\r
199         lwi r25, r1, portR25_OFFSET\r
200         lwi r24, r1, portR24_OFFSET\r
201         lwi r23, r1, portR23_OFFSET\r
202         lwi r22, r1, portR22_OFFSET\r
203         lwi r21, r1, portR21_OFFSET\r
204         lwi r20, r1, portR20_OFFSET\r
205         lwi r19, r1, portR19_OFFSET\r
206         lwi r17, r1, portR17_OFFSET\r
207         lwi r16, r1, portR16_OFFSET\r
208         lwi r15, r1, portR15_OFFSET\r
209         lwi r14, r1, portR14_OFFSET\r
210         lwi r13, r1, portR13_OFFSET\r
211         lwi r12, r1, portR12_OFFSET\r
212         lwi r11, r1, portR11_OFFSET\r
213         lwi r10, r1, portR10_OFFSET\r
214         lwi r9, r1, portR9_OFFSET\r
215         lwi r8, r1, portR8_OFFSET\r
216         lwi r7, r1, portR7_OFFSET\r
217         lwi r6, r1, portR6_OFFSET\r
218         lwi r5, r1, portR5_OFFSET\r
219         lwi r4, r1, portR4_OFFSET\r
220         lwi r3, r1, portR3_OFFSET\r
221         lwi r2, r1, portR2_OFFSET\r
222 \r
223         /* Reload the rmsr from the stack. */\r
224         lwi r18, r1, portMSR_OFFSET\r
225         mts rmsr, r18\r
226 \r
227         #if( XPAR_MICROBLAZE_USE_FPU != 0 )\r
228                 /* Reload the FSR from the stack. */\r
229                 lwi r18, r1, portFSR_OFFSET\r
230                 mts rfsr, r18\r
231         #endif\r
232 \r
233         /* Load the critical nesting value. */\r
234         lwi r18, r1, portCRITICAL_NESTING_OFFSET\r
235         swi r18, r0, uxCriticalNesting\r
236 \r
237         /* Test the critical nesting value.  If it is non zero then the task last\r
238         exited the running state using a yield.  If it is zero, then the task\r
239         last exited the running state through an interrupt. */\r
240         xori r18, r18, 0\r
241         bnei r18, exit_from_yield\r
242 \r
243         /* r18 was being used as a temporary.  Now restore its true value from the\r
244         stack. */\r
245         lwi r18, r1, portR18_OFFSET\r
246 \r
247         /* Remove the stack frame. */\r
248         addik r1, r1, portCONTEXT_SIZE\r
249 \r
250         /* Return using rtid so interrupts are re-enabled as this function is\r
251         exited. */\r
252         rtid r14, 0\r
253         or r0, r0, r0\r
254 \r
255         .endm\r
256 \r
257 /* This function is used to exit portRESTORE_CONTEXT() if the task being\r
258 returned to last left the Running state by calling taskYIELD() (rather than\r
259 being preempted by an interrupt). */\r
260         .text\r
261         .align  4\r
262 exit_from_yield:\r
263 \r
264         /* r18 was being used as a temporary.  Now restore its true value from the\r
265         stack. */\r
266         lwi r18, r1, portR18_OFFSET\r
267 \r
268         /* Remove the stack frame. */\r
269         addik r1, r1, portCONTEXT_SIZE\r
270 \r
271         /* Return to the task. */\r
272         rtsd r14, 0\r
273         or r0, r0, r0\r
274 \r
275 \r
276         .text\r
277         .align  4\r
278 _interrupt_handler:\r
279 \r
280         portSAVE_CONTEXT\r
281 \r
282         /* Stack the return address. */\r
283         swi r14, r1, portR14_OFFSET\r
284 \r
285         /* Switch to the ISR stack. */\r
286         lwi r1, r0, pulISRStack\r
287 \r
288 #if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )\r
289         ori r18, r0, _stack_end\r
290         mts rslr, r18\r
291         ori r18, r0, _stack\r
292         mts rshr, r18\r
293 #endif\r
294 \r
295         /* The parameter to the interrupt handler. */\r
296         ori r5, r0, configINTERRUPT_CONTROLLER_TO_USE\r
297 \r
298         /* Execute any pending interrupts. */\r
299         bralid r15, XIntc_DeviceInterruptHandler\r
300         or r0, r0, r0\r
301 \r
302         /* See if a new task should be selected to execute. */\r
303         lwi r18, r0, ulTaskSwitchRequested\r
304         or r18, r18, r0\r
305 \r
306         /* If ulTaskSwitchRequested is already zero, then jump straight to\r
307         restoring the task that is already in the Running state. */\r
308         beqi r18, task_switch_not_requested\r
309 \r
310         /* Set ulTaskSwitchRequested back to zero as a task switch is about to be\r
311         performed. */\r
312         swi r0, r0, ulTaskSwitchRequested\r
313 \r
314         /* ulTaskSwitchRequested was not 0 when tested.  Select the next task to\r
315         execute. */\r
316         bralid r15, vTaskSwitchContext\r
317         or r0, r0, r0\r
318 \r
319 task_switch_not_requested:\r
320 \r
321         /* Restore the context of the next task scheduled to execute. */\r
322         portRESTORE_CONTEXT\r
323 \r
324 \r
325         .text\r
326         .align  4\r
327 VPortYieldASM:\r
328 \r
329         portSAVE_CONTEXT\r
330 \r
331         /* Modify the return address so a return is done to the instruction after\r
332         the call to VPortYieldASM. */\r
333         addi r14, r14, 8\r
334         swi r14, r1, portR14_OFFSET\r
335 \r
336         /* Switch to use the ISR stack. */\r
337         lwi r1, r0, pulISRStack\r
338 \r
339 #if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )\r
340         ori r18, r0, _stack_end\r
341         mts rslr, r18\r
342         ori r18, r0, _stack\r
343         mts rshr, r18\r
344 #endif\r
345 \r
346         /* Select the next task to execute. */\r
347         bralid r15, vTaskSwitchContext\r
348         or r0, r0, r0\r
349 \r
350         /* Restore the context of the next task scheduled to execute. */\r
351         portRESTORE_CONTEXT\r
352 \r
353         .text\r
354         .align  4\r
355 vPortStartFirstTask:\r
356 \r
357         portRESTORE_CONTEXT\r
358 \r
359 \r
360 \r
361 #if ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 )\r
362 \r
363         .text\r
364         .align 4\r
365 vPortExceptionHandlerEntry:\r
366 \r
367         /* Take a copy of the stack pointer before vPortExecptionHandler is called,\r
368         storing its value prior to the function stack frame being created. */\r
369         swi r1, r0, pulStackPointerOnFunctionEntry\r
370         bralid r15, vPortExceptionHandler\r
371         or r0, r0, r0\r
372 \r
373 #endif /* ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 ) */\r
374 \r
375 \r
376 \r