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"
5#include "mos/platform/platform_defs.hpp"
10
11#include <mos/platform_syscall.h>
12#include <mos/shared_ptr.hpp>
13#include <mos_stdlib.hpp>
14
15// Platform Context Switching APIs
16typedef void (*switch_func_t)();
17extern "C" void riscv64_do_context_switch(ptr_t *old_stack, ptr_t new_stack, switch_func_t switcher, bool *lock);
19
21{
23 reg_t sstatus = read_csr(sstatus);
24 sstatus &= ~SSTATUS_SPP;
25 sstatus |= SSTATUS_SPIE;
26 sstatus |= SSTATUS_SUM;
27
28 write_csr(sstatus, sstatus);
29 write_csr(sscratch, current_thread->k_stack.top);
31 write_csr(sepc, regs->sepc);
33}
34
36{
38 const thread_entry_t entry = (thread_entry_t) regs->sepc;
39 void *const arg = (void *) regs->a0;
40 entry(arg);
42}
43
45{
46 (*(volatile u32 *) pa_va(0x100000)) = 0x5555;
47 while (1)
49}
50
52{
53 return 0;
54}
55
57{
58 __asm__ volatile("wfi");
59}
60
62{
63 pr_info("General Purpose Registers:");
64 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);
65 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);
66 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);
67 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);
68 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);
69 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);
70 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);
71 pr_info2(" t4/x29: " PTR_FMT " t5/x30: " PTR_FMT " t6/x31: " PTR_FMT, regs->t4, regs->t5, regs->t6);
72}
73
75{
76 return (platform_regs_t *) (thread->k_stack.top - sizeof(platform_regs_t));
77}
78
79static void thread_setup_common(Thread *thread)
80{
81 thread->k_stack.head = thread->k_stack.top - sizeof(platform_regs_t);
82}
83
84// Platform Thread / Process APIs
85void platform_context_setup_main_thread(Thread *thread, ptr_t entry, ptr_t sp, int argc, ptr_t argv, ptr_t envp)
86{
87 thread_setup_common(thread);
89 *regs = platform_regs_t();
90 regs->sepc = entry;
91 regs->a0 = argc;
92 regs->a1 = argv;
93 regs->a2 = envp;
94 regs->sp = sp;
95}
96
98{
99 thread_setup_common(thread);
101 regs->a0 = (ptr_t) arg;
102 regs->sepc = (ptr_t) entry;
103
104 if (thread->mode == THREAD_MODE_KERNEL)
105 return;
106
107 // for user threads, set up the global pointer
108 if (thread->owner == current_process)
110
111 MOS_ASSERT(thread->owner->mm == current_mm);
112 MOS_ASSERT(thread != thread->owner->main_thread);
113
114 regs->sp = thread->u_stack.head; // update the stack pointer
115}
116
118{
120 platform_regs_t *from_regs = platform_thread_regs(from);
121 *to_regs = *from_regs;
122 to_regs->a0 = 0; // return 0 for the child
123 if (to->mode == THREAD_MODE_USER)
124 {
125 to->u_stack.head = to_regs->sp;
126 }
127 to->k_stack.head -= sizeof(platform_regs_t);
128}
129
131{
132 MOS_UNUSED(thread);
133 // nothing to cleanup
134}
135
137{
138 const reg_t sstatus = read_csr(sstatus);
139 write_csr(sstatus, sstatus & ~SSTATUS_SIE);
140}
141
143{
144 const reg_t sstatus = read_csr(sstatus);
145 write_csr(sstatus, sstatus | SSTATUS_SIE);
146}
147
148void platform_switch_mm(const MMContext *new_mm)
149{
150 write_csr(satp, make_satp(SATP_MODE_SV48, 0, pgd_pfn(new_mm->pgd)));
151 __asm__ volatile("sfence.vma zero, zero");
152}
153
154#define FLEN 64 // D extension
155
156static void do_save_fp_context(Thread *thread)
157{
158 if (thread->mode == THREAD_MODE_KERNEL)
159 return;
160
161#define f_op(reg, val) __asm__ volatile("fld " #reg ", %0" : : "m"(thread->platform_options.f[val]))
162 f_op(f0, 0);
163 f_op(f1, 1);
164 f_op(f2, 2);
165 f_op(f3, 3);
166 f_op(f4, 4);
167 f_op(f5, 5);
168 f_op(f6, 6);
169 f_op(f7, 7);
170 f_op(f8, 8);
171 f_op(f9, 9);
172 f_op(f10, 10);
173 f_op(f11, 11);
174 f_op(f12, 12);
175 f_op(f13, 13);
176 f_op(f14, 14);
177 f_op(f15, 15);
178 f_op(f16, 16);
179 f_op(f17, 17);
180 f_op(f18, 18);
181 f_op(f19, 19);
182 f_op(f20, 20);
183 f_op(f21, 21);
184 f_op(f22, 22);
185 f_op(f23, 23);
186 f_op(f24, 24);
187 f_op(f25, 25);
188 f_op(f26, 26);
189 f_op(f27, 27);
190 f_op(f28, 28);
191 f_op(f29, 29);
192 f_op(f30, 30);
193 f_op(f31, 31);
194 thread->platform_options.fcsr = read_csr(fcsr);
195#undef f_op
196}
197
199{
200 if (thread->mode == THREAD_MODE_KERNEL)
201 return;
202#define f_op(reg, val) __asm__ volatile("fsd " #reg ", %0" : : "m"(thread->platform_options.f[val]))
203 write_csr(fcsr, thread->platform_options.fcsr);
204 f_op(f0, 0);
205 f_op(f1, 1);
206 f_op(f2, 2);
207 f_op(f3, 3);
208 f_op(f4, 4);
209 f_op(f5, 5);
210 f_op(f6, 6);
211 f_op(f7, 7);
212 f_op(f8, 8);
213 f_op(f9, 9);
214 f_op(f10, 10);
215 f_op(f11, 11);
216 f_op(f12, 12);
217 f_op(f13, 13);
218 f_op(f14, 14);
219 f_op(f15, 15);
220 f_op(f16, 16);
221 f_op(f17, 17);
222 f_op(f18, 18);
223 f_op(f19, 19);
224 f_op(f20, 20);
225 f_op(f21, 21);
226 f_op(f22, 22);
227 f_op(f23, 23);
228 f_op(f24, 24);
229 f_op(f25, 25);
230 f_op(f26, 26);
231 f_op(f27, 27);
232 f_op(f28, 28);
233 f_op(f29, 29);
234 f_op(f30, 30);
235 f_op(f31, 31);
236#undef f_op
237}
238
239void platform_switch_to_thread(Thread *current, Thread *new_thread, ContextSwitchBehaviorFlags switch_flags)
240{
241 const switch_func_t switch_func = statement_expr(switch_func_t, {
242 switch (switch_flags)
243 {
246 default: retval = riscv64_normal_switch_impl; break;
247 }
248 });
249
250 if (current)
252 do_restore_fp_context(new_thread);
253
254 __atomic_store_n(&current_cpu->thread, new_thread, __ATOMIC_SEQ_CST);
255
256 ptr_t trash = 0;
257 ptr_t *const stack_ptr = current ? &current->k_stack.head : &trash;
258 bool trash_lock = false;
259 bool *const lock = current ? &current->state_lock.flag : &trash_lock;
260 riscv64_do_context_switch(stack_ptr, new_thread->k_stack.head, switch_func, lock);
261}
262
264{
265 reg_t sstatus = read_csr(sstatus);
266 sstatus &= ~SSTATUS_SPP;
267 sstatus |= SSTATUS_SPIE;
268 sstatus |= SSTATUS_SUM;
269 write_csr(sstatus, sstatus);
270 write_csr(sscratch, current_thread->k_stack.top);
272 write_csr(sepc, regs->sepc);
273 riscv64_trap_exit(regs);
274}
275
276u64 platform_arch_syscall(u64 syscall, u64 arg1, u64 arg2, u64 arg3, u64 arg4)
277{
278 MOS_UNUSED(arg2);
279 MOS_UNUSED(arg3);
280 MOS_UNUSED(arg4);
281
282 switch (syscall)
283 {
285 {
287 current_cpu->interrupt_regs->tp = arg1;
288 return 0;
289 }
290 }
291 return 0;
292}
293
294void platform_ipi_send(u8 target_cpu, ipi_type_t type)
295{
296 MOS_UNUSED(target_cpu);
297 MOS_UNUSED(type);
298 // pr_emerg("platform_ipi_send() not implemented");
299}
300
302{
303 ptr_t *caller_fp = (ptr_t *) regs->fp;
304 pr_info("Stack dump:");
305 for (int i = 0; i < 16; i++)
306 {
307 pr_info(" %p: %ps", (void *) caller_fp, (void *) *(caller_fp - 1));
308 caller_fp = (ptr_t *) *(caller_fp - 2);
309 if (!caller_fp || !is_aligned(caller_fp, 16) || (ptr_t) caller_fp < MOS_KERNEL_START_VADDR)
310 break;
311 }
312}
313
315{
316 regs->a7 = syscall_nr;
317 regs->sepc -= 4; // replay the 'ecall' instruction
318}
319
321{
322 regs->a0 = result;
323}
324
326{
327 current_thread->u_stack.head = regs->sp - 128;
328
329 // backup previous frame
330 stack_push_val(&current_thread->u_stack, *regs);
331 stack_push_val(&current_thread->u_stack, *sigreturn_data);
332
333 // Set up the new context
334 auto ret_regs = mos::make_shared<platform_regs_t>(regs);
335 ret_regs->sepc = (ptr_t) sa->handler;
336 ret_regs->ra = (ptr_t) sa->sa_restorer; // the return address
337 ret_regs->a0 = sigreturn_data->signal; // arg1
338 ret_regs->sp = current_thread->u_stack.head;
339 return ret_regs;
340}
341
343{
344 current_thread->u_stack.head = (ptr_t) sp;
345 sigreturn_data_t data;
346 platform_regs_t regs;
347 stack_pop_val(&current_thread->u_stack, data);
348 stack_pop_val(&current_thread->u_stack, regs);
349
350 signal_on_returned(&data);
352}
353
355{
356 return 0;
357}
358
360{
361 tv->day = 0;
362 tv->hour = 0;
363 tv->minute = 0;
364 tv->second = 0;
365 tv->year = 0;
366 tv->month = 0;
367}
368
370{
371 const auto val = (volatile u64 *) pa_va(0x101000);
372 constexpr auto RTC_TIME = 0x00;
373 *timestamp = *(val + RTC_TIME);
374}
375
377{
378 mWarn << "Stack dump not implemented";
379}
#define MOS_ASSERT(cond)
Definition assert.hpp:19
#define MOS_UNREACHABLE()
Definition assert.hpp:10
uint8_t argc
Definition avr_io.c:15
#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:299
MOSAPI void(1, 2) fatal_abort(const char *fmt
#define pa_va(pa)
Definition mm.hpp:87
@ THREAD_MODE_KERNEL
@ THREAD_MODE_USER
ipi_type_t
The type of IPI to send.
Definition ipi.hpp:13
#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
shared_ptr< T > make_shared(Args &&...args)
@ SWITCH_TO_NEW_KERNEL_THREAD
Definition platform.hpp:56
@ SWITCH_TO_NEW_USER_THREAD
Definition platform.hpp:55
#define current_thread
Definition platform.hpp:33
#define current_mm
Definition platform.hpp:35
#define current_cpu
Definition platform.hpp:32
#define current_process
Definition platform.hpp:34
#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:21
#define SSTATUS_SPIE
Definition cpu.hpp:22
#define SSTATUS_SPP
Definition cpu.hpp:23
const char __riscv64_usermode_trap_entry[]
void riscv64_trap_exit(platform_regs_t *regs)
#define read_csr(reg)
Definition cpu.hpp:12
#define write_csr(reg, val)
Definition cpu.hpp:13
#define make_satp(mode, asid, ppn)
Definition cpu.hpp:15
#define SATP_MODE_SV48
Definition cpu.hpp:18
#define SSTATUS_SUM
Definition cpu.hpp:24
@ RISCV64_SYSCALL_SET_TP
platform_regs_t * platform_thread_regs(Thread *thread)
void platform_context_cleanup(Thread *thread)
void platform_get_time(timeval_t *tv)
void do_restore_fp_context(Thread *thread)
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)()
u64 platform_get_timestamp()
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_switch_mm(const MMContext *new_mm)
void platform_dump_regs(const platform_regs_t *regs)
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_context_clone(Thread *from, Thread *to)
ptr< platform_regs_t > platform_setup_signal_handler_regs(const platform_regs_t *regs, const sigreturn_data_t *sigreturn_data, const sigaction_t *sa)
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_switch_to_thread(Thread *current, Thread *new_thread, ContextSwitchBehaviorFlags switch_flags)
void platform_dump_stack(const platform_regs_t *regs)
void platform_get_unix_timestamp(u64 *timestamp)
void riscv64_do_context_switch(ptr_t *old_stack, ptr_t new_stack, switch_func_t switcher, bool *lock)
void platform_interrupt_disable()
void riscv64_normal_switch_impl()
void platform_dump_current_stack()
mos::shared_ptr< T > ptr
void(* thread_entry_t)(void *arg)
Definition signal_types.h:8
pgd_t pgd
Definition platform.hpp:64
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
__sighandler handler
void(* sa_restorer)(void)
signal_t signal
Definition signal.hpp:68
constexpr auto mWarn
Definition syslog.hpp:154
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