1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/mm/paging/pml_types.h"
4#include "mos/platform/platform_defs.h"
5#include "mos/tasks/signal.h"
6#include "mos/x86/devices/rtc.h"
7
8#include <mos/lib/sync/spinlock.h>
9#include <mos/mm/paging/paging.h>
10#include <mos/mm/physical/pmm.h>
11#include <mos/mos_global.h>
12#include <mos/platform/platform.h>
13#include <mos/platform_syscall.h>
14#include <mos/syslog/printk.h>
15#include <mos/tasks/process.h>
16#include <mos/tasks/task_types.h>
17#include <mos/x86/cpu/cpu.h>
18#include <mos/x86/delays.h>
19#include <mos/x86/devices/port.h>
20#include <mos/x86/interrupt/apic.h>
21#include <mos/x86/mm/paging_impl.h>
22#include <mos/x86/tasks/context.h>
23#include <mos/x86/x86_interrupt.h>
24#include <mos/x86/x86_platform.h>
25#include <mos_stdio.h>
26#include <mos_stdlib.h>
27#include <mos_string.h>
28
29[[noreturn]] void platform_shutdown(void)
30{
31 platform_interrupt_disable();
32 port_outw(port: 0x604, value: 0x2000);
33 x86_cpu_halt();
34 while (1)
35 ;
36}
37
38void platform_halt_cpu(void)
39{
40 x86_cpu_halt();
41}
42
43void platform_invalidate_tlb(ptr_t vaddr)
44{
45 if (!vaddr)
46 x86_cpu_invlpg_all();
47 else
48 x86_cpu_invlpg(addr: vaddr);
49}
50
51u32 platform_current_cpu_id(void)
52{
53 return x86_cpuid(b, 1, 0) >> 24;
54}
55
56void platform_cpu_idle(void)
57{
58 __asm__ volatile("hlt");
59}
60
61u64 platform_get_timestamp()
62{
63 return rdtsc();
64}
65
66datetime_str_t *platform_get_datetime_str(void)
67{
68 static PER_CPU_DECLARE(datetime_str_t, datetime_str);
69
70 timeval_t time;
71 platform_get_time(val: &time);
72 snprintf(str: *per_cpu(datetime_str), size: sizeof(datetime_str_t), format: "%d-%02d-%02d %02d:%02d:%02d", time.year, time.month, time.day, time.hour, time.minute, time.second);
73 return per_cpu(datetime_str);
74}
75
76void platform_interrupt_enable(void)
77{
78 __asm__ volatile("sti");
79}
80
81void platform_interrupt_disable(void)
82{
83 __asm__ volatile("cli");
84}
85
86void platform_switch_mm(const mm_context_t *mm)
87{
88 x86_cpu_set_cr3(pgd_pfn(mm->pgd) * MOS_PAGE_SIZE);
89}
90
91platform_regs_t *platform_thread_regs(const thread_t *thread)
92{
93 return (platform_regs_t *) (thread->k_stack.top - sizeof(platform_regs_t));
94}
95
96void platform_dump_thread_kernel_stack(const thread_t *thread)
97{
98 if (!thread)
99 {
100 pr_warn("thread is null, cannot dump its stack");
101 return;
102 }
103
104 if (thread->state != THREAD_STATE_BLOCKED)
105 {
106 pr_emph("thread %pt is not blocked, cannot dump stack", (void *) thread);
107 return;
108 }
109
110 ptr_t *rbp_ptr = (ptr_t *) thread->k_stack.head;
111 rbp_ptr += 6; // 6 registers pushed by x86_context_switch_impl
112 x86_dump_stack_at(this_frame: *rbp_ptr, can_access_vmaps: false);
113}
114
115[[noreturn]] void platform_return_to_userspace(platform_regs_t *regs)
116{
117 x86_interrupt_return_impl(regs);
118}
119
120u64 platform_arch_syscall(u64 syscall, u64 __maybe_unused arg1, u64 __maybe_unused arg2, u64 __maybe_unused arg3, u64 __maybe_unused arg4)
121{
122 switch (syscall)
123 {
124 case X86_SYSCALL_IOPL_ENABLE:
125 {
126 pr_dinfo2(syscall, "enabling IOPL for thread %pt", (void *) current_thread);
127 current_process->platform_options.iopl = true;
128 platform_thread_regs(current_thread)->eflags |= 0x3000;
129 return 0;
130 }
131 case X86_SYSCALL_IOPL_DISABLE:
132 {
133 pr_dinfo2(syscall, "disabling IOPL for thread %pt", (void *) current_thread);
134 current_process->platform_options.iopl = false;
135 platform_thread_regs(current_thread)->eflags &= ~0x3000;
136 return 0;
137 }
138 case X86_SYSCALL_SET_FS_BASE:
139 {
140 current_thread->platform_options.fs_base = arg1;
141 x86_set_fsbase(current_thread);
142 return 0;
143 }
144 case X86_SYSCALL_SET_GS_BASE:
145 {
146 current_thread->platform_options.gs_base = arg1;
147 // x86_update_current_gsbase();
148 MOS_UNIMPLEMENTED("set_gs_base");
149 return 0;
150 }
151 default:
152 {
153 pr_warn("unknown arch-specific syscall %llu", syscall);
154 return -1;
155 }
156 }
157}
158
159void platform_ipi_send(u8 target, ipi_type_t type)
160{
161 if (target == TARGET_CPU_ALL)
162 lapic_interrupt(IPI_BASE + type, dest: 0xff, delivery_mode: APIC_DELIVER_MODE_NORMAL, dest_mode: LAPIC_DEST_MODE_PHYSICAL, shorthand: LAPIC_SHORTHAND_ALL_EXCLUDING_SELF);
163 else
164 lapic_interrupt(IPI_BASE + type, dest: target, delivery_mode: APIC_DELIVER_MODE_NORMAL, dest_mode: LAPIC_DEST_MODE_PHYSICAL, shorthand: LAPIC_SHORTHAND_NONE);
165}
166
167void platform_jump_to_signal_handler(const platform_regs_t *regs, const sigreturn_data_t *sigreturn_data, const sigaction_t *sa)
168{
169 current_thread->u_stack.head = regs->sp - 128;
170
171 // backup previous frame
172 stack_push_val(&current_thread->u_stack, *regs);
173 stack_push_val(&current_thread->u_stack, *sigreturn_data);
174
175 // Set up the new context
176 platform_regs_t ret_regs = *regs;
177 ret_regs.ip = (ptr_t) sa->handler;
178 stack_push_val(&current_thread->u_stack, (ptr_t) sa->sa_restorer); // the return address
179
180 ret_regs.di = sigreturn_data->signal; // arg1
181 ret_regs.sp = current_thread->u_stack.head;
182 x86_interrupt_return_impl(regs: &ret_regs);
183}
184
185void platform_restore_from_signal_handler(void *sp)
186{
187 current_thread->u_stack.head = (ptr_t) sp;
188 sigreturn_data_t data;
189 platform_regs_t regs;
190 stack_pop_val(&current_thread->u_stack, data);
191 stack_pop_val(&current_thread->u_stack, regs);
192
193 signal_on_returned(supplimentary_data: &data);
194 x86_interrupt_return_impl(regs: &regs);
195}
196
197void platform_get_time(timeval_t *time)
198{
199 rtc_read_time(time);
200}
201
202void platform_dump_regs(platform_regs_t *frame)
203{
204 pr_emph("General Purpose Registers:\n"
205 " RAX: " PTR_FMT " RBX: " PTR_FMT " RCX: " PTR_FMT " RDX: " PTR_FMT "\n"
206 " RSI: " PTR_FMT " RDI: " PTR_FMT " RBP: " PTR_FMT " RSP: " PTR_FMT "\n"
207 " R8: " PTR_FMT " R9: " PTR_FMT " R10: " PTR_FMT " R11: " PTR_FMT "\n"
208 " R12: " PTR_FMT " R13: " PTR_FMT " R14: " PTR_FMT " R15: " PTR_FMT "\n"
209 " IP: " PTR_FMT "\n"
210 "Context:\n"
211 " EFLAGS: " PTR_FMT "\n"
212 " Instruction: 0x%lx:" PTR_FMT "\n"
213 " Stack: 0x%lx:" PTR_FMT,
214 frame->ax, frame->bx, frame->cx, frame->dx, //
215 frame->si, frame->di, frame->bp, frame->sp, //
216 frame->r8, frame->r9, frame->r10, frame->r11, //
217 frame->r12, frame->r13, frame->r14, frame->r15, //
218 frame->ip, //
219 frame->eflags, //
220 frame->cs, frame->ip, //
221 frame->ss, frame->sp //
222 );
223}
224
225void platform_syscall_setup_restart_context(platform_regs_t *regs, reg_t syscall_nr)
226{
227 regs->ax = syscall_nr;
228 regs->ip -= 2; // replay the 'syscall' or 'int 0x88' instruction
229}
230
231void platform_syscall_store_retval(platform_regs_t *regs, reg_t result)
232{
233 regs->ax = result;
234}
235