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(%" B_PRId32 "(%s))\n", thread->id, thread->name); 131 132 addr_t commpageAdr = (addr_t)thread->team->commpage_address; 133 addr_t threadExitAddr; 134 ASSERT(user_memcpy(&threadExitAddr, 135 &((addr_t*)commpageAdr)[COMMPAGE_ENTRY_RISCV64_THREAD_EXIT], 136 sizeof(threadExitAddr)) >= B_OK); 137 threadExitAddr += commpageAdr; 138 139 disable_interrupts(); 140 141 iframe frame; 142 memset(&frame, 0, sizeof(frame)); 143 144 SstatusReg status(Sstatus()); 145 status.pie = (1 << modeS); // enable interrupts when enter userspace 146 status.spp = modeU; 147 SetSstatus(status.val); 148 149 frame.epc = entry; 150 frame.a0 = (addr_t)arg1; 151 frame.a1 = (addr_t)arg2; 152 frame.ra = threadExitAddr; 153 frame.sp = thread->user_stack_base + thread->user_stack_size; 154 frame.tp = thread->user_local_storage; 155 156 arch_longjmp_iframe(&frame); 157 158 // never return 159 return B_ERROR; 160 } 161 162 163 bool 164 arch_on_signal_stack(Thread *thread) 165 { 166 struct iframe* frame = thread->arch_info.userFrame; 167 if (frame == NULL) { 168 panic("arch_on_signal_stack(): No user iframe!"); 169 return false; 170 } 171 172 return frame->sp >= thread->signal_stack_base 173 && frame->sp < thread->signal_stack_base 174 + thread->signal_stack_size; 175 } 176 177 178 static uint8* 179 get_signal_stack(Thread* thread, struct iframe* frame, 180 struct sigaction* action, size_t spaceNeeded) 181 { 182 // use the alternate signal stack if we should and can 183 if ( 184 thread->signal_stack_enabled && 185 (action->sa_flags & SA_ONSTACK) != 0 && ( 186 frame->sp < thread->signal_stack_base || 187 frame->sp >= thread->signal_stack_base + thread->signal_stack_size 188 ) 189 ) { 190 addr_t stackTop = thread->signal_stack_base 191 + thread->signal_stack_size; 192 return (uint8*)ROUNDDOWN(stackTop - spaceNeeded, 16); 193 } 194 return (uint8*)ROUNDDOWN(frame->sp - spaceNeeded, 16); 195 } 196 197 198 status_t 199 arch_setup_signal_frame(Thread *thread, struct sigaction *sa, 200 struct signal_frame_data *signalFrameData) 201 { 202 // dprintf("arch_setup_signal_frame()\n"); 203 iframe* frame = thread->arch_info.userFrame; 204 205 // fill signal context 206 signalFrameData->context.uc_mcontext.x[ 0] = frame->ra; 207 signalFrameData->context.uc_mcontext.x[ 1] = frame->sp; 208 signalFrameData->context.uc_mcontext.x[ 2] = frame->gp; 209 signalFrameData->context.uc_mcontext.x[ 3] = frame->tp; 210 signalFrameData->context.uc_mcontext.x[ 4] = frame->t0; 211 signalFrameData->context.uc_mcontext.x[ 5] = frame->t1; 212 signalFrameData->context.uc_mcontext.x[ 6] = frame->t2; 213 signalFrameData->context.uc_mcontext.x[ 7] = frame->fp; 214 signalFrameData->context.uc_mcontext.x[ 8] = frame->s1; 215 signalFrameData->context.uc_mcontext.x[ 9] = frame->a0; 216 signalFrameData->context.uc_mcontext.x[10] = frame->a1; 217 signalFrameData->context.uc_mcontext.x[11] = frame->a2; 218 signalFrameData->context.uc_mcontext.x[12] = frame->a3; 219 signalFrameData->context.uc_mcontext.x[13] = frame->a4; 220 signalFrameData->context.uc_mcontext.x[14] = frame->a5; 221 signalFrameData->context.uc_mcontext.x[15] = frame->a6; 222 signalFrameData->context.uc_mcontext.x[16] = frame->a7; 223 signalFrameData->context.uc_mcontext.x[17] = frame->s2; 224 signalFrameData->context.uc_mcontext.x[18] = frame->s3; 225 signalFrameData->context.uc_mcontext.x[19] = frame->s4; 226 signalFrameData->context.uc_mcontext.x[20] = frame->s5; 227 signalFrameData->context.uc_mcontext.x[21] = frame->s6; 228 signalFrameData->context.uc_mcontext.x[22] = frame->s7; 229 signalFrameData->context.uc_mcontext.x[23] = frame->s8; 230 signalFrameData->context.uc_mcontext.x[24] = frame->s9; 231 signalFrameData->context.uc_mcontext.x[25] = frame->s10; 232 signalFrameData->context.uc_mcontext.x[26] = frame->s11; 233 signalFrameData->context.uc_mcontext.x[27] = frame->t3; 234 signalFrameData->context.uc_mcontext.x[28] = frame->t4; 235 signalFrameData->context.uc_mcontext.x[29] = frame->t5; 236 signalFrameData->context.uc_mcontext.x[30] = frame->t6; 237 signalFrameData->context.uc_mcontext.pc = frame->epc; 238 // TODO: don't assume that kernel code don't use FPU 239 save_fpu((fpu_context*)&signalFrameData->context.uc_mcontext.f[0]); 240 // end of fill signal context 241 242 signal_get_user_stack(frame->sp, &signalFrameData->context.uc_stack); 243 /* 244 dprintf(" thread->signal_stack_enabled: %d\n", 245 thread->signal_stack_enabled); 246 if (thread->signal_stack_enabled) { 247 dprintf(" signal stack: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR "\n", 248 thread->signal_stack_base, 249 thread->signal_stack_base + thread->signal_stack_size 250 ); 251 } 252 */ 253 uint8* userStack = get_signal_stack(thread, frame, sa, 254 sizeof(*signalFrameData)); 255 // dprintf(" user stack: 0x%" B_PRIxADDR "\n", (addr_t)userStack); 256 status_t res = user_memcpy(userStack, signalFrameData, 257 sizeof(*signalFrameData)); 258 if (res < B_OK) 259 return res; 260 261 addr_t commpageAdr = (addr_t)thread->team->commpage_address; 262 // dprintf(" commpageAdr: 0x%" B_PRIxADDR "\n", commpageAdr); 263 addr_t signalHandlerAddr; 264 ASSERT(user_memcpy(&signalHandlerAddr, 265 &((addr_t*)commpageAdr)[COMMPAGE_ENTRY_RISCV64_SIGNAL_HANDLER], 266 sizeof(signalHandlerAddr)) >= B_OK); 267 signalHandlerAddr += commpageAdr; 268 269 frame->ra = frame->epc; 270 frame->sp = (addr_t)userStack; 271 frame->epc = signalHandlerAddr; 272 frame->a0 = frame->sp; 273 274 // WriteTrapInfo(); 275 276 return B_OK; 277 } 278 279 280 int64 281 arch_restore_signal_frame(struct signal_frame_data* signalFrameData) 282 { 283 // dprintf("arch_restore_signal_frame()\n"); 284 iframe* frame = thread_get_current_thread()->arch_info.userFrame; 285 286 frame->ra = signalFrameData->context.uc_mcontext.x[ 0]; 287 frame->sp = signalFrameData->context.uc_mcontext.x[ 1]; 288 frame->gp = signalFrameData->context.uc_mcontext.x[ 2]; 289 frame->tp = signalFrameData->context.uc_mcontext.x[ 3]; 290 frame->t0 = signalFrameData->context.uc_mcontext.x[ 4]; 291 frame->t1 = signalFrameData->context.uc_mcontext.x[ 5]; 292 frame->t2 = signalFrameData->context.uc_mcontext.x[ 6]; 293 frame->fp = signalFrameData->context.uc_mcontext.x[ 7]; 294 frame->s1 = signalFrameData->context.uc_mcontext.x[ 8]; 295 frame->a0 = signalFrameData->context.uc_mcontext.x[ 9]; 296 frame->a1 = signalFrameData->context.uc_mcontext.x[10]; 297 frame->a2 = signalFrameData->context.uc_mcontext.x[11]; 298 frame->a3 = signalFrameData->context.uc_mcontext.x[12]; 299 frame->a4 = signalFrameData->context.uc_mcontext.x[13]; 300 frame->a5 = signalFrameData->context.uc_mcontext.x[14]; 301 frame->a6 = signalFrameData->context.uc_mcontext.x[15]; 302 frame->a7 = signalFrameData->context.uc_mcontext.x[16]; 303 frame->s2 = signalFrameData->context.uc_mcontext.x[17]; 304 frame->s3 = signalFrameData->context.uc_mcontext.x[18]; 305 frame->s4 = signalFrameData->context.uc_mcontext.x[19]; 306 frame->s5 = signalFrameData->context.uc_mcontext.x[20]; 307 frame->s6 = signalFrameData->context.uc_mcontext.x[21]; 308 frame->s7 = signalFrameData->context.uc_mcontext.x[22]; 309 frame->s8 = signalFrameData->context.uc_mcontext.x[23]; 310 frame->s9 = signalFrameData->context.uc_mcontext.x[24]; 311 frame->s10 = signalFrameData->context.uc_mcontext.x[25]; 312 frame->s11 = signalFrameData->context.uc_mcontext.x[26]; 313 frame->t3 = signalFrameData->context.uc_mcontext.x[27]; 314 frame->t4 = signalFrameData->context.uc_mcontext.x[28]; 315 frame->t5 = signalFrameData->context.uc_mcontext.x[29]; 316 frame->t6 = signalFrameData->context.uc_mcontext.x[30]; 317 frame->epc = signalFrameData->context.uc_mcontext.pc; 318 restore_fpu((fpu_context*)&signalFrameData->context.uc_mcontext.f[0]); 319 320 return frame->a0; 321 } 322 323 324 void 325 arch_check_syscall_restart(Thread *thread) 326 { 327 panic("arch_check_syscall_restart(): not yet implemented\n"); 328 } 329 330 331 /** Saves everything needed to restore the frame in the child fork in the 332 * arch_fork_arg structure to be passed to arch_restore_fork_frame(). 333 * Also makes sure to return the right value. 334 */ 335 336 void 337 arch_store_fork_frame(struct arch_fork_arg *arg) 338 { 339 /* 340 dprintf("arch_store_fork_frame()\n"); 341 dprintf(" arg: %p\n", arg); 342 dprintf(" userFrame: %p\n", 343 thread_get_current_thread()->arch_info.userFrame); 344 */ 345 memcpy(&arg->frame, thread_get_current_thread()->arch_info.userFrame, 346 sizeof(iframe)); 347 arg->frame.a0 = 0; // fork return value 348 } 349 350 351 /** Restores the frame from a forked team as specified by the provided 352 * arch_fork_arg structure. 353 * Needs to be called from within the child team, ie. instead of 354 * arch_thread_enter_uspace() as thread "starter". 355 * This function does not return to the caller, but will enter userland 356 * in the child team at the same position where the parent team left of. 357 */ 358 359 void 360 arch_restore_fork_frame(struct arch_fork_arg *arg) 361 { 362 // dprintf("arch_restore_fork_frame(%p)\n", arg); 363 disable_interrupts(); 364 if (arch_setjmp(&thread_get_current_thread()->arch_info.context) == 0) { 365 SstatusReg status(Sstatus()); 366 status.pie = (1 << modeS); // enable interrupts when enter userspace 367 status.spp = modeU; 368 SetSstatus(status.val); 369 arch_longjmp_iframe(&arg->frame); 370 } else { 371 panic("return from userspace"); 372 } 373 } 374