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