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