1@/***************************************************************************
2@ * Copyright (c) 2024 Microsoft Corporation
3@ *
4@ * This program and the accompanying materials are made available under the
5@ * terms of the MIT License which is available at
6@ * https://opensource.org/licenses/MIT.
7@ *
8@ * SPDX-License-Identifier: MIT
9@ **************************************************************************/
10@
11@
12@/**************************************************************************/
13@/**************************************************************************/
14@/**                                                                       */
15@/** ThreadX Component                                                     */
16@/**                                                                       */
17@/**   Initialize                                                          */
18@/**                                                                       */
19@/**************************************************************************/
20@/**************************************************************************/
21@
22@
23@#define TX_SOURCE_CODE
24@
25@
26@/* Include necessary system files.  */
27@
28@#include "tx_api.h"
29@#include "tx_initialize.h"
30@#include "tx_thread.h"
31@#include "tx_timer.h"
32
33    .arm
34
35SVC_MODE        =       0xD3                    @ Disable IRQ/FIQ SVC mode
36IRQ_MODE        =       0xD2                    @ Disable IRQ/FIQ IRQ mode
37FIQ_MODE        =       0xD1                    @ Disable IRQ/FIQ FIQ mode
38SYS_MODE        =       0xDF                    @ Disable IRQ/FIQ SYS mode
39FIQ_STACK_SIZE  =       512                     @ FIQ stack size
40IRQ_STACK_SIZE  =       1024                    @ IRQ stack size
41SYS_STACK_SIZE  =       1024                    @ System stack size
42@
43@
44    .global     _tx_thread_system_stack_ptr
45    .global     _tx_initialize_unused_memory
46    .global     _tx_thread_context_save
47    .global     _tx_thread_context_restore
48    .global     _tx_timer_interrupt
49    .global     _end
50    .global     _sp
51    .global     _stack_bottom
52
53@
54@
55@/* Define the 16-bit Thumb mode veneer for _tx_initialize_low_level for
56@   applications calling this function from to 16-bit Thumb mode.  */
57@
58    .text
59    .align 2
60    .thumb
61    .global $_tx_initialize_low_level
62    .type   $_tx_initialize_low_level,function
63$_tx_initialize_low_level:
64     BX        pc                               @ Switch to 32-bit mode
65     NOP                                        @
66    .arm
67     STMFD     sp!, {lr}                        @ Save return address
68     BL        _tx_initialize_low_level         @ Call _tx_initialize_low_level function
69     LDMFD     sp!, {lr}                        @ Recover saved return address
70     BX        lr                               @ Return to 16-bit caller
71@
72@
73    .text
74    .align 2
75@/**************************************************************************/
76@/*                                                                        */
77@/*  FUNCTION                                               RELEASE        */
78@/*                                                                        */
79@/*    _tx_initialize_low_level                             ARM9/GNU       */
80@/*                                                           6.1          */
81@/*  AUTHOR                                                                */
82@/*                                                                        */
83@/*    William E. Lamie, Microsoft Corporation                             */
84@/*                                                                        */
85@/*  DESCRIPTION                                                           */
86@/*                                                                        */
87@/*    This function is responsible for any low-level processor            */
88@/*    initialization, including setting up interrupt vectors, setting     */
89@/*    up a periodic timer interrupt source, saving the system stack       */
90@/*    pointer for use in ISR processing later, and finding the first      */
91@/*    available RAM memory address for tx_application_define.             */
92@/*                                                                        */
93@/*  INPUT                                                                 */
94@/*                                                                        */
95@/*    None                                                                */
96@/*                                                                        */
97@/*  OUTPUT                                                                */
98@/*                                                                        */
99@/*    None                                                                */
100@/*                                                                        */
101@/*  CALLS                                                                 */
102@/*                                                                        */
103@/*    None                                                                */
104@/*                                                                        */
105@/*  CALLED BY                                                             */
106@/*                                                                        */
107@/*    _tx_initialize_kernel_enter           ThreadX entry function        */
108@/*                                                                        */
109@/*  RELEASE HISTORY                                                       */
110@/*                                                                        */
111@/*    DATE              NAME                      DESCRIPTION             */
112@/*                                                                        */
113@/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
114@/*                                                                        */
115@/**************************************************************************/
116@VOID   _tx_initialize_low_level(VOID)
117@{
118    .global _tx_initialize_low_level
119    .type   _tx_initialize_low_level,function
120_tx_initialize_low_level:
121@
122@    /* We must be in SVC mode at this point!  */
123@
124@    /* Setup various stack pointers.  */
125@
126    LDR     r1, =_sp                            @ Get pointer to stack area
127
128#ifdef TX_ENABLE_IRQ_NESTING
129@
130@    /* Setup the system mode stack for nested interrupt support  */
131@
132    LDR     r2, =SYS_STACK_SIZE                 @ Pickup stack size
133    MOV     r3, #SYS_MODE                       @ Build SYS mode CPSR
134    MSR     CPSR_cxsf, r3                       @ Enter SYS mode
135    SUB     r1, r1, #1                          @ Backup 1 byte
136    BIC     r1, r1, #7                          @ Ensure 8-byte alignment
137    MOV     sp, r1                              @ Setup SYS stack pointer
138    SUB     r1, r1, r2                          @ Calculate start of next stack
139#endif
140
141    LDR     r2, =FIQ_STACK_SIZE                 @ Pickup stack size
142    MOV     r0, #FIQ_MODE                       @ Build FIQ mode CPSR
143    MSR     CPSR, r0                            @ Enter FIQ mode
144    SUB     r1, r1, #1                          @ Backup 1 byte
145    BIC     r1, r1, #7                          @ Ensure 8-byte alignment
146    MOV     sp, r1                              @ Setup FIQ stack pointer
147    SUB     r1, r1, r2                          @ Calculate start of next stack
148    LDR     r2, =IRQ_STACK_SIZE                 @ Pickup IRQ stack size
149    MOV     r0, #IRQ_MODE                       @ Build IRQ mode CPSR
150    MSR     CPSR, r0                            @ Enter IRQ mode
151    SUB     r1, r1, #1                          @ Backup 1 byte
152    BIC     r1, r1, #7                          @ Ensure 8-byte alignment
153    MOV     sp, r1                              @ Setup IRQ stack pointer
154    SUB     r3, r1, r2                          @ Calculate end of IRQ stack
155    MOV     r0, #SVC_MODE                       @ Build SVC mode CPSR
156    MSR     CPSR, r0                            @ Enter SVC mode
157    LDR     r2, =_stack_bottom                  @ Pickup stack bottom
158    CMP     r3, r2                              @ Compare the current stack end with the bottom
159_stack_error_loop:
160    BLT     _stack_error_loop                   @ If the IRQ stack exceeds the stack bottom, just sit here!
161@
162@    /* Save the system stack pointer.  */
163@    _tx_thread_system_stack_ptr = (VOID_PTR) (sp);
164@
165    LDR     r2, =_tx_thread_system_stack_ptr    @ Pickup stack pointer
166    STR     r1, [r2]                            @ Save the system stack
167@
168@    /* Save the first available memory address.  */
169@    _tx_initialize_unused_memory =  (VOID_PTR) _end;
170@
171    LDR     r1, =_end                           @ Get end of non-initialized RAM area
172    LDR     r2, =_tx_initialize_unused_memory   @ Pickup unused memory ptr address
173    ADD     r1, r1, #8                          @ Increment to next free word
174    STR     r1, [r2]                            @ Save first free memory address
175@
176@    /* Setup Timer for periodic interrupts.  */
177@
178@    /* Done, return to caller.  */
179@
180#ifdef __THUMB_INTERWORK
181    BX      lr                                  @ Return to caller
182#else
183    MOV     pc, lr                              @ Return to caller
184#endif
185@}
186@
187@
188@/* Define shells for each of the interrupt vectors.  */
189@
190    .global __tx_undefined
191__tx_undefined:
192    B       __tx_undefined                      @ Undefined handler
193@
194    .global __tx_swi_interrupt
195__tx_swi_interrupt:
196    B       __tx_swi_interrupt                  @ Software interrupt handler
197@
198    .global __tx_prefetch_handler
199__tx_prefetch_handler:
200    B       __tx_prefetch_handler               @ Prefetch exception handler
201@
202    .global __tx_abort_handler
203__tx_abort_handler:
204    B       __tx_abort_handler                  @ Abort exception handler
205@
206    .global __tx_reserved_handler
207__tx_reserved_handler:
208    B       __tx_reserved_handler               @ Reserved exception handler
209@
210    .global __tx_irq_handler
211    .global __tx_irq_processing_return
212__tx_irq_handler:
213@
214@    /* Jump to context save to save system context.  */
215    B       _tx_thread_context_save
216__tx_irq_processing_return:
217@
218@    /* At this point execution is still in the IRQ mode.  The CPSR, point of
219@       interrupt, and all C scratch registers are available for use.  In
220@       addition, IRQ interrupts may be re-enabled - with certain restrictions -
221@       if nested IRQ interrupts are desired.  Interrupts may be re-enabled over
222@       small code sequences where lr is saved before enabling interrupts and
223@       restored after interrupts are again disabled.  */
224@
225@    /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start
226@       from IRQ mode with interrupts disabled.  This routine switches to the
227@       system mode and returns with IRQ interrupts enabled.
228@
229@       NOTE:  It is very important to ensure all IRQ interrupts are cleared
230@       prior to enabling nested IRQ interrupts.  */
231#ifdef TX_ENABLE_IRQ_NESTING
232    BL      _tx_thread_irq_nesting_start
233#endif
234@
235@    /* For debug purpose, execute the timer interrupt processing here.  In
236@       a real system, some kind of status indication would have to be checked
237@       before the timer interrupt handler could be called.  */
238@
239    BL     _tx_timer_interrupt                  @ Timer interrupt handler
240@
241@
242@    /* If interrupt nesting was started earlier, the end of interrupt nesting
243@       service must be called before returning to _tx_thread_context_restore.
244@       This routine returns in processing in IRQ mode with interrupts disabled.  */
245#ifdef TX_ENABLE_IRQ_NESTING
246    BL      _tx_thread_irq_nesting_end
247#endif
248@
249@    /* Jump to context restore to restore system context.  */
250    B       _tx_thread_context_restore
251@
252@
253@    /* This is an example of a vectored IRQ handler.  */
254@
255@    .global __tx_example_vectored_irq_handler
256@__tx_example_vectored_irq_handler:
257@
258@
259@    /* Save initial context and call context save to prepare for
260@       vectored ISR execution.  */
261@
262@    STMDB   sp!, {r0-r3}                        @ Save some scratch registers
263@    MRS     r0, SPSR                            @ Pickup saved SPSR
264@    SUB     lr, lr, #4                          @ Adjust point of interrupt
265@    STMDB   sp!, {r0, r10, r12, lr}             @ Store other scratch registers
266@    BL      _tx_thread_vectored_context_save    @ Vectored context save
267@
268@    /* At this point execution is still in the IRQ mode.  The CPSR, point of
269@       interrupt, and all C scratch registers are available for use.  In
270@       addition, IRQ interrupts may be re-enabled - with certain restrictions -
271@       if nested IRQ interrupts are desired.  Interrupts may be re-enabled over
272@       small code sequences where lr is saved before enabling interrupts and
273@       restored after interrupts are again disabled.  */
274@
275@
276@    /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start
277@       from IRQ mode with interrupts disabled.  This routine switches to the
278@       system mode and returns with IRQ interrupts enabled.
279@
280@       NOTE:  It is very important to ensure all IRQ interrupts are cleared
281@       prior to enabling nested IRQ interrupts.  */
282@#ifdef TX_ENABLE_IRQ_NESTING
283@    BL      _tx_thread_irq_nesting_start
284@#endif
285@
286@    /* Application IRQ handlers can be called here!  */
287@
288@    /* If interrupt nesting was started earlier, the end of interrupt nesting
289@       service must be called before returning to _tx_thread_context_restore.
290@       This routine returns in processing in IRQ mode with interrupts disabled.  */
291@#ifdef TX_ENABLE_IRQ_NESTING
292@    BL      _tx_thread_irq_nesting_end
293@#endif
294@
295@    /* Jump to context restore to restore system context.  */
296@    B       _tx_thread_context_restore
297@
298@
299#ifdef TX_ENABLE_FIQ_SUPPORT
300    .global  __tx_fiq_handler
301    .global  __tx_fiq_processing_return
302__tx_fiq_handler:
303@
304@    /* Jump to fiq context save to save system context.  */
305    B       _tx_thread_fiq_context_save
306__tx_fiq_processing_return:
307@
308@    /* At this point execution is still in the FIQ mode.  The CPSR, point of
309@       interrupt, and all C scratch registers are available for use.  */
310@
311@    /* Interrupt nesting is allowed after calling _tx_thread_fiq_nesting_start
312@       from FIQ mode with interrupts disabled.  This routine switches to the
313@       system mode and returns with FIQ interrupts enabled.
314@
315@       NOTE:  It is very important to ensure all FIQ interrupts are cleared
316@       prior to enabling nested FIQ interrupts.  */
317#ifdef TX_ENABLE_FIQ_NESTING
318    BL      _tx_thread_fiq_nesting_start
319#endif
320@
321@    /* Application FIQ handlers can be called here!  */
322@
323@    /* If interrupt nesting was started earlier, the end of interrupt nesting
324@       service must be called before returning to _tx_thread_fiq_context_restore.  */
325#ifdef TX_ENABLE_FIQ_NESTING
326    BL      _tx_thread_fiq_nesting_end
327#endif
328@
329@    /* Jump to fiq context restore to restore system context.  */
330    B       _tx_thread_fiq_context_restore
331@
332@
333#else
334    .global  __tx_fiq_handler
335__tx_fiq_handler:
336    B       __tx_fiq_handler                    @ FIQ interrupt handler
337#endif
338@
339@
340BUILD_OPTIONS:
341    .word  _tx_build_options                    @ Reference to bring in
342VERSION_ID:
343    .word  _tx_version_id                       @ Reference to bring in
344
345
346
347