xref: /Kernel-v10.6.2/portable/GCC/IA32_flat/portASM.S (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1/*
2 * FreeRTOS Kernel V10.6.2
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.file "portASM.S"
30#include "FreeRTOSConfig.h"
31#include "ISR_Support.h"
32
33    .extern pxCurrentTCB
34    .extern vTaskSwitchContext
35    .extern vPortCentralInterruptHandler
36    .extern xTaskIncrementTick
37    .extern vPortAPICErrorHandler
38    .extern pucPortTaskFPUContextBuffer
39    .extern ulPortYieldPending
40
41    .global vPortStartFirstTask
42    .global vPortCentralInterruptWrapper
43    .global vPortAPICErrorHandlerWrapper
44    .global vPortTimerHandler
45    .global vPortYieldCall
46    .global vPortAPICSpuriousHandler
47
48    .text
49
50/*-----------------------------------------------------------*/
51
52.align 4
53.func vPortYieldCall
54vPortYieldCall:
55    /* Save general purpose registers. */
56    pusha
57
58    .if configSUPPORT_FPU == 1
59
60        /* If the task has a buffer allocated to save the FPU context then save
61        the FPU context now. */
62        movl    pucPortTaskFPUContextBuffer, %eax
63        test    %eax, %eax
64        je      1f
65        fnsave  ( %eax )
66        fwait
67
68        1:
69
70        /* Save the address of the FPU context, if any. */
71        push    pucPortTaskFPUContextBuffer
72
73    .endif /* configSUPPORT_FPU */
74
75    /* Find the TCB. */
76    movl    pxCurrentTCB, %eax
77
78    /* Stack location is first item in the TCB. */
79    movl    %esp, (%eax)
80
81    call vTaskSwitchContext
82
83    /* Find the location of pxCurrentTCB again - a callee saved register could
84    be used in place of eax to prevent this second load, but that then relies
85    on the compiler and other asm code. */
86    movl    pxCurrentTCB, %eax
87    movl    (%eax), %esp
88
89    .if configSUPPORT_FPU == 1
90
91        /* Restore address of task's FPU context buffer. */
92        pop     pucPortTaskFPUContextBuffer
93
94        /* If the task has a buffer allocated in which its FPU context is saved,
95        then restore it now. */
96        movl    pucPortTaskFPUContextBuffer, %eax
97        test    %eax, %eax
98        je      1f
99        frstor  ( %eax )
100        1:
101    .endif
102
103    popa
104    iret
105
106.endfunc
107/*-----------------------------------------------------------*/
108
109.align 4
110.func vPortStartFirstTask
111vPortStartFirstTask:
112
113    /* Find the TCB. */
114    movl    pxCurrentTCB, %eax
115
116    /* Stack location is first item in the TCB. */
117    movl    (%eax), %esp
118
119    /* Restore FPU context flag. */
120    .if configSUPPORT_FPU == 1
121
122        pop     pucPortTaskFPUContextBuffer
123
124    .endif /* configSUPPORT_FPU */
125
126    /* Restore general purpose registers. */
127    popa
128    iret
129.endfunc
130/*-----------------------------------------------------------*/
131
132.align 4
133.func vPortAPICErrorHandlerWrapper
134vPortAPICErrorHandlerWrapper:
135    pusha
136    call    vPortAPICErrorHandler
137    popa
138    /* EOI. */
139    movl    $0x00, (0xFEE000B0)
140    iret
141.endfunc
142/*-----------------------------------------------------------*/
143
144.align 4
145.func vPortTimerHandler
146vPortTimerHandler:
147
148    /* Save general purpose registers. */
149    pusha
150
151    /* Interrupts are not nested, so save the rest of the task context. */
152    .if configSUPPORT_FPU == 1
153
154        /* If the task has a buffer allocated to save the FPU context then save the
155        FPU context now. */
156        movl    pucPortTaskFPUContextBuffer, %eax
157        test    %eax, %eax
158        je      1f
159        fnsave  ( %eax ) /* Save FLOP context into ucTempFPUBuffer array. */
160        fwait
161
162        1:
163        /* Save the address of the FPU context, if any. */
164        push    pucPortTaskFPUContextBuffer
165
166    .endif /* configSUPPORT_FPU */
167
168    /* Find the TCB. */
169    movl    pxCurrentTCB, %eax
170
171    /* Stack location is first item in the TCB. */
172    movl    %esp, (%eax)
173
174    /* Switch stacks. */
175    movl    ulTopOfSystemStack, %esp
176    movl    %esp, %ebp
177
178    /* Increment nesting count. */
179    add     $1, ulInterruptNesting
180
181    call    xTaskIncrementTick
182
183    sti
184
185    /* Is a switch to another task required? */
186    test    %eax, %eax
187    je      _skip_context_switch
188    cli
189    call    vTaskSwitchContext
190
191_skip_context_switch:
192    cli
193
194    /* Decrement the variable used to determine if a switch to a system
195    stack is necessary. */
196    sub     $1, ulInterruptNesting
197
198    /* Stack location is first item in the TCB. */
199    movl    pxCurrentTCB, %eax
200    movl    (%eax), %esp
201
202    .if configSUPPORT_FPU == 1
203
204        /* Restore address of task's FPU context buffer. */
205        pop     pucPortTaskFPUContextBuffer
206
207        /* If the task has a buffer allocated in which its FPU context is saved,
208        then restore it now. */
209        movl    pucPortTaskFPUContextBuffer, %eax
210        test    %eax, %eax
211        je      1f
212        frstor  ( %eax )
213        1:
214    .endif
215
216    popa
217
218    /* EOI. */
219    movl    $0x00, (0xFEE000B0)
220    iret
221
222.endfunc
223/*-----------------------------------------------------------*/
224
225.if configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1
226
227    .align 4
228    .func vPortCentralInterruptWrapper
229    vPortCentralInterruptWrapper:
230
231        portFREERTOS_INTERRUPT_ENTRY
232
233        movl $0xFEE00170, %eax          /* Highest In Service Register (ISR) long word. */
234        movl $8, %ecx                   /* Loop counter. */
235
236    next_isr_long_word:
237        test %ecx, %ecx                 /* Loop counter reached 0? */
238        je wrapper_epilogue             /* Looked at all ISR registers without finding a bit set. */
239        sub $1, %ecx                    /* Sub 1 from loop counter. */
240        movl (%eax), %ebx               /* Load next ISR long word. */
241        sub $0x10, %eax                 /* Point to next ISR long word in case no bits are set in the current long word. */
242        test %ebx, %ebx                 /* Are there any bits set? */
243        je next_isr_long_word           /* Look at next ISR long word if no bits were set. */
244        sti
245        bsr %ebx, %ebx                  /* A bit was set, which one? */
246        movl $32, %eax                  /* Destination operand for following multiplication. */
247        mul %ecx                        /* Calculate base vector for current register, 32 vectors per register. */
248        add %ebx, %eax                  /* Add bit offset into register to get final vector number. */
249        push %eax                       /* Vector number is function parameter. */
250        call vPortCentralInterruptHandler
251        pop %eax                        /* Remove parameter. */
252
253    wrapper_epilogue:
254        portFREERTOS_INTERRUPT_EXIT
255
256    .endfunc
257
258.endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
259/*-----------------------------------------------------------*/
260
261.align 4
262.func vPortAPISpuriousHandler
263vPortAPICSpuriousHandler:
264    iret
265
266.endfunc
267
268.end
269