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