xref: /haiku/src/system/kernel/arch/riscv64/arch_thread.cpp (revision 3386b8b7858f5659c205b8f088eb568692699591)
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 
22 extern "C" void SVecU();
23 
24 
25 status_t
26 arch_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 
35 status_t
36 arch_team_init_team_struct(Team *team, bool kernel)
37 {
38 	// Nothing to do. The structure is empty.
39 	return B_OK;
40 }
41 
42 
43 status_t
44 arch_thread_init_thread_struct(Thread *thread)
45 {
46 	return B_OK;
47 }
48 
49 
50 void
51 arch_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 
65 status_t
66 arch_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 
74 void
75 arch_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 
100 void
101 arch_thread_dump_info(void *info)
102 {
103 }
104 
105 
106 status_t
107 arch_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 
146 bool
147 arch_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 
161 static uint8*
162 get_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 
181 status_t
182 arch_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 
265 int64
266 arch_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 
317 void
318 arch_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 
340 void
341 arch_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