1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/x86/x86_platform.hpp"
4
5#include "mos/device/console.hpp"
6#include "mos/device/serial.hpp"
7#include "mos/device/serial_console.hpp"
8#include "mos/interrupt/interrupt.hpp"
9#include "mos/mm/mm.hpp"
10#include "mos/mm/paging/paging.hpp"
11#include "mos/syslog/printk.hpp"
12#include "mos/tasks/schedule.hpp"
13#include "mos/x86/acpi/acpi.hpp"
14#include "mos/x86/acpi/acpi_types.hpp"
15#include "mos/x86/acpi/madt.hpp"
16#include "mos/x86/cpu/ap_entry.hpp"
17#include "mos/x86/cpu/cpu.hpp"
18#include "mos/x86/descriptors/descriptors.hpp"
19#include "mos/x86/devices/port.hpp"
20#include "mos/x86/devices/rtc.hpp"
21#include "mos/x86/interrupt/apic.hpp"
22#include "mos/x86/mm/paging_impl.hpp"
23#include "mos/x86/x86_interrupt.hpp"
24
25#include <mos_stdlib.hpp>
26#include <mos_string.hpp>
27
28typedef enum : u16
29{
30 COM1 = 0x3F8,
31 COM2 = 0x2F8,
32 COM3 = 0x3E8,
33 COM4 = 0x2E8,
34 COM5 = 0x5F8,
35 COM6 = 0x4F8,
36 COM7 = 0x5E8,
37 COM8 = 0x4E8
38} x86ComPort;
39
40class x86SerialDevice : public ISerialDevice
41{
42 x86ComPort port;
43
44 public:
45 explicit x86SerialDevice(x86ComPort port) : port(port)
46 {
47 baudrate_divisor = BAUD_RATE_115200;
48 char_length = CHAR_LENGTH_8;
49 stop_bits = STOP_BITS_15_OR_2;
50 parity = PARITY_EVEN;
51 }
52
53 public:
54 u8 read_byte() override
55 {
56 return port_inb(port);
57 }
58
59 int write_byte(u8 data) override
60 {
61 port_outb(port, value: data);
62 return 0;
63 }
64
65 u8 read_register(serial_register_t reg) override
66 {
67 return port_inb(port: (u16) port + reg);
68 }
69
70 void write_register(serial_register_t reg, u8 data) override
71 {
72 port_outb(port: (u16) port + reg, value: data);
73 }
74
75 bool get_data_ready() override
76 {
77 return (port_inb(port: port + 5) & 1) != 0;
78 }
79};
80
81static Buffer<MOS_PAGE_SIZE> com1_buf;
82static Buffer<MOS_PAGE_SIZE> com2_buf;
83
84x86SerialDevice com1_device{ COM1 };
85x86SerialDevice com2_device{ COM2 };
86
87SerialConsole com1_console{ "com1_console", CONSOLE_CAP_READ, &com1_buf, &com1_device, LightBlue, Black };
88SerialConsole com2_console{ "com2_console", CONSOLE_CAP_READ, &com2_buf, &com2_device, LightBlue, Black };
89
90mos_platform_info_t *const platform_info = &x86_platform;
91mos_platform_info_t x86_platform = { .boot_console = &com1_console };
92const acpi_rsdp_t *acpi_rsdp = NULL;
93
94static bool x86_keyboard_handler(u32 irq, void *data)
95{
96 MOS_UNUSED(data);
97 MOS_ASSERT(irq == IRQ_KEYBOARD);
98 int scancode = port_inb(port: 0x60);
99
100 pr_info("Keyboard scancode: %x", scancode);
101 return true;
102}
103
104static bool x86_pit_timer_handler(u32 irq, void *data)
105{
106 MOS_UNUSED(data);
107 MOS_ASSERT(irq == IRQ_PIT_TIMER);
108 spinlock_acquire(&current_thread->state_lock);
109 reschedule();
110 return true;
111}
112
113void x86_setup_lapic_timer()
114{
115 lapic_set_timer(initial_count: 1000000);
116}
117
118typedef struct _frame
119{
120 struct _frame *bp;
121 ptr_t ip;
122} frame_t;
123
124void x86_dump_stack_at(ptr_t this_frame, bool can_access_vmaps)
125{
126 frame_t *frame = (frame_t *) this_frame;
127
128 const bool do_mapped_check = current_cpu->mm_context;
129
130 if (unlikely(!do_mapped_check))
131 pr_warn(" no mm context available, mapping checks are disabled (early-boot panic?)");
132
133 const bool no_relock = do_mapped_check && spinlock_is_locked(lock: &current_cpu->mm_context->mm_lock);
134 if (no_relock)
135 pr_emerg(" mm lock is already held, stack trace may be corrupted");
136
137 pr_info("-- stack trace:");
138 for (u32 i = 0; frame; i++)
139 {
140#define TRACE_FMT " %-3d [" PTR_FMT "]: "
141 if (do_mapped_check)
142 {
143 const pfn_t pfn = mm_get_phys_addr(current_cpu->mm_context, vaddr: (ptr_t) frame) / MOS_PAGE_SIZE;
144 if (!pfn)
145 {
146 pr_emerg(TRACE_FMT "<corrupted>, aborting backtrace", i, (ptr_t) frame);
147 break;
148 }
149 }
150
151 if (frame->bp == 0)
152 {
153 // end of stack
154 pr_warn(TRACE_FMT "<end>", i, (ptr_t) 0);
155 break;
156 }
157 else if (frame == frame->bp)
158 {
159 pr_emerg(TRACE_FMT "<corrupted>, aborting backtrace", i, (ptr_t) frame);
160 break;
161 }
162 else if (frame->ip >= MOS_KERNEL_START_VADDR)
163 {
164 pr_warn(TRACE_FMT "%ps", i, frame->ip, (void *) frame->ip);
165 }
166 else if (frame->ip == 0)
167 {
168 pr_warn(TRACE_FMT "<end>", i, frame->ip);
169 break;
170 }
171 else if (frame->ip < 1 KB)
172 {
173 pr_emerg(TRACE_FMT "<corrupted?>", i, frame->ip);
174 }
175 else if (can_access_vmaps)
176 {
177 if (!no_relock)
178 spinlock_acquire(&current_cpu->mm_context->mm_lock);
179 vmap_t *const vmap = vmap_obtain(current_cpu->mm_context, vaddr: (ptr_t) frame->ip, NULL);
180
181 if (vmap && vmap->io)
182 {
183 char filepath[MOS_PATH_MAX_LENGTH];
184 io_get_name(io: vmap->io, buf: filepath, size: sizeof(filepath));
185 pr_warn(TRACE_FMT "%s (+" PTR_VLFMT ")", i, frame->ip, filepath, frame->ip - vmap->vaddr + vmap->io_offset);
186 }
187 else
188 {
189 pr_warn(TRACE_FMT "<userspace?, unknown>", i, frame->ip);
190 }
191
192 if (vmap)
193 spinlock_release(&vmap->lock);
194
195 if (!no_relock)
196 spinlock_release(&current_cpu->mm_context->mm_lock);
197 }
198 else
199 {
200 pr_warn(TRACE_FMT "<unknown>", i, frame->ip);
201 }
202 frame = frame->bp;
203 }
204#undef TRACE_FMT
205 pr_info("-- end of stack trace");
206}
207
208void platform_dump_current_stack(void)
209{
210 ptr_t frame;
211 __asm__("mov %%rbp, %0" : "=r"(frame));
212 x86_dump_stack_at(this_frame: frame, can_access_vmaps: true);
213}
214
215void platform_dump_stack(platform_regs_t *regs)
216{
217 x86_dump_stack_at(this_frame: regs->bp, can_access_vmaps: true);
218}
219
220void platform_startup_early()
221{
222 console_register(con: &com2_console);
223 x86_idt_init();
224 x86_init_percpu_gdt();
225 x86_init_percpu_idt();
226 x86_init_percpu_tss();
227
228 // happens before setting up the kernel MM
229 x86_cpu_initialise_caps();
230
231#if MOS_DEBUG_FEATURE(x86_startup)
232 pr_info2("cpu features:");
233
234#define do_print_cpu_feature(feature) \
235 if (cpu_has_feature(CPU_FEATURE_##feature)) \
236 pr_cont(" " #feature);
237 FOR_ALL_CPU_FEATURES(do_print_cpu_feature)
238
239#undef do_print_cpu_feature
240
241#endif
242
243 x86_cpu_setup_xsave_area();
244}
245
246void platform_startup_setup_kernel_mm()
247{
248 x86_paging_setup();
249}
250
251void platform_startup_late()
252{
253 pr_dinfo2(x86_startup, "Parsing ACPI tables...");
254
255 if (platform_info->arch_info.rsdp_addr)
256 {
257 pr_dinfo2(x86_startup, "Using RSDP from bootloader: " PTR_FMT, platform_info->arch_info.rsdp_addr);
258 acpi_rsdp = (const acpi_rsdp_t *) platform_info->arch_info.rsdp_addr;
259 }
260 else
261 {
262 pr_dinfo2(x86_startup, "Searching for RSDP in EBDA...");
263 acpi_rsdp = acpi_find_rsdp(pa_va(X86_EBDA_MEMREGION_PADDR), EBDA_MEMREGION_SIZE);
264 if (!acpi_rsdp)
265 {
266 pr_dinfo2(x86_startup, "Searching for RSDP in BIOS memory region...");
267 acpi_rsdp = acpi_find_rsdp(pa_va(X86_BIOS_MEMREGION_PADDR), BIOS_MEMREGION_SIZE);
268 if (!acpi_rsdp)
269 mos_panic("RSDP not found");
270 }
271 }
272
273 const pmm_region_t *acpi_region = pmm_find_reserved_region(needle: acpi_rsdp->v1.rsdt_addr);
274 MOS_ASSERT_X(acpi_region && acpi_region->reserved, "ACPI region not found or not reserved");
275
276 acpi_parse_rsdt(rsdp: acpi_rsdp);
277
278 pr_dinfo2(x86_startup, "Initializing APICs...");
279 madt_parse_table();
280 lapic_enable(); // enable the local APIC
281 current_cpu->id = x86_platform.boot_cpu_id = lapic_get_id();
282
283 pic_remap_irq();
284 ioapic_init();
285
286 rtc_init();
287
288 interrupt_handler_register(irq: IRQ_PIT_TIMER, handler: x86_pit_timer_handler, NULL);
289 interrupt_handler_register(irq: IRQ_CMOS_RTC, handler: rtc_irq_handler, NULL);
290 interrupt_handler_register(irq: IRQ_KEYBOARD, handler: x86_keyboard_handler, NULL);
291 interrupt_handler_register(irq: IRQ_COM1, handler: serial_console_irq_handler, data: &com1_console);
292
293 ioapic_enable_interrupt(irq: IRQ_CMOS_RTC, lapic_id: x86_platform.boot_cpu_id);
294 ioapic_enable_interrupt(irq: IRQ_KEYBOARD, lapic_id: x86_platform.boot_cpu_id);
295 ioapic_enable_interrupt(irq: IRQ_COM1, lapic_id: x86_platform.boot_cpu_id);
296
297 x86_setup_lapic_timer();
298
299 x86_unblock_aps();
300}
301