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