MOS Source Code
Loading...
Searching...
No Matches
riscv64_platform_api.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/assert.hpp"
8
9#include <mos/platform_syscall.h>
10#include <mos_stdlib.hpp>
11
12// Platform Context Switching APIs
13typedef void (*switch_func_t)();
14extern "C" void riscv64_do_context_switch(ptr_t *old_stack, ptr_t new_stack, switch_func_t switcher, bool *lock);
16
23
25{
27 const thread_entry_t entry = (thread_entry_t) regs->sepc;
28 void *const arg = (void *) regs->a0;
29 entry(arg);
31}
32
34{
35 (*(volatile u32 *) pa_va(0x100000)) = 0x5555;
36 while (1)
38}
39
41{
42 return 0;
43}
44
46{
47 __asm__ volatile("wfi");
48}
49
51{
52 pr_info("General Purpose Registers:");
53 pr_info2(" ra/x1: " PTR_FMT " sp/x2: " PTR_FMT " gp/x3: " PTR_FMT " tp/x4: " PTR_FMT, regs->ra, regs->sp, regs->gp, regs->tp);
54 pr_info2(" t0/x5: " PTR_FMT " t1/x6: " PTR_FMT " t2/x7: " PTR_FMT " fp/x8: " PTR_FMT, regs->t0, regs->t1, regs->t2, regs->fp);
55 pr_info2(" s1/x9: " PTR_FMT " a0/x10: " PTR_FMT " a1/x11: " PTR_FMT " a2/x12: " PTR_FMT, regs->s1, regs->a0, regs->a1, regs->a2);
56 pr_info2(" a3/x13: " PTR_FMT " a4/x14: " PTR_FMT " a5/x15: " PTR_FMT " a6/x16: " PTR_FMT, regs->a3, regs->a4, regs->a5, regs->a6);
57 pr_info2(" a7/x17: " PTR_FMT " s2/x18: " PTR_FMT " s3/x19: " PTR_FMT " s4/x20: " PTR_FMT, regs->a7, regs->s2, regs->s3, regs->s4);
58 pr_info2(" s5/x21: " PTR_FMT " s6/x22: " PTR_FMT " s7/x23: " PTR_FMT " s8/x24: " PTR_FMT, regs->s5, regs->s6, regs->s7, regs->s8);
59 pr_info2(" s9/x25: " PTR_FMT " s10/x26: " PTR_FMT " s11/x27: " PTR_FMT " t3/x28: " PTR_FMT, regs->s9, regs->s10, regs->s11, regs->t3);
60 pr_info2(" t4/x29: " PTR_FMT " t5/x30: " PTR_FMT " t6/x31: " PTR_FMT, regs->t4, regs->t5, regs->t6);
61}
62
64{
65 return (platform_regs_t *) (thread->k_stack.top - sizeof(platform_regs_t));
66}
67
68static void thread_setup_common(Thread *thread)
69{
70 thread->k_stack.head = thread->k_stack.top - sizeof(platform_regs_t);
71}
72
73// Platform Thread / Process APIs
75{
76 thread_setup_common(thread);
78 regs->sepc = entry;
79 regs->a0 = argc;
80 regs->a1 = argv;
81 regs->a2 = envp;
82 regs->sp = sp;
83}
84
86{
87 thread_setup_common(thread);
89 regs->a0 = (ptr_t) arg;
90 regs->sepc = (ptr_t) entry;
91
92 if (thread->mode == THREAD_MODE_KERNEL)
93 return;
94
95 // for user threads, set up the global pointer
96 if (thread->owner == current_process)
98
99 MOS_ASSERT(thread->owner->mm == current_mm);
100 MOS_ASSERT(thread != thread->owner->main_thread);
101
102 regs->sp = thread->u_stack.head; // update the stack pointer
103}
104
106{
108 platform_regs_t *from_regs = platform_thread_regs(from);
109 *to_regs = *from_regs;
110 to_regs->a0 = 0; // return 0 for the child
111 if (to->mode == THREAD_MODE_USER)
112 {
113 to->u_stack.head = to_regs->sp;
114 }
115 to->k_stack.head -= sizeof(platform_regs_t);
116}
117
119{
120 MOS_UNUSED(thread);
121 // nothing to cleanup
122}
123
125{
126 const reg_t sstatus = read_csr(sstatus);
127 write_csr(sstatus, sstatus & ~SSTATUS_SIE);
128}
129
131{
132 const reg_t sstatus = read_csr(sstatus);
133 write_csr(sstatus, sstatus | SSTATUS_SIE);
134}
135
136void platform_switch_mm(const MMContext *new_mm)
137{
138 write_csr(satp, make_satp(SATP_MODE_SV48, 0, pgd_pfn(new_mm->pgd)));
139 __asm__ volatile("sfence.vma zero, zero");
140}
141
142#define FLEN 64 // D extension
143
144static void do_save_fp_context(Thread *thread)
145{
146 if (thread->mode == THREAD_MODE_KERNEL)
147 return;
148
149#define f_op(reg, val) __asm__ volatile("fld " #reg ", %0" : : "m"(thread->platform_options.f[val]))
150 f_op(f0, 0);
151 f_op(f1, 1);
152 f_op(f2, 2);
153 f_op(f3, 3);
154 f_op(f4, 4);
155 f_op(f5, 5);
156 f_op(f6, 6);
157 f_op(f7, 7);
158 f_op(f8, 8);
159 f_op(f9, 9);
160 f_op(f10, 10);
161 f_op(f11, 11);
162 f_op(f12, 12);
163 f_op(f13, 13);
164 f_op(f14, 14);
165 f_op(f15, 15);
166 f_op(f16, 16);
167 f_op(f17, 17);
168 f_op(f18, 18);
169 f_op(f19, 19);
170 f_op(f20, 20);
171 f_op(f21, 21);
172 f_op(f22, 22);
173 f_op(f23, 23);
174 f_op(f24, 24);
175 f_op(f25, 25);
176 f_op(f26, 26);
177 f_op(f27, 27);
178 f_op(f28, 28);
179 f_op(f29, 29);
180 f_op(f30, 30);
181 f_op(f31, 31);
182 thread->platform_options.fcsr = read_csr(fcsr);
183#undef f_op
184}
185
187{
188 if (thread->mode == THREAD_MODE_KERNEL)
189 return;
190#define f_op(reg, val) __asm__ volatile("fsd " #reg ", %0" : : "m"(thread->platform_options.f[val]))
191 write_csr(fcsr, thread->platform_options.fcsr);
192 f_op(f0, 0);
193 f_op(f1, 1);
194 f_op(f2, 2);
195 f_op(f3, 3);
196 f_op(f4, 4);
197 f_op(f5, 5);
198 f_op(f6, 6);
199 f_op(f7, 7);
200 f_op(f8, 8);
201 f_op(f9, 9);
202 f_op(f10, 10);
203 f_op(f11, 11);
204 f_op(f12, 12);
205 f_op(f13, 13);
206 f_op(f14, 14);
207 f_op(f15, 15);
208 f_op(f16, 16);
209 f_op(f17, 17);
210 f_op(f18, 18);
211 f_op(f19, 19);
212 f_op(f20, 20);
213 f_op(f21, 21);
214 f_op(f22, 22);
215 f_op(f23, 23);
216 f_op(f24, 24);
217 f_op(f25, 25);
218 f_op(f26, 26);
219 f_op(f27, 27);
220 f_op(f28, 28);
221 f_op(f29, 29);
222 f_op(f30, 30);
223 f_op(f31, 31);
224#undef f_op
225}
226
228{
229 const switch_func_t switch_func = statement_expr(switch_func_t, {
230 switch (switch_flags)
231 {
234 default: retval = riscv64_normal_switch_impl; break;
235 }
236 });
237
238 if (current)
240 do_restore_fp_context(new_thread);
241
242 __atomic_store_n(&current_cpu->thread, new_thread, __ATOMIC_SEQ_CST);
243
244 ptr_t trash = 0;
245 ptr_t *const stack_ptr = current ? &current->k_stack.head : &trash;
246 bool trash_lock = false;
247 bool *const lock = current ? &current->state_lock.flag : &trash_lock;
248 riscv64_do_context_switch(stack_ptr, new_thread->k_stack.head, switch_func, lock);
249}
250
252{
253 reg_t sstatus = read_csr(sstatus);
254 sstatus &= ~SSTATUS_SPP;
255 sstatus |= SSTATUS_SPIE;
256 sstatus |= SSTATUS_SUM;
257 write_csr(sstatus, sstatus);
258 write_csr(sscratch, current_thread->k_stack.top);
260 write_csr(sepc, regs->sepc);
261 riscv64_trap_exit(regs);
262}
263
264u64 platform_arch_syscall(u64 syscall, u64 arg1, u64 arg2, u64 arg3, u64 arg4)
265{
266 MOS_UNUSED(arg2);
267 MOS_UNUSED(arg3);
268 MOS_UNUSED(arg4);
269
270 switch (syscall)
271 {
273 {
275 current_cpu->interrupt_regs->tp = arg1;
276 return 0;
277 }
278 }
279 return 0;
280}
281
282void platform_ipi_send(u8 target_cpu, ipi_type_t type)
283{
284 MOS_UNUSED(target_cpu);
285 MOS_UNUSED(type);
286 // pr_emerg("platform_ipi_send() not implemented");
287}
288
290{
291 ptr_t *caller_fp = (ptr_t *) regs->fp;
292 pr_info("Stack dump:");
293 for (int i = 0; i < 16; i++)
294 {
295 pr_info(" %p: %ps", (void *) caller_fp, (void *) *(caller_fp - 1));
296 caller_fp = (ptr_t *) *(caller_fp - 2);
297 if (!caller_fp || !is_aligned(caller_fp, 16) || (ptr_t) caller_fp < MOS_KERNEL_START_VADDR)
298 break;
299 }
300}
301
303{
304 regs->a7 = syscall_nr;
305 regs->sepc -= 4; // replay the 'ecall' instruction
306}
307
309{
310 regs->a0 = result;
311}
312
313void platform_jump_to_signal_handler(const platform_regs_t *regs, const sigreturn_data_t *sigreturn_data, const sigaction_t *sa)
314{
315 current_thread->u_stack.head = regs->sp - 128;
316
317 // backup previous frame
318 stack_push_val(&current_thread->u_stack, *regs);
319 stack_push_val(&current_thread->u_stack, *sigreturn_data);
320
321 // Set up the new context
322 platform_regs_t ret_regs = *regs;
323 ret_regs.sepc = (ptr_t) sa->handler;
324 ret_regs.ra = (ptr_t) sa->sa_restorer; // the return address
325 ret_regs.a0 = sigreturn_data->signal; // arg1
326 ret_regs.sp = current_thread->u_stack.head;
328}
329
331{
332 current_thread->u_stack.head = (ptr_t) sp;
333 sigreturn_data_t data;
334 platform_regs_t regs;
335 stack_pop_val(&current_thread->u_stack, data);
336 stack_pop_val(&current_thread->u_stack, regs);
337
338 signal_on_returned(&data);
340}
#define MOS_ASSERT(cond)
Definition assert.hpp:14
#define MOS_UNREACHABLE()
Definition assert.hpp:11
#define stack_pop_val(stack, val)
Definition stack.hpp:35
#define stack_push_val(stack, val)
Definition stack.hpp:26
void signal_on_returned(sigreturn_data_t *supplimentary_data)
Return from a signal handler.
Definition signal.cpp:290
void signal_exit_to_user_prepare(platform_regs_t *regs)
Prepare to exit to userspace.
Definition signal.cpp:240
MOSAPI void(1, 2) fatal_abort(const char *fmt
#define pa_va(pa)
Definition mm.hpp:81
@ THREAD_MODE_KERNEL
@ THREAD_MODE_USER
ipi_type_t
The type of IPI to send.
Definition ipi.hpp:13
const char ** argv
Definition kmain.cpp:34
size_t argc
Definition kmain.cpp:33
#define statement_expr(type,...)
Definition mos_global.h:102
#define is_aligned(ptr, alignment)
Definition mos_global.h:56
#define MOS_UNUSED(x)
Definition mos_global.h:65
#define current
#define current_thread
Definition platform.hpp:32
#define current_mm
Definition platform.hpp:34
#define current_cpu
Definition platform.hpp:31
#define current_process
Definition platform.hpp:33
switch_flags_t
Definition platform.hpp:76
@ SWITCH_TO_NEW_KERNEL_THREAD
Definition platform.hpp:79
@ SWITCH_TO_NEW_USER_THREAD
Definition platform.hpp:78
#define pgd_pfn(pgd)
Definition pml_types.hpp:93
#define pr_info2(fmt,...)
Definition printk.hpp:36
#define pr_info(fmt,...)
Definition printk.hpp:35
#define MOS_KERNEL_START_VADDR
#define SSTATUS_SIE
Definition cpu.hpp:32
#define SSTATUS_SPIE
Definition cpu.hpp:33
#define SSTATUS_SPP
Definition cpu.hpp:34
const char __riscv64_usermode_trap_entry[]
void riscv64_trap_exit(platform_regs_t *regs)
#define read_csr(reg)
Definition cpu.hpp:23
#define write_csr(reg, val)
Definition cpu.hpp:24
#define make_satp(mode, asid, ppn)
Definition cpu.hpp:26
#define SATP_MODE_SV48
Definition cpu.hpp:29
#define SSTATUS_SUM
Definition cpu.hpp:35
@ RISCV64_SYSCALL_SET_TP
void platform_context_cleanup(Thread *thread)
void do_restore_fp_context(Thread *thread)
void platform_dump_regs(platform_regs_t *regs)
void platform_switch_to_thread(Thread *current, Thread *new_thread, switch_flags_t switch_flags)
u32 platform_current_cpu_id()
static void do_save_fp_context(Thread *thread)
u64 platform_arch_syscall(u64 syscall, u64 arg1, u64 arg2, u64 arg3, u64 arg4)
void platform_return_to_userspace(platform_regs_t *regs)
void(* switch_func_t)()
void platform_syscall_setup_restart_context(platform_regs_t *regs, reg_t syscall_nr)
void platform_restore_from_signal_handler(void *sp)
void platform_interrupt_enable()
static void riscv64_start_kernel_thread()
void platform_cpu_idle()
static void thread_setup_common(Thread *thread)
void platform_jump_to_signal_handler(const platform_regs_t *regs, const sigreturn_data_t *sigreturn_data, const sigaction_t *sa)
void platform_switch_mm(const MMContext *new_mm)
static void riscv64_start_user_thread()
void platform_context_setup_main_thread(Thread *thread, ptr_t entry, ptr_t sp, int argc, ptr_t argv, ptr_t envp)
void platform_shutdown()
#define f_op(reg, val)
void platform_ipi_send(u8 target_cpu, ipi_type_t type)
void platform_syscall_store_retval(platform_regs_t *regs, reg_t result)
void platform_context_setup_child_thread(Thread *thread, thread_entry_t entry, void *arg)
void platform_context_clone(const Thread *from, Thread *to)
void riscv64_do_context_switch(ptr_t *old_stack, ptr_t new_stack, switch_func_t switcher, bool *lock)
void platform_interrupt_disable()
void platform_dump_stack(platform_regs_t *regs)
void riscv64_normal_switch_impl()
platform_regs_t * platform_thread_regs(const Thread *thread)
void(* thread_entry_t)(void *arg)
Definition signal_types.h:8
pgd_t pgd
Definition platform.hpp:87
Thread * main_thread
MMContext * mm
platform_thread_options_t platform_options
platform-specific thread options
thread_mode mode
user-mode thread or kernel-mode
Process * owner
downwards_stack_t u_stack
user-mode stack
downwards_stack_t k_stack
kernel-mode stack
reg_t sepc
Definition cpu.hpp:18
reg_t s10
Definition cpu.hpp:14
reg_t s11
Definition cpu.hpp:14
__sighandler handler
void(* sa_restorer)(void)
signal_t signal
Definition signal.hpp:66
uintn reg_t
Definition types.h:47
unsigned int u32
Definition types.h:17
#define PTR_FMT
Definition types.h:29
unsigned long ptr_t
Definition types.h:21
unsigned long long u64
Definition types.h:19
unsigned char u8
Definition types.h:15