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/** Thread */ 19/** */ 20/**************************************************************************/ 21/**************************************************************************/ 22 23 EXTERN __tx_thread_execute_ptr 24 EXTERN __tx_thread_current_ptr 25 EXTERN __tx_timer_time_slice 26 IMPORT __txm_module_manager_kernel_dispatch 27 IMPORT __tx_thread_system_state 28 EXTERN __txm_module_manager_memory_fault_info 29 EXTERN __txm_module_manager_memory_fault_handler 30 31 section .text:CODE:ROOT 32 33/**************************************************************************/ 34/* */ 35/* FUNCTION RELEASE */ 36/* */ 37/* _tx_thread_schedule RXv2/IAR */ 38/* 6.1.10 */ 39/* AUTHOR */ 40/* */ 41/* Scott Larson, Microsoft Corporation */ 42/* */ 43/* DESCRIPTION */ 44/* */ 45/* This function waits for a thread control block pointer to appear in */ 46/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ 47/* in the variable, the corresponding thread is resumed. */ 48/* */ 49/* INPUT */ 50/* */ 51/* None */ 52/* */ 53/* OUTPUT */ 54/* */ 55/* None */ 56/* */ 57/* CALLS */ 58/* */ 59/* None */ 60/* */ 61/* CALLED BY */ 62/* */ 63/* _tx_initialize_kernel_enter ThreadX entry function */ 64/* _tx_thread_system_return Return to system from thread */ 65/* _tx_thread_context_restore Restore thread's context */ 66/* */ 67/* RELEASE HISTORY */ 68/* */ 69/* DATE NAME DESCRIPTION */ 70/* */ 71/* 12-30-2020 William E. Lamie Initial Version 6.1.3 */ 72/* 10-15-2021 William E. Lamie Modified comment(s), and */ 73/* removed unnecessary stack */ 74/* type checking, */ 75/* resulting in version 6.1.9 */ 76/* */ 77/**************************************************************************/ 78// VOID _tx_thread_schedule(VOID) 79// { 80 public __tx_thread_schedule 81__tx_thread_schedule: 82 83 /* Enable interrupts. */ 84 85 SETPSW I 86 87 /* Wait for a thread to execute. */ 88 // do 89 // { 90 MOV.L #__tx_thread_execute_ptr, R1 // Address of thread to executer ptr 91__tx_thread_schedule_loop: 92 MOV.L [R1],R2 // Pickup next thread to execute 93 CMP #0,R2 // Is it NULL? 94 BEQ __tx_thread_schedule_loop // Yes, idle system, keep checking 95 96 // } 97 // while(_tx_thread_execute_ptr == TX_NULL); 98 99 /* Yes! We have a thread to execute. Lockout interrupts and transfer control to it. */ 100 101 CLRPSW I // Disable interrupts 102 103 /* Setup the current thread pointer. */ 104 // _tx_thread_current_ptr = _tx_thread_execute_ptr; 105 106 MOV.L #__tx_thread_current_ptr, R3 107 MOV.L R2,[R3] // Setup current thread pointer 108 109 /* Increment the run count for this thread. */ 110 // _tx_thread_current_ptr -> tx_thread_run_count++; 111 112 MOV.L 4[R2],R3 // Pickup run count 113 ADD #1,R3 // Increment run counter 114 MOV.L R3,4[R2] // Store it back in control block 115 116 /* Setup time-slice, if present. */ 117 // _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; 118 119 MOV.L 24[R2],R3 // Pickup thread time-slice 120 MOV.L #__tx_timer_time_slice,R4 // Pickup pointer to time-slice 121 MOV.L R3, [R4] // Setup time-slice 122 123 /* Switch to the thread's stack. */ 124 // SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; 125 SETPSW U // User stack mode 126 MOV.L 8[R2],SP // Pickup stack pointer 127 128 129 /* Set up MPU. */ 130 // Disable MPU 131 MOV.L #0x00086500,R1 // Pickup MPEN 132 MOV #0,R3 // Build disable value 133 MOV.L R3,[R1] // Disable MPU 134 // Determine if protection for this thread is required 135 MOV.L 156[R2],R1 // Pickup user_mode 136 CMP #0,R1 // Is protection required for this thread? 137 BEQ skip_mpu_setup // No, skip MPU setup 138 139 MOV.L #0x00086408,R1 // Region 1 Start Page Register address 140 MOV.L 144[R2],R2 // Address of module instance ptr at offset 144 in TCB 141 ADD #100,R2,R2 // Get address of MPU table in module struct, starting at region 1 142 143 // Region 0 (Trampoline from User mode to ThreadX) set up in txm_module_manager_setup_mpu_registers.c 144 145 // Build region 1 (User code) 146 MOV.L [R2+],R4 // Pickup region 1 start page, increment to region 1 end page 147 MOV.L R4,[R1+] // Setup region 1 start page reg, increment to region 1 end page reg. 148 MOV.L [R2+],R4 // Pickup region 1 end page, increment to region 2 start page 149 MOV.L R4,[R1+] // Setup region 1 end page reg, increment to region 2 start page reg. 150 151 // Build region 2 (User data) 152 MOV.L [R2+],R4 // Pickup region 2 start page, increment to region 2 end page 153 MOV.L R4,[R1+] // Setup region 2 start page reg, increment to region 2 end page reg. 154 MOV.L [R2+],R4 // Pickup region 2 end page, increment to region 3 start page 155 MOV.L R4,[R1+] // Setup region 2 end page reg, increment to region 3 start page reg. 156 157 // Build region 3 (Shared memory) 158 MOV.L [R2+],R4 // Pickup region 3 start page, increment to region 3 end page 159 MOV.L R4,[R1+] // Setup region 3 start page reg, increment to region 3 end page reg. 160 MOV.L [R2+],R4 // Pickup region 3 end page, increment to region 4 start page 161 MOV.L R4,[R1+] // Setup region 3 end page reg, increment to region 4 start page reg. 162 163 // Region 4-7 unused 164 165 // Setup background region 166 MOV.L #0x00086504,R1 // Pickup MPBAC 167 MOV #0,[R1] // Read/Write/Execute prohibited. 168 // Enable MPU 169 MOV.L #0x00086500,R1 // Pickup MPEN 170 MOV #1,[R1] // Enable MPU 171 172skip_mpu_setup 173 174 POPM R1-R3 // Restore accumulators. 175 MVTACLO R3, A0 176 MVTACHI R2, A0 177 MVTACGU R1, A0 178 POPM R1-R3 179 MVTACLO R3, A1 180 MVTACHI R2, A1 181 MVTACGU R1, A1 182 183 POPM R6-R13 // Recover interrupt stack frame 184 POPC FPSW 185 POPM R14-R15 186 POPM R3-R5 187 POPM R1-R2 188 RTE // Return to point of interrupt, this restores PC and PSW 189 190// } 191 192 extern __tx_thread_context_save 193 extern __tx_thread_context_restore 194 195/* Software triggered interrupt used to perform context switches. 196 The priority of this interrupt is set to the lowest priority within 197 tx_initialize_low_level() and triggered by ThreadX when calling 198 _tx_thread_system_return(). */ 199 200 public ___interrupt_27 201___interrupt_27: 202 203 PUSHM R1-R2 204 205 BSR __tx_thread_context_save 206 207 BRA __tx_thread_context_restore 208 209 210/* You may have to modify BSP to use this handler. 211 // MPU Memory access violation 212 PUBLIC ___excep_access_inst 213 PUBLIC ___violation_handler 214___excep_access_inst 215___violation_handler 216 // Disable interrupts 217 CLRPSW I // disable interrupts 218 // Save contents of R1 and R2 219 PUSH R1 220 PUSH R2 221 // Increment and save system state 222 MOV.L #__tx_thread_system_state, R1 // Pickup address of system state 223 MOV.L [R1], R2 // Pickup system state 224 ADD #1, R2 // Increment 225 MOV.L R2, [R1] // Store new system state 226 227 // Now pickup and store all the fault related information. 228 229 MOV.L #__txm_module_manager_memory_fault_info, R1 230 MOV.L #__tx_thread_current_ptr, R2 // Build current thread pointer address 231 MOV.L [R2], R2 // Pickup the current thread pointer 232 MOV.L R2, 0[R1] // Save current thread pointer in fault info structure 233 MOV.L 8[SP], R2 // Pickup instruction address at point of fault 234 MOV.L R2, 4[R1] // Save point of fault 235 MOV.L #0x0008650C, R2 // Pickup Memory-Protection Error Status Register 236 MOV.L [R2], 8[R1] // Save MPESTS 237 MOV.L #0x00086514, R2 // Pickup Data Memory-Protection Error Address Register 238 MOV.L [R2], 12[R1] // Save MPDEA 239 MOV.L #0x00086528, R2 // Pickup Instruction Hit Region Register 240 MOV.L [R2], 16[R1] // Save MHITI 241 MOV.L #0x0008652C, R2 // Pickup Data Hit Region Register 242 MOV.L [R2], 20[R1] // Save MHITD 243 MOV.L 12[SP], R2 // Pickup PSW 244 MOV.L R2, 24[R1] // Save PSW 245 MVFC USP, R2 // Pickup user stack pointer 246 MOV.L R2, 28[R1] // Save user stack pointer 247 MOV.L R3, 40[R1] // Save R3 248 MOV.L R4, 44[R1] // Save R4 249 MOV.L R5, 48[R1] // Save R5 250 MOV.L R6, 52[R1] // Save R6 251 MOV.L R7, 56[R1] // Save R7 252 MOV.L R8, 60[R1] // Save R8 253 MOV.L R9, 64[R1] // Save R9 254 MOV.L R10, 68[R1] // Save R10 255 MOV.L R11, 72[R1] // Save R11 256 MOV.L R12, 76[R1] // Save R12 257 MOV.L R13, 80[R1] // Save R13 258 MOV.L R14, 84[R1] // Save R14 259 MOV.L R15, 84[R1] // Save R15 260 POP R3 // Recall R1 261 MOV.L R3, 32[R1] // Save R1 262 POP R3 // Recall R2 263 MOV.L R3, 36[R1] // Save R2 264 265 BSR __txm_module_manager_memory_fault_handler // Call memory manager fault handler 266 267 // Decrement and save system state 268 MOV.L #__tx_thread_system_state, R1 // Pickup address of system state 269 MOV.L [R1], R2 // Pickup system state 270 SUB #1, R2 // Decrement 271 MOV.L R2, [R1] // Store new system state 272 273 MOV.L #__tx_thread_current_ptr, R2 // Pickup address of current thread pointer 274 MOV.L #0, [R2] // Clear current thread pointer 275 BRA __tx_thread_schedule // Attempt to schedule the next thread 276*/ 277 278 279 public ___interrupt_26 280___interrupt_26: 281 PUBLIC __txm_module_manager_kernel 282__txm_module_manager_kernel 283 284 MOV.L [SP], R5 // Get return address 285 CMP #__txm_module_manager_user_mode_entry+3, R5 // Did we come from user_mode_entry? 286 BEQ __txm_module_manager_entry // If so, continue. 287 RTE // If not, then return from where we came. 288 289__txm_module_manager_entry 290 // We are entering the kernel from a module thread with user mode selected. 291 // At this point, we are out of user mode! 292 // Clear current user mode. 293 MOV.L #__tx_thread_current_ptr, R5 294 MOV [R5],R5 295 MOV #0,152[R5] 296 297 // Switch to kernel stack 298 PUSHM R1-R2 299 MVFC USP, R1 // Pickup module thread stack pointer 300 MOV.L R1, 172[R5] // Save module thread stack pointer 301 MOV.L 164[R5], R1 // Pickup kernel stack end 302#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE 303 MOV.L R1, 16[R5] // Set stack end 304 MOV.L 160[R5], R2 // Pickup kernel stack start 305 MOV.L R2, 12[R5] // Set stack start 306 MOV.L 168[R5], R2 // Pickup kernel stack size 307 MOV.L R2, 20[R5] // Set stack size 308#endif 309 MVTC R1, USP // Set stack pointer 310 POPM R1-R2 311 312 // Modify PSW in ISP to return in supervisor mode and user stack 313 MOV.L 4[SP], R5 314 BCLR #20, R5 315 MOV.L R5, 4[SP] 316 317 // Return to user_mode_entry where kernel_dispatch will be called. 318 RTE 319 320 321 322 SECTION CODE:CODE (4) // Align 4, smallest page size for MPU is 16 bytes. 323 ALIGN 4 324 PUBLIC __txm_module_manager_user_mode_entry 325__txm_module_manager_user_mode_entry 326 327 INT #26 // Enter ThreadX kernel (exit User mode). 328 329 // At this point, we are out of user mode. 330 // Simply call the kernel dispatch function. 331 MOV.L #__txm_module_manager_kernel_dispatch,R5 332 JSR R5 333 334 // Restore user mode while inside of ThreadX. 335 MOV.L #__tx_thread_current_ptr, R5 336 MOV [R5],R5 337 MOV #1,152[R5] 338 339 // Switch to module thread stack 340#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE 341 PUSH R1 342 MOV.L 176[R5], R1 // Pickup module thread stack start 343 MOV.L R1, 12[R5] // Set stack start 344 MOV.L 180[R5], R1 // Pickup module thread stack end 345 MOV.L R1, 16[R5] // Set stack end 346 MOV.L 184[R5], R1 // Pickup kernel stack size 347 MOV.L R1, 20[R5] // Set stack size 348 POP R1 349#endif 350 MOV.L 172[R5], R5 // Pickup module thread stack pointer 351 MVTC R5, USP // Set stack pointer 352 353 354 // USP is set for an RTS, need to set for RTE to set User mode in PSW. 355 // Push return address on SP 356 MOV.L [SP],R5 357 PUSH R5 358 // Set user mode and place PSW in prev position in SP 359 MVFC PSW,R5 360 BSET #20,R5 361 MOV.L R5,4[SP] 362 RTE 363 364 // Fill rest of page with NOPs. 365 NOP 366 NOP 367 NOP 368 NOP 369 370 NOP 371 NOP 372 NOP 373 NOP 374 375 NOP 376 NOP 377 NOP 378 NOP 379 380 END 381