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