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