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; 34SVC_MODE EQU 0xD3 ; Disable IRQ/FIQ SVC mode 35IRQ_MODE EQU 0xD2 ; Disable IRQ/FIQ IRQ mode 36FIQ_MODE EQU 0xD1 ; Disable IRQ/FIQ FIQ mode 37SYS_MODE EQU 0xDF ; Disable IRQ/FIQ SYS mode 38HEAP_SIZE EQU 4096 ; Heap size 39FIQ_STACK_SIZE EQU 512 ; FIQ stack size 40SYS_STACK_SIZE EQU 1024 ; SYS stack size (used for nested interrupts) 41IRQ_STACK_SIZE EQU 1024 ; IRQ stack size 42; 43; 44;/* ARM11 ARMulator Timer and Interrupt controller information. This depends on 45; the ARMulator's Interrupt Controller and Timer being enabled in the default.ami. 46; In addition, the addresses must match those specified in the peripherals.ami file. 47; Please refer to section 2.10 and 4.16 of the Debug Target Guide, version 1.2. */ 48; 49IRQStatus EQU 0x0a000000 ; IRQ Status Register 50IRQRawStatus EQU 0x0a000004 ; IRQ Raw Status Register 51IRQEnable EQU 0x0a000008 ; IRQ Enable Set Register 52IRQEnableClear EQU 0x0a00000C ; IRQ Enable Clear Register 53IRQSoft EQU 0x0a000010 ; IRQ Soft 54FIQStatus EQU 0x0a000100 ; FIQ Status Register 55FIQRawStatus EQU 0x0a000104 ; FIQ Raw Status Register 56FIQEnable EQU 0x0a000108 ; FIQ Enable Set Register 57FIQEnableClear EQU 0x0a00010C ; FIQ Enable Clear Register 58 59TIMER1_BIT EQU 0x00000010 ; IRQ/FIQ Timer1 bit 60TIMER2_BIT EQU 0x00000020 ; IRQ/FIQ Timer2 bit 61 62Timer1Load EQU 0x0a800000 ; Timer1 Load Register 63Timer1Value EQU 0x0a800004 ; Timer1 Value Register 64Timer1Control EQU 0x0a800008 ; Timer1 Control Register 65Timer1Clear EQU 0x0a80000C ; Timer1 Clear Register 66 67Timer1Mode EQU 0x000000C0 ; Timer1 Control Value, Timer enable, periodic, no prescaler 68Timer1Period EQU 0x0000FFFF ; Timer1 count-down period, maximum value 69 70Timer2Load EQU 0x0a800020 ; Timer2 Load Register 71Timer2Value EQU 0x0a800024 ; Timer2 Value Register 72Timer2Control EQU 0x0a800028 ; Timer2 Control Register 73Timer2Clear EQU 0x0a80002C ; Timer2 Clear Register 74; 75; 76 IMPORT _tx_thread_system_stack_ptr 77 IMPORT _tx_initialize_unused_memory 78 IMPORT _tx_thread_context_save 79 IMPORT _tx_thread_context_restore 80 IF :DEF:TX_ENABLE_FIQ_SUPPORT 81 IMPORT _tx_thread_fiq_context_save 82 IMPORT _tx_thread_fiq_context_restore 83 ENDIF 84 IF :DEF:TX_ENABLE_IRQ_NESTING 85 IMPORT _tx_thread_irq_nesting_start 86 IMPORT _tx_thread_irq_nesting_end 87 ENDIF 88 IF :DEF:TX_ENABLE_FIQ_NESTING 89 IMPORT _tx_thread_fiq_nesting_start 90 IMPORT _tx_thread_fiq_nesting_end 91 ENDIF 92 IMPORT _tx_timer_interrupt 93 IMPORT __main 94 IMPORT _tx_version_id 95 IMPORT _tx_build_options 96 IMPORT |Image$$ZI$$Limit| 97; 98; 99 AREA Init, CODE, READONLY 100; 101;/* Define the ARM11 vector area. This should be located or copied to 0. */ 102; 103 EXPORT __vectors 104__vectors 105 LDR pc,=__main ; Reset goes to startup function 106 LDR pc,=__tx_undefined ; Undefined handler 107 LDR pc,=__tx_swi_interrupt ; Software interrupt handler 108 LDR pc,=__tx_prefetch_handler ; Prefetch exception handler 109 LDR pc,=__tx_abort_handler ; Abort exception handler 110 LDR pc,=__tx_reserved_handler ; Reserved exception handler 111 LDR pc,=__tx_irq_handler ; IRQ interrupt handler 112 LDR pc,=__tx_fiq_handler ; FIQ interrupt handler 113; 114; 115 AREA ||.text||, CODE, READONLY 116;/**************************************************************************/ 117;/* */ 118;/* FUNCTION RELEASE */ 119;/* */ 120;/* _tx_initialize_low_level ARM11/AC5 */ 121;/* 6.1 */ 122;/* AUTHOR */ 123;/* */ 124;/* William E. Lamie, Microsoft Corporation */ 125;/* */ 126;/* DESCRIPTION */ 127;/* */ 128;/* This function is responsible for any low-level processor */ 129;/* initialization, including setting up interrupt vectors, setting */ 130;/* up a periodic timer interrupt source, saving the system stack */ 131;/* pointer for use in ISR processing later, and finding the first */ 132;/* available RAM memory address for tx_application_define. */ 133;/* */ 134;/* INPUT */ 135;/* */ 136;/* None */ 137;/* */ 138;/* OUTPUT */ 139;/* */ 140;/* None */ 141;/* */ 142;/* CALLS */ 143;/* */ 144;/* None */ 145;/* */ 146;/* CALLED BY */ 147;/* */ 148;/* _tx_initialize_kernel_enter ThreadX entry function */ 149;/* */ 150;/* RELEASE HISTORY */ 151;/* */ 152;/* DATE NAME DESCRIPTION */ 153;/* */ 154;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ 155;/* */ 156;/**************************************************************************/ 157;VOID _tx_initialize_low_level(VOID) 158;{ 159 EXPORT _tx_initialize_low_level 160_tx_initialize_low_level 161; 162; 163; /****** NOTE ****** We must be in SVC MODE at this point. Some monitors 164; enter this routine in USER mode and require a software interrupt to 165; change into SVC mode. */ 166; 167 LDR r1, =|Image$$ZI$$Limit| ; Get end of non-initialized RAM area 168 LDR r2, =HEAP_SIZE ; Pickup the heap size 169 ADD r1, r2, r1 ; Setup heap limit 170 ADD r1, r1, #4 ; Setup stack limit 171; 172 IF :DEF:TX_ENABLE_IRQ_NESTING 173; /* Setup the system mode stack for nested interrupt support */ 174 LDR r2, =SYS_STACK_SIZE ; Pickup stack size 175 MOV r3, #SYS_MODE ; Build SYS mode CPSR 176 MSR CPSR_cxsf, r3 ; Enter SYS mode 177 ADD r1, r1, r2 ; Calculate start of SYS stack 178 BIC r1, r1, #7 ; Ensure 8-byte alignment 179 MOV sp, r1 ; Setup SYS stack pointer 180 ENDIF 181; 182 LDR r2, =FIQ_STACK_SIZE ; Pickup stack size 183 MOV r0, #FIQ_MODE ; Build FIQ mode CPSR 184 MSR CPSR_c, r0 ; Enter FIQ mode 185 ADD r1, r1, r2 ; Calculate start of FIQ stack 186 BIC r1, r1, #7 ; Ensure 8-byte alignment 187 MOV sp, r1 ; Setup FIQ stack pointer 188 MOV sl, #0 ; Clear sl 189 MOV fp, #0 ; Clear fp 190 LDR r2, =IRQ_STACK_SIZE ; Pickup IRQ (system stack size) 191 MOV r0, #IRQ_MODE ; Build IRQ mode CPSR 192 MSR CPSR_c, r0 ; Enter IRQ mode 193 ADD r1, r1, r2 ; Calculate start of IRQ stack 194 BIC r1, r1, #7 ; Ensure 8-byte alignment 195 MOV sp, r1 ; Setup IRQ stack pointer 196 MOV r0, #SVC_MODE ; Build SVC mode CPSR 197 MSR CPSR_c, r0 ; Enter SVC mode 198 LDR r3, =_tx_thread_system_stack_ptr ; Pickup stack pointer 199 STR r1, [r3, #0] ; Save the system stack 200; 201; /* Save the system stack pointer. */ 202; _tx_thread_system_stack_ptr = (VOID_PTR) (sp); 203; 204 LDR r1, =_tx_thread_system_stack_ptr ; Pickup address of system stack ptr 205 LDR r0, [r1, #0] ; Pickup system stack 206 ADD r0, r0, #4 ; Increment to next free word 207; 208; /* Save the first available memory address. */ 209; _tx_initialize_unused_memory = (VOID_PTR) |Image$$ZI$$Limit| + HEAP + [SYS_STACK] + FIQ_STACK + IRQ_STACK; 210; 211 LDR r2, =_tx_initialize_unused_memory ; Pickup unused memory ptr address 212 STR r0, [r2, #0] ; Save first free memory address 213; 214; /* Setup Timer for periodic interrupts. */ 215; 216; /* Setup ARMulator Timer1 for periodic interrupts. */ 217; 218 LDR r0,=IRQEnable ; Build address of IRQ enable register 219 LDR r1,=TIMER1_BIT ; Build value of Timer1 IRQ enable 220 STR r1,[r0] ; Enable IRQ interrupts for Timer1 221 222 LDR r0,=Timer1Load ; Build address of Timer1 load register 223 LDR r1,=Timer1Period ; Build Timer1 periodic value 224 STR r1,[r0] ; Set Timer1 load value 225 226 LDR r0,=Timer1Control ; Build address of Timer1 control register 227 LDR r1,=Timer1Mode ; Build Timer1 control value 228 STR r1,[r0] ; Enable Timer1 229; 230; /* Done, return to caller. */ 231; 232 IF {INTER} = {TRUE} 233 BX lr ; Return to caller 234 ELSE 235 MOV pc, lr ; Return to caller 236 ENDIF 237;} 238; 239; 240;/* Define initial heap/stack routine for the ARM RealView (and ADS) startup code. This 241; routine will set the initial stack to use the ThreadX IRQ & FIQ & 242; (optionally SYS) stack areas. */ 243; 244 EXPORT __user_initial_stackheap 245__user_initial_stackheap 246 LDR r0, =|Image$$ZI$$Limit| ; Get end of non-initialized RAM area 247 LDR r2, =HEAP_SIZE ; Pickup the heap size 248 ADD r2, r2, r0 ; Setup heap limit 249 ADD r3, r2, #4 ; Setup stack limit 250 MOV r1, r3 ; Setup start of stack 251 IF :DEF:TX_ENABLE_IRQ_NESTING 252 LDR r12, =SYS_STACK_SIZE ; Pickup IRQ system stack 253 ADD r1, r1, r12 ; Setup the return system stack 254 BIC r1, r1, #7 ; Ensure 8-byte alignment 255 ENDIF 256 LDR r12, =FIQ_STACK_SIZE ; Pickup FIQ stack size 257 ADD r1, r1, r12 ; Setup the return system stack 258 BIC r1, r1, #7 ; Ensure 8-byte alignment 259 LDR r12, =IRQ_STACK_SIZE ; Pickup IRQ system stack 260 ADD r1, r1, r12 ; Setup the return system stack 261 BIC r1, r1, #7 ; Ensure 8-byte alignment 262 IF {INTER} = {TRUE} 263 BX lr ; Return to caller 264 ELSE 265 MOV pc, lr ; Return to caller 266 ENDIF 267; 268; 269;/* Define shells for each of the interrupt vectors. */ 270; 271 EXPORT __tx_undefined 272__tx_undefined 273 B __tx_undefined ; Undefined handler 274; 275 EXPORT __tx_swi_interrupt 276__tx_swi_interrupt 277 B __tx_swi_interrupt ; Software interrupt handler 278; 279 EXPORT __tx_prefetch_handler 280__tx_prefetch_handler 281 B __tx_prefetch_handler ; Prefetch exception handler 282; 283 EXPORT __tx_abort_handler 284__tx_abort_handler 285 B __tx_abort_handler ; Abort exception handler 286; 287 EXPORT __tx_reserved_handler 288__tx_reserved_handler 289 B __tx_reserved_handler ; Reserved exception handler 290; 291; 292 EXPORT __tx_irq_handler 293 EXPORT __tx_irq_processing_return 294__tx_irq_handler 295; 296; /* Jump to context save to save system context. */ 297 B _tx_thread_context_save 298__tx_irq_processing_return 299; 300; /* At this point execution is still in the IRQ mode. The CPSR, point of 301; interrupt, and all C scratch registers are available for use. In 302; addition, IRQ interrupts may be re-enabled - with certain restrictions - 303; if nested IRQ interrupts are desired. Interrupts may be re-enabled over 304; small code sequences where lr is saved before enabling interrupts and 305; restored after interrupts are again disabled. */ 306; 307; 308; /* Check for Timer1 interrupts on the ARMulator. */ 309 310 LDR r1,=IRQStatus ; Pickup address of IRQStatus register 311 LDR r2, [r1] ; Read IRQStatus 312 LDR r0,=TIMER1_BIT ; Pickup Timer1 interrupt present bit 313 AND r2, r2, r0 ; Is this a timer interrupt? 314 CMP r2, r0 ; 315 BNE _tx_not_timer_interrupt ; If 0, not a timer interrupt 316 317 LDR r1,=Timer1Clear ; Build address of Timer1 clear register 318 MOV r0,#0 ; 319 STR r0, [r1] ; Clear timer 0 interrupt 320 321 BL _tx_timer_interrupt ; Timer interrupt handler 322_tx_not_timer_interrupt 323; 324; /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start 325; from IRQ mode with interrupts disabled. This routine switches to the 326; system mode and returns with IRQ interrupts enabled. 327; 328; NOTE: It is very important to ensure all IRQ interrupts are cleared 329; prior to enabling nested IRQ interrupts. */ 330 IF :DEF:TX_ENABLE_IRQ_NESTING 331 BL _tx_thread_irq_nesting_start 332 ENDIF 333; 334; 335; /* Application IRQ handlers can be called here! */ 336; 337; /* If interrupt nesting was started earlier, the end of interrupt nesting 338; service must be called before returning to _tx_thread_context_restore. 339; This routine returns in processing in IRQ mode with interrupts disabled. */ 340 IF :DEF:TX_ENABLE_IRQ_NESTING 341 BL _tx_thread_irq_nesting_end 342 ENDIF 343; 344; /* Jump to context restore to restore system context. */ 345 B _tx_thread_context_restore 346; 347; 348; /* This is an example of a vectored IRQ handler. */ 349; 350 EXPORT __tx_example_vectored_irq_handler 351__tx_example_vectored_irq_handler 352; 353; 354; /* Save initial context and call context save to prepare for 355; vectored ISR execution. */ 356; 357; STMDB sp!, {r0-r3} ; Save some scratch registers 358; MRS r0, SPSR ; Pickup saved SPSR 359; SUB lr, lr, #4 ; Adjust point of interrupt 360; STMDB sp!, {r0, r10, r12, lr} ; Store other scratch registers 361; BL _tx_thread_vectored_context_save ; Vectored context save 362; 363; /* At this point execution is still in the IRQ mode. The CPSR, point of 364; interrupt, and all C scratch registers are available for use. In 365; addition, IRQ interrupts may be re-enabled - with certain restrictions - 366; if nested IRQ interrupts are desired. Interrupts may be re-enabled over 367; small code sequences where lr is saved before enabling interrupts and 368; restored after interrupts are again disabled. */ 369; 370; 371; /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start 372; from IRQ mode with interrupts disabled. This routine switches to the 373; system mode and returns with IRQ interrupts enabled. 374; 375; NOTE: It is very important to ensure all IRQ interrupts are cleared 376; prior to enabling nested IRQ interrupts. */ 377; IF :DEF:TX_ENABLE_IRQ_NESTING 378; BL _tx_thread_irq_nesting_start 379; ENDIF 380; 381; /* Application IRQ handlers can be called here! */ 382; 383; /* If interrupt nesting was started earlier, the end of interrupt nesting 384; service must be called before returning to _tx_thread_context_restore. 385; This routine returns in processing in IRQ mode with interrupts disabled. */ 386; IF :DEF:TX_ENABLE_IRQ_NESTING 387; BL _tx_thread_irq_nesting_end 388; ENDIF 389; 390; /* Jump to context restore to restore system context. */ 391; B _tx_thread_context_restore 392; 393; 394 IF :DEF:TX_ENABLE_FIQ_SUPPORT 395 EXPORT __tx_fiq_handler 396 EXPORT __tx_fiq_processing_return 397__tx_fiq_handler 398; 399; /* Jump to fiq context save to save system context. */ 400 B _tx_thread_fiq_context_save 401__tx_fiq_processing_return 402; 403; /* At this point execution is still in the FIQ mode. The CPSR, point of 404; interrupt, and all C scratch registers are available for use. */ 405; 406; /* Interrupt nesting is allowed after calling _tx_thread_fiq_nesting_start 407; from FIQ mode with interrupts disabled. This routine switches to the 408; system mode and returns with FIQ interrupts enabled. 409; 410; NOTE: It is very important to ensure all FIQ interrupts are cleared 411; prior to enabling nested FIQ interrupts. */ 412 IF :DEF:TX_ENABLE_FIQ_NESTING 413 BL _tx_thread_fiq_nesting_start 414 ENDIF 415; 416; /* Application FIQ handlers can be called here! */ 417; 418; /* If interrupt nesting was started earlier, the end of interrupt nesting 419; service must be called before returning to _tx_thread_fiq_context_restore. */ 420 IF :DEF:TX_ENABLE_FIQ_NESTING 421 BL _tx_thread_fiq_nesting_end 422 ENDIF 423; 424; /* Jump to fiq context restore to restore system context. */ 425 B _tx_thread_fiq_context_restore 426; 427; 428 ELSE 429 EXPORT __tx_fiq_handler 430__tx_fiq_handler 431 B __tx_fiq_handler ; FIQ interrupt handler 432 ENDIF 433; 434; /* Reference build options and version ID to ensure they come in. */ 435; 436 LDR r2, =_tx_build_options ; Pickup build options variable address 437 LDR r0, [r2, #0] ; Pickup build options content 438 LDR r2, =_tx_version_id ; Pickup version ID variable address 439 LDR r0, [r2, #0] ; Pickup version ID content 440; 441; 442 END 443 444