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