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#include "tx_port.h"
23
24    .section .text
25/**************************************************************************/
26/*                                                                        */
27/*  FUNCTION                                               RELEASE        */
28/*                                                                        */
29/*    _tx_thread_context_save                            RISC-V64/GNU     */
30/*                                                           6.2.1        */
31/*  AUTHOR                                                                */
32/*                                                                        */
33/*    Scott Larson, Microsoft Corporation                                 */
34/*                                                                        */
35/*  DESCRIPTION                                                           */
36/*                                                                        */
37/*    This function saves the context of an executing thread in the       */
38/*    beginning of interrupt processing.  The function also ensures that  */
39/*    the system stack is used upon return to the calling ISR.            */
40/*                                                                        */
41/*  INPUT                                                                 */
42/*                                                                        */
43/*    None                                                                */
44/*                                                                        */
45/*  OUTPUT                                                                */
46/*                                                                        */
47/*    None                                                                */
48/*                                                                        */
49/*  CALLS                                                                 */
50/*                                                                        */
51/*    None                                                                */
52/*                                                                        */
53/*  CALLED BY                                                             */
54/*                                                                        */
55/*    ISRs                                                                */
56/*                                                                        */
57/*  RELEASE HISTORY                                                       */
58/*                                                                        */
59/*    DATE              NAME                      DESCRIPTION             */
60/*                                                                        */
61/*  03-08-2023      Scott Larson            Initial Version 6.2.1         */
62/*                                                                        */
63/**************************************************************************/
64/* VOID   _tx_thread_context_save(VOID)
65{  */
66    .global      _tx_thread_context_save
67_tx_thread_context_save:
68
69    /* Upon entry to this routine, it is assumed that interrupts are locked
70       out and the interrupt stack fame has been allocated and x1 (ra) has
71       been saved on the stack. */
72
73    STORE   x5, 19*REGBYTES(sp)                         // First store t0 and t1
74    STORE   x6, 18*REGBYTES(sp)
75
76    la      x5, _tx_thread_system_state                 // Pickup address of system state
77    LOAD    x6, 0(x5)                                   // Pickup system state
78
79    /* Check for a nested interrupt condition.  */
80    /* if (_tx_thread_system_state++)
81    {  */
82    beqz    x6, _tx_thread_not_nested_save              // If 0, first interrupt condition
83    addi    x6, x6, 1                                   // Increment the interrupt counter
84    STORE   x6, 0(x5)                                   // Store the interrupt counter
85
86    /* Nested interrupt condition.
87       Save the reset of the scratch registers on the stack and return to the
88       calling ISR.  */
89
90    STORE   x7,  17*REGBYTES(sp)                        // Store t2
91    STORE   x8,  12*REGBYTES(sp)                        // Store s0
92    STORE   x10, 27*REGBYTES(sp)                        // Store a0
93    STORE   x11, 26*REGBYTES(sp)                        // Store a1
94    STORE   x12, 25*REGBYTES(sp)                        // Store a2
95    STORE   x13, 24*REGBYTES(sp)                        // Store a3
96    STORE   x14, 23*REGBYTES(sp)                        // Store a4
97    STORE   x15, 22*REGBYTES(sp)                        // Store a5
98    STORE   x16, 21*REGBYTES(sp)                        // Store a6
99    STORE   x17, 20*REGBYTES(sp)                        // Store a7
100    STORE   x28, 16*REGBYTES(sp)                        // Store t3
101    STORE   x29, 15*REGBYTES(sp)                        // Store t4
102    STORE   x30, 14*REGBYTES(sp)                        // Store t5
103    STORE   x31, 13*REGBYTES(sp)                        // Store t6
104    csrr    t0, mepc                                    // Load exception program counter
105    STORE   t0, 30*REGBYTES(sp)                         // Save it on the stack
106
107    /* Save floating point scratch registers.  */
108#if defined(__riscv_float_abi_single)
109    fsw     f0, 31*REGBYTES(sp)                         // Store ft0
110    fsw     f1, 32*REGBYTES(sp)                         // Store ft1
111    fsw     f2, 33*REGBYTES(sp)                         // Store ft2
112    fsw     f3, 34*REGBYTES(sp)                         // Store ft3
113    fsw     f4, 35*REGBYTES(sp)                         // Store ft4
114    fsw     f5, 36*REGBYTES(sp)                         // Store ft5
115    fsw     f6, 37*REGBYTES(sp)                         // Store ft6
116    fsw     f7, 38*REGBYTES(sp)                         // Store ft7
117    fsw     f10,41*REGBYTES(sp)                         // Store fa0
118    fsw     f11,42*REGBYTES(sp)                         // Store fa1
119    fsw     f12,43*REGBYTES(sp)                         // Store fa2
120    fsw     f13,44*REGBYTES(sp)                         // Store fa3
121    fsw     f14,45*REGBYTES(sp)                         // Store fa4
122    fsw     f15,46*REGBYTES(sp)                         // Store fa5
123    fsw     f16,47*REGBYTES(sp)                         // Store fa6
124    fsw     f17,48*REGBYTES(sp)                         // Store fa7
125    fsw     f28,59*REGBYTES(sp)                         // Store ft8
126    fsw     f29,60*REGBYTES(sp)                         // Store ft9
127    fsw     f30,61*REGBYTES(sp)                         // Store ft10
128    fsw     f31,62*REGBYTES(sp)                         // Store ft11
129    csrr    t0, fcsr
130    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
131#elif defined(__riscv_float_abi_double)
132    fsd     f0, 31*REGBYTES(sp)                         // Store ft0
133    fsd     f1, 32*REGBYTES(sp)                         // Store ft1
134    fsd     f2, 33*REGBYTES(sp)                         // Store ft2
135    fsd     f3, 34*REGBYTES(sp)                         // Store ft3
136    fsd     f4, 35*REGBYTES(sp)                         // Store ft4
137    fsd     f5, 36*REGBYTES(sp)                         // Store ft5
138    fsd     f6, 37*REGBYTES(sp)                         // Store ft6
139    fsd     f7, 38*REGBYTES(sp)                         // Store ft7
140    fsd     f10,41*REGBYTES(sp)                         // Store fa0
141    fsd     f11,42*REGBYTES(sp)                         // Store fa1
142    fsd     f12,43*REGBYTES(sp)                         // Store fa2
143    fsd     f13,44*REGBYTES(sp)                         // Store fa3
144    fsd     f14,45*REGBYTES(sp)                         // Store fa4
145    fsd     f15,46*REGBYTES(sp)                         // Store fa5
146    fsd     f16,47*REGBYTES(sp)                         // Store fa6
147    fsd     f17,48*REGBYTES(sp)                         // Store fa7
148    fsd     f28,59*REGBYTES(sp)                         // Store ft8
149    fsd     f29,60*REGBYTES(sp)                         // Store ft9
150    fsd     f30,61*REGBYTES(sp)                         // Store ft10
151    fsd     f31,62*REGBYTES(sp)                         // Store ft11
152    csrr    t0, fcsr
153    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
154#endif
155
156#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
157    call    _tx_execution_isr_enter                     // Call the ISR execution enter function
158#endif
159
160    ret                                                 // Return to calling ISR
161
162_tx_thread_not_nested_save:
163    /* }  */
164
165    /* Otherwise, not nested, check to see if a thread was running.  */
166    /* else if (_tx_thread_current_ptr)
167    {  */
168    addi    x6, x6, 1                                   // Increment the interrupt counter
169    STORE   x6, 0(x5)                                   // Store the interrupt counter
170
171    /* Not nested: Find the user thread that was running and load our SP */
172
173    LOAD    x5, _tx_thread_current_ptr                  // Pickup current thread pointer
174    beqz    x5, _tx_thread_idle_system_save             // If NULL, idle system was interrupted
175
176    /* Save the standard scratch registers.  */
177
178    STORE   x7,  17*REGBYTES(sp)                        // Store t2
179    STORE   x8,  12*REGBYTES(sp)                        // Store s0
180    STORE   x10, 27*REGBYTES(sp)                        // Store a0
181    STORE   x11, 26*REGBYTES(sp)                        // Store a1
182    STORE   x12, 25*REGBYTES(sp)                        // Store a2
183    STORE   x13, 24*REGBYTES(sp)                        // Store a3
184    STORE   x14, 23*REGBYTES(sp)                        // Store a4
185    STORE   x15, 22*REGBYTES(sp)                        // Store a5
186    STORE   x16, 21*REGBYTES(sp)                        // Store a6
187    STORE   x17, 20*REGBYTES(sp)                        // Store a7
188    STORE   x28, 16*REGBYTES(sp)                        // Store t3
189    STORE   x29, 15*REGBYTES(sp)                        // Store t4
190    STORE   x30, 14*REGBYTES(sp)                        // Store t5
191    STORE   x31, 13*REGBYTES(sp)                        // Store t6
192
193    csrr    t0, mepc                                    // Load exception program counter
194    STORE   t0, 30*REGBYTES(sp)                         // Save it on the stack
195
196    /* Save floating point scratch registers.  */
197#if defined(__riscv_float_abi_single)
198    fsw     f0, 31*REGBYTES(sp)                         // Store ft0
199    fsw     f1, 32*REGBYTES(sp)                         // Store ft1
200    fsw     f2, 33*REGBYTES(sp)                         // Store ft2
201    fsw     f3, 34*REGBYTES(sp)                         // Store ft3
202    fsw     f4, 35*REGBYTES(sp)                         // Store ft4
203    fsw     f5, 36*REGBYTES(sp)                         // Store ft5
204    fsw     f6, 37*REGBYTES(sp)                         // Store ft6
205    fsw     f7, 38*REGBYTES(sp)                         // Store ft7
206    fsw     f10,41*REGBYTES(sp)                         // Store fa0
207    fsw     f11,42*REGBYTES(sp)                         // Store fa1
208    fsw     f12,43*REGBYTES(sp)                         // Store fa2
209    fsw     f13,44*REGBYTES(sp)                         // Store fa3
210    fsw     f14,45*REGBYTES(sp)                         // Store fa4
211    fsw     f15,46*REGBYTES(sp)                         // Store fa5
212    fsw     f16,47*REGBYTES(sp)                         // Store fa6
213    fsw     f17,48*REGBYTES(sp)                         // Store fa7
214    fsw     f28,59*REGBYTES(sp)                         // Store ft8
215    fsw     f29,60*REGBYTES(sp)                         // Store ft9
216    fsw     f30,61*REGBYTES(sp)                         // Store ft10
217    fsw     f31,62*REGBYTES(sp)                         // Store ft11
218    csrr    t0, fcsr
219    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
220#elif defined(__riscv_float_abi_double)
221    fsd     f0, 31*REGBYTES(sp)                         // Store ft0
222    fsd     f1, 32*REGBYTES(sp)                         // Store ft1
223    fsd     f2, 33*REGBYTES(sp)                         // Store ft2
224    fsd     f3, 34*REGBYTES(sp)                         // Store ft3
225    fsd     f4, 35*REGBYTES(sp)                         // Store ft4
226    fsd     f5, 36*REGBYTES(sp)                         // Store ft5
227    fsd     f6, 37*REGBYTES(sp)                         // Store ft6
228    fsd     f7, 38*REGBYTES(sp)                         // Store ft7
229    fsd     f10,41*REGBYTES(sp)                         // Store fa0
230    fsd     f11,42*REGBYTES(sp)                         // Store fa1
231    fsd     f12,43*REGBYTES(sp)                         // Store fa2
232    fsd     f13,44*REGBYTES(sp)                         // Store fa3
233    fsd     f14,45*REGBYTES(sp)                         // Store fa4
234    fsd     f15,46*REGBYTES(sp)                         // Store fa5
235    fsd     f16,47*REGBYTES(sp)                         // Store fa6
236    fsd     f17,48*REGBYTES(sp)                         // Store fa7
237    fsd     f28,59*REGBYTES(sp)                         // Store ft8
238    fsd     f29,60*REGBYTES(sp)                         // Store ft9
239    fsd     f30,61*REGBYTES(sp)                         // Store ft10
240    fsd     f31,62*REGBYTES(sp)                         // Store ft11
241    csrr    t0, fcsr
242    STORE   t0, 63*REGBYTES(sp)                         // Store fcsr
243#endif
244
245    /* Save the current stack pointer in the thread's control block.  */
246    /* _tx_thread_current_ptr -> tx_thread_stack_ptr =  sp;  */
247
248    /* Switch to the system stack.  */
249    /* sp =  _tx_thread_system_stack_ptr;  */
250
251    LOAD    t1, _tx_thread_current_ptr                  // Pickup current thread pointer
252    STORE   sp, 2*REGBYTES(t1)                          // Save stack pointer
253
254#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
255    /* _tx_execution_isr_enter is called with thread stack pointer */
256    call    _tx_execution_isr_enter                     // Call the ISR execution enter function
257#endif
258
259
260    LOAD    sp, _tx_thread_system_stack_ptr             // Switch to system stack
261    ret                                                 // Return to calling ISR
262
263    /* }
264    else
265    {  */
266
267_tx_thread_idle_system_save:
268
269
270#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
271    call    _tx_execution_isr_enter                     // Call the ISR execution enter function
272#endif
273
274    /* Interrupt occurred in the scheduling loop.  */
275
276    /* }
277}  */
278#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
279    addi    sp, sp, 65*REGBYTES                         // Recover stack frame - with floating point enabled
280#else
281    addi    sp, sp, 32*REGBYTES                         // Recover the reserved stack space
282#endif
283    ret                                                 // Return to calling ISR
284