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