1 /* Copyright 2019, Adrien Destugues, pulkomandy@pulkomandy.tk 2 * Distributed under the terms of the MIT License. 3 */ 4 5 6 #include <string.h> 7 8 #include <arch_cpu.h> 9 #include <arch_debug.h> 10 #include <arch/thread.h> 11 #include <boot/stage2.h> 12 #include <commpage.h> 13 #include <kernel.h> 14 #include <thread.h> 15 #include <team.h> 16 #include <tls.h> 17 #include <vm/vm_types.h> 18 #include <vm/VMAddressSpace.h> 19 20 #include "RISCV64VMTranslationMap.h" 21 22 23 extern "C" void SVecU(); 24 25 extern "C" void RestoreUserRegs() 26 { 27 SetSscratch((addr_t)&thread_get_current_thread()->arch_info); 28 SetTp(thread_get_current_thread()->user_local_storage); 29 } 30 31 32 status_t 33 arch_thread_init(struct kernel_args *args) 34 { 35 // Initialize the static initial arch_thread state (sInitialState). 36 // Currently nothing to do, i.e. zero initialized is just fine. 37 38 return B_OK; 39 } 40 41 42 status_t 43 arch_team_init_team_struct(Team *team, bool kernel) 44 { 45 // Nothing to do. The structure is empty. 46 return B_OK; 47 } 48 49 50 status_t 51 arch_thread_init_thread_struct(Thread *thread) 52 { 53 thread->arch_info.thread = thread; 54 return B_OK; 55 } 56 57 58 static inline VMAddressSpace* 59 GetThreadAddressSpace(Thread* thread) 60 { 61 /* 62 if (thread->team == team_get_kernel_team()) 63 return VMAddressSpace::Kernel(); 64 */ 65 return thread->team->address_space; 66 } 67 68 69 void 70 arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop, 71 void (*function)(void*), const void* data) 72 { 73 // dprintf("arch_thread_init_kthread_stack(%p(%s))\n", thread, thread->name); 74 memset(&thread->arch_info.context, 0, sizeof(arch_context)); 75 thread->arch_info.context.sp = (addr_t)_stackTop; 76 thread->arch_info.context.s[0] = 0; // fp 77 thread->arch_info.context.s[1] = (addr_t)function; 78 thread->arch_info.context.s[2] = (addr_t)data; 79 thread->arch_info.context.ra = (addr_t)arch_thread_entry; 80 VMTranslationMap* map = GetThreadAddressSpace(thread)->TranslationMap(); 81 thread->arch_info.context.satp = ((RISCV64VMTranslationMap*)map)->Satp(); 82 } 83 84 85 status_t 86 arch_thread_init_tls(Thread *thread) 87 { 88 addr_t tls[TLS_FIRST_FREE_SLOT]; 89 90 thread->user_local_storage = thread->user_stack_base 91 + thread->user_stack_size; 92 93 // initialize default TLS fields 94 memset(tls, 0, sizeof(tls)); 95 tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage; 96 tls[TLS_THREAD_ID_SLOT] = thread->id; 97 tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread; 98 99 return user_memcpy((void*)thread->user_local_storage, tls, sizeof(tls)); 100 } 101 102 103 void 104 arch_thread_context_switch(Thread *from, Thread *to) 105 { 106 /* 107 dprintf("arch_thread_context_switch(%p(%s), %p(%s))\n", from, from->name, 108 to, to->name); 109 */ 110 // TODO: save/restore FPU only if needed 111 save_fpu(&from->arch_info.fpuContext); 112 if (arch_setjmp(&from->arch_info.context) == 0) { 113 arch_longjmp(&to->arch_info.context, 1); 114 } else { 115 restore_fpu(&from->arch_info.fpuContext); 116 } 117 } 118 119 120 void 121 arch_thread_dump_info(void *info) 122 { 123 } 124 125 126 status_t 127 arch_thread_enter_userspace(Thread *thread, addr_t entry, void *arg1, 128 void *arg2) 129 { 130 // dprintf("arch_thread_enter_uspace()\n"); 131 132 disable_interrupts(); 133 if (arch_setjmp(&thread->arch_info.context) == 0) { 134 SstatusReg status(Sstatus()); 135 status.pie = (1 << modeS); // enable interrupts when enter userspace 136 status.spp = modeU; 137 SetSstatus(status.val); 138 SetStvec((addr_t)SVecU); 139 SetSepc(entry); 140 RestoreUserRegs(); 141 arch_enter_userspace(arg1, arg2, 142 thread->user_stack_base + thread->user_stack_size); 143 } else { 144 panic("return from userspace"); 145 } 146 return B_ERROR; 147 } 148 149 150 bool 151 arch_on_signal_stack(Thread *thread) 152 { 153 struct iframe* frame = thread->arch_info.userFrame; 154 if (frame == NULL) { 155 panic("arch_on_signal_stack(): No user iframe!"); 156 return false; 157 } 158 159 return frame->sp >= thread->signal_stack_base 160 && frame->sp < thread->signal_stack_base 161 + thread->signal_stack_size; 162 } 163 164 165 static uint8* 166 get_signal_stack(Thread* thread, struct iframe* frame, 167 struct sigaction* action, size_t spaceNeeded) 168 { 169 // use the alternate signal stack if we should and can 170 if ( 171 thread->signal_stack_enabled && 172 (action->sa_flags & SA_ONSTACK) != 0 && ( 173 frame->sp < thread->signal_stack_base || 174 frame->sp >= thread->signal_stack_base + thread->signal_stack_size 175 ) 176 ) { 177 addr_t stackTop = thread->signal_stack_base 178 + thread->signal_stack_size; 179 return (uint8*)ROUNDDOWN(stackTop - spaceNeeded, 16); 180 } 181 return (uint8*)ROUNDDOWN(frame->sp - spaceNeeded, 16); 182 } 183 184 185 status_t 186 arch_setup_signal_frame(Thread *thread, struct sigaction *sa, 187 struct signal_frame_data *signalFrameData) 188 { 189 // dprintf("arch_setup_signal_frame()\n"); 190 iframe* frame = thread->arch_info.userFrame; 191 192 // fill signal context 193 signalFrameData->context.uc_mcontext.x[ 0] = frame->ra; 194 signalFrameData->context.uc_mcontext.x[ 1] = frame->sp; 195 signalFrameData->context.uc_mcontext.x[ 2] = frame->gp; 196 signalFrameData->context.uc_mcontext.x[ 3] = frame->tp; 197 signalFrameData->context.uc_mcontext.x[ 4] = frame->t0; 198 signalFrameData->context.uc_mcontext.x[ 5] = frame->t1; 199 signalFrameData->context.uc_mcontext.x[ 6] = frame->t2; 200 signalFrameData->context.uc_mcontext.x[ 7] = frame->fp; 201 signalFrameData->context.uc_mcontext.x[ 8] = frame->s1; 202 signalFrameData->context.uc_mcontext.x[ 9] = frame->a0; 203 signalFrameData->context.uc_mcontext.x[10] = frame->a1; 204 signalFrameData->context.uc_mcontext.x[11] = frame->a2; 205 signalFrameData->context.uc_mcontext.x[12] = frame->a3; 206 signalFrameData->context.uc_mcontext.x[13] = frame->a4; 207 signalFrameData->context.uc_mcontext.x[14] = frame->a5; 208 signalFrameData->context.uc_mcontext.x[15] = frame->a6; 209 signalFrameData->context.uc_mcontext.x[16] = frame->a7; 210 signalFrameData->context.uc_mcontext.x[17] = frame->s2; 211 signalFrameData->context.uc_mcontext.x[18] = frame->s3; 212 signalFrameData->context.uc_mcontext.x[19] = frame->s4; 213 signalFrameData->context.uc_mcontext.x[20] = frame->s5; 214 signalFrameData->context.uc_mcontext.x[21] = frame->s6; 215 signalFrameData->context.uc_mcontext.x[22] = frame->s7; 216 signalFrameData->context.uc_mcontext.x[23] = frame->s8; 217 signalFrameData->context.uc_mcontext.x[24] = frame->s9; 218 signalFrameData->context.uc_mcontext.x[25] = frame->s10; 219 signalFrameData->context.uc_mcontext.x[26] = frame->s11; 220 signalFrameData->context.uc_mcontext.x[27] = frame->t3; 221 signalFrameData->context.uc_mcontext.x[28] = frame->t4; 222 signalFrameData->context.uc_mcontext.x[29] = frame->t5; 223 signalFrameData->context.uc_mcontext.x[30] = frame->t6; 224 signalFrameData->context.uc_mcontext.pc = frame->epc; 225 // TODO: don't assume that kernel code don't use FPU 226 save_fpu((fpu_context*)&signalFrameData->context.uc_mcontext.f[0]); 227 // end of fill signal context 228 229 signal_get_user_stack(frame->sp, &signalFrameData->context.uc_stack); 230 /* 231 dprintf(" thread->signal_stack_enabled: %d\n", 232 thread->signal_stack_enabled); 233 if (thread->signal_stack_enabled) { 234 dprintf(" signal stack: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR "\n", 235 thread->signal_stack_base, 236 thread->signal_stack_base + thread->signal_stack_size 237 ); 238 } 239 */ 240 uint8* userStack = get_signal_stack(thread, frame, sa, 241 sizeof(*signalFrameData)); 242 // dprintf(" user stack: 0x%" B_PRIxADDR "\n", (addr_t)userStack); 243 status_t res = user_memcpy(userStack, signalFrameData, 244 sizeof(*signalFrameData)); 245 if (res < B_OK) 246 return res; 247 248 addr_t commpageAdr = (addr_t)thread->team->commpage_address; 249 // dprintf(" commpageAdr: 0x%" B_PRIxADDR "\n", commpageAdr); 250 addr_t signalHandlerAddr; 251 ASSERT(user_memcpy(&signalHandlerAddr, 252 &((addr_t*)commpageAdr)[COMMPAGE_ENTRY_RISCV64_SIGNAL_HANDLER], 253 sizeof(signalHandlerAddr)) >= B_OK); 254 signalHandlerAddr += commpageAdr; 255 256 frame->ra = frame->epc; 257 frame->sp = (addr_t)userStack; 258 frame->epc = signalHandlerAddr; 259 frame->a0 = frame->sp; 260 261 // WriteTrapInfo(); 262 263 return B_OK; 264 } 265 266 267 int64 268 arch_restore_signal_frame(struct signal_frame_data* signalFrameData) 269 { 270 // dprintf("arch_restore_signal_frame()\n"); 271 iframe* frame = thread_get_current_thread()->arch_info.userFrame; 272 273 frame->ra = signalFrameData->context.uc_mcontext.x[ 0]; 274 frame->sp = signalFrameData->context.uc_mcontext.x[ 1]; 275 frame->gp = signalFrameData->context.uc_mcontext.x[ 2]; 276 frame->tp = signalFrameData->context.uc_mcontext.x[ 3]; 277 frame->t0 = signalFrameData->context.uc_mcontext.x[ 4]; 278 frame->t1 = signalFrameData->context.uc_mcontext.x[ 5]; 279 frame->t2 = signalFrameData->context.uc_mcontext.x[ 6]; 280 frame->fp = signalFrameData->context.uc_mcontext.x[ 7]; 281 frame->s1 = signalFrameData->context.uc_mcontext.x[ 8]; 282 frame->a0 = signalFrameData->context.uc_mcontext.x[ 9]; 283 frame->a1 = signalFrameData->context.uc_mcontext.x[10]; 284 frame->a2 = signalFrameData->context.uc_mcontext.x[11]; 285 frame->a3 = signalFrameData->context.uc_mcontext.x[12]; 286 frame->a4 = signalFrameData->context.uc_mcontext.x[13]; 287 frame->a5 = signalFrameData->context.uc_mcontext.x[14]; 288 frame->a6 = signalFrameData->context.uc_mcontext.x[15]; 289 frame->a7 = signalFrameData->context.uc_mcontext.x[16]; 290 frame->s2 = signalFrameData->context.uc_mcontext.x[17]; 291 frame->s3 = signalFrameData->context.uc_mcontext.x[18]; 292 frame->s4 = signalFrameData->context.uc_mcontext.x[19]; 293 frame->s5 = signalFrameData->context.uc_mcontext.x[20]; 294 frame->s6 = signalFrameData->context.uc_mcontext.x[21]; 295 frame->s7 = signalFrameData->context.uc_mcontext.x[22]; 296 frame->s8 = signalFrameData->context.uc_mcontext.x[23]; 297 frame->s9 = signalFrameData->context.uc_mcontext.x[24]; 298 frame->s10 = signalFrameData->context.uc_mcontext.x[25]; 299 frame->s11 = signalFrameData->context.uc_mcontext.x[26]; 300 frame->t3 = signalFrameData->context.uc_mcontext.x[27]; 301 frame->t4 = signalFrameData->context.uc_mcontext.x[28]; 302 frame->t5 = signalFrameData->context.uc_mcontext.x[29]; 303 frame->t6 = signalFrameData->context.uc_mcontext.x[30]; 304 frame->epc = signalFrameData->context.uc_mcontext.pc; 305 restore_fpu((fpu_context*)&signalFrameData->context.uc_mcontext.f[0]); 306 307 return frame->a0; 308 } 309 310 311 void 312 arch_check_syscall_restart(Thread *thread) 313 { 314 panic("arch_check_syscall_restart(): not yet implemented\n"); 315 } 316 317 318 /** Saves everything needed to restore the frame in the child fork in the 319 * arch_fork_arg structure to be passed to arch_restore_fork_frame(). 320 * Also makes sure to return the right value. 321 */ 322 323 void 324 arch_store_fork_frame(struct arch_fork_arg *arg) 325 { 326 /* 327 dprintf("arch_store_fork_frame()\n"); 328 dprintf(" arg: %p\n", arg); 329 dprintf(" userFrame: %p\n", 330 thread_get_current_thread()->arch_info.userFrame); 331 */ 332 memcpy(&arg->frame, thread_get_current_thread()->arch_info.userFrame, 333 sizeof(iframe)); 334 arg->frame.a0 = 0; // fork return value 335 } 336 337 338 /** Restores the frame from a forked team as specified by the provided 339 * arch_fork_arg structure. 340 * Needs to be called from within the child team, ie. instead of 341 * arch_thread_enter_uspace() as thread "starter". 342 * This function does not return to the caller, but will enter userland 343 * in the child team at the same position where the parent team left of. 344 */ 345 346 void 347 arch_restore_fork_frame(struct arch_fork_arg *arg) 348 { 349 // dprintf("arch_restore_fork_frame(%p)\n", arg); 350 disable_interrupts(); 351 if (arch_setjmp(&thread_get_current_thread()->arch_info.context) == 0) { 352 SstatusReg status(Sstatus()); 353 status.pie = (1 << modeS); // enable interrupts when enter userspace 354 status.spp = modeU; 355 SetSstatus(status.val); 356 arch_longjmp_iframe(&arg->frame); 357 } else { 358 panic("return from userspace"); 359 } 360 } 361