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