xref: /haiku/src/system/kernel/arch/riscv64/arch_thread.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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