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