1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#define pr_fmt(fmt) "limine: " fmt
4
5#include "limine.h"
6
7#include "mos/device/console.h"
8#include "mos/misc/cmdline.h"
9#include "mos/misc/setup.h"
10#include "mos/mm/mm.h"
11#include "mos/syslog/printk.h"
12
13#include <mos_stdlib.h>
14
15#define limine_request __section(".limine.requests") __used static volatile
16
17MOS_WARNING_PUSH
18MOS_WARNING_DISABLE("-Wextra-semi")
19MOS_WARNING_DISABLE("-Wpedantic")
20__used __section(".limine.markers.requests_start") static volatile LIMINE_REQUESTS_START_MARKER;
21__used __section(".limine.markers.requests_end") static volatile LIMINE_REQUESTS_END_MARKER;
22limine_request LIMINE_BASE_REVISION(2);
23MOS_WARNING_POP
24
25limine_request struct limine_bootloader_info_request bootloader_info = { .id = LIMINE_BOOTLOADER_INFO_REQUEST, .revision = 0 };
26limine_request struct limine_dtb_request dtb = { .id = LIMINE_DTB_REQUEST, .revision = 0 };
27limine_request struct limine_efi_system_table_request efi_system_table = { .id = LIMINE_EFI_SYSTEM_TABLE_REQUEST, .revision = 0 };
28limine_request struct limine_framebuffer_request framebuffer = { .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0 };
29limine_request struct limine_hhdm_request hhdm = { .id = LIMINE_HHDM_REQUEST, .revision = 0 };
30limine_request struct limine_kernel_address_request kernel_address = { .id = LIMINE_KERNEL_ADDRESS_REQUEST, .revision = 0 };
31limine_request struct limine_kernel_file_request kernel_file = { .id = LIMINE_KERNEL_FILE_REQUEST, .revision = 0 };
32limine_request struct limine_memmap_request memmap = { .id = LIMINE_MEMMAP_REQUEST, .revision = 0 };
33limine_request struct limine_module_request module = { .id = LIMINE_MODULE_REQUEST, .revision = 0 };
34limine_request struct limine_paging_mode_request paging_mode = { .id = LIMINE_PAGING_MODE_REQUEST, .revision = 0, .mode = LIMINE_PAGING_MODE_DEFAULT };
35limine_request struct limine_rsdp_request rsdp = { .id = LIMINE_RSDP_REQUEST, .revision = 0 };
36limine_request struct limine_smp_request smp = { .id = LIMINE_SMP_REQUEST, .revision = 0, .flags = 0 };
37limine_request struct limine_stack_size_request stack_size = { .id = LIMINE_STACK_SIZE_REQUEST, .revision = 0, .stack_size = 16 MB };
38
39static void add_to_memmap(pfn_t start, size_t npages, bool reserved, u32 type, const char *typestr)
40{
41 if (start + npages < 1 MB / MOS_PAGE_SIZE)
42 type = LIMINE_MEMMAP_RESERVED, reserved = true;
43
44 if (npages == 0)
45 return;
46
47 pmm_region_t *entry = &platform_info->pmm_regions[platform_info->num_pmm_regions++];
48 entry->reserved = reserved;
49 entry->nframes = npages;
50 entry->pfn_start = start;
51 entry->type = type;
52 pr_dinfo2(limine, "%25s: " PFNADDR_RANGE " (%zu pages)", typestr, PFNADDR(entry->pfn_start, entry->pfn_start + entry->nframes), entry->nframes);
53
54 if (entry->type == LIMINE_MEMMAP_USABLE || entry->type == LIMINE_MEMMAP_KERNEL_AND_MODULES || entry->type == LIMINE_MEMMAP_FRAMEBUFFER ||
55 entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE || entry->type == LIMINE_MEMMAP_ACPI_RECLAIMABLE || entry->type == LIMINE_MEMMAP_ACPI_NVS)
56 platform_info->max_pfn = MAX(platform_info->max_pfn, entry->pfn_start + entry->nframes);
57}
58
59static void ap_entry(struct limine_smp_info *info)
60{
61 u64 processor_id = info->processor_id;
62 pr_dinfo(limine, "AP started: #%llu", processor_id);
63 platform_ap_entry(arg: info->extra_argument);
64}
65
66void limine_entry(void)
67{
68 if (hhdm.response->offset)
69 platform_info->direct_map_base = hhdm.response->offset; // early-populate direct_map_base
70
71 if (platform_info->boot_console)
72 console_register(con: platform_info->boot_console);
73
74#if MOS_DEBUG_FEATURE(limine)
75 pr_cont("bootloader: %s, version %s", bootloader_info.response ? bootloader_info.response->name : "unknown",
76 bootloader_info.response ? bootloader_info.response->version : "unknown");
77 pr_info2("stack size: %zu KB", stack_size.stack_size / (1 KB));
78#endif
79
80 if (!LIMINE_BASE_REVISION_SUPPORTED)
81 mos_panic("Unsupported Limine base revision");
82
83 if (paging_mode.response == NULL)
84 mos_panic("No paging mode found");
85
86 struct limine_paging_mode_response *paging_mode_response = paging_mode.response;
87 if (paging_mode_response->mode != LIMINE_PAGING_MODE_DEFAULT)
88 mos_panic("non-default paging mode not supported");
89
90 if (smp.response == NULL)
91 mos_panic("No SMP info found");
92
93 struct limine_smp_response *smp_response = smp.response;
94 for (size_t i = 0; i < smp_response->cpu_count; i++)
95 {
96 struct limine_smp_info *info = smp_response->cpus[i];
97 if (info->processor_id == 0)
98 continue; // skip BSP
99
100 __atomic_store_n(&info->goto_address, ap_entry, __ATOMIC_SEQ_CST);
101 }
102
103 if (kernel_file.response == NULL)
104 mos_panic("No kernel file found");
105
106 mos_cmdline_init(bootloader_cmdline: kernel_file.response->kernel_file->cmdline);
107 startup_invoke_early_cmdline_hooks();
108
109 if (hhdm.response == NULL)
110 mos_panic("No HHDM found");
111
112 platform_info->direct_map_base = hhdm.response->offset;
113 pr_dinfo2(limine, "Direct map base: " PTR_FMT, platform_info->direct_map_base);
114
115 if (memmap.response == NULL)
116 mos_panic("No memory map found"); // are we able to panic at this early stage?
117
118 pfn_t last_end_pfn = 0;
119
120 struct limine_memmap_response *memmap_response = memmap.response;
121 for (size_t i = 0; i < memmap_response->entry_count; i++)
122 {
123 const struct limine_memmap_entry *entry = memmap_response->entries[i];
124
125 const pfn_t start_pfn = entry->base / MOS_PAGE_SIZE;
126 const size_t npages = entry->length / MOS_PAGE_SIZE;
127
128 // there's a gap between the last region and this one
129 // we fake a reserved region to fill the gap
130 if (last_end_pfn != start_pfn)
131 add_to_memmap(start: last_end_pfn, npages: start_pfn - last_end_pfn, reserved: true, LIMINE_MEMMAP_RESERVED, typestr: "<hole>");
132 last_end_pfn = start_pfn + npages;
133
134 const char *typestr = NULL;
135 switch (entry->type)
136 {
137 case LIMINE_MEMMAP_USABLE: typestr = "usable"; break;
138 case LIMINE_MEMMAP_RESERVED: typestr = "reserved"; break;
139 case LIMINE_MEMMAP_ACPI_RECLAIMABLE: typestr = "ACPI reclaimable"; break;
140 case LIMINE_MEMMAP_ACPI_NVS: typestr = "ACPI NVS"; break;
141 case LIMINE_MEMMAP_BAD_MEMORY: typestr = "bad memory"; break;
142 case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE: typestr = "bootloader reclaimable"; break;
143 case LIMINE_MEMMAP_KERNEL_AND_MODULES: typestr = "kernel and modules"; break;
144 case LIMINE_MEMMAP_FRAMEBUFFER: typestr = "framebuffer"; break;
145 }
146
147 add_to_memmap(start: start_pfn, npages, reserved: entry->type != LIMINE_MEMMAP_USABLE, type: entry->type, typestr);
148 }
149
150 if (module.response == NULL)
151 mos_panic("No modules found");
152
153 struct limine_module_response *module_response = module.response;
154 if (module_response->module_count != 1)
155 mos_panic("Expected exactly one module, got %zu", module_response->module_count);
156
157 struct limine_file *module = module_response->modules[0];
158 pr_dinfo2(limine, "initrd: %s, " PTR_RANGE, module->path, (ptr_t) module->address, (ptr_t) module->address + module->size);
159 platform_info->initrd_pfn = va_pfn(module->address);
160 platform_info->initrd_npages = ALIGN_UP_TO_PAGE(module->size) / MOS_PAGE_SIZE;
161 pr_dinfo2(limine, "initrd at " PFN_FMT ", size %zu pages", platform_info->initrd_pfn, platform_info->initrd_npages);
162
163 if (kernel_address.response == NULL)
164 mos_panic("No kernel address found");
165
166 struct limine_kernel_address_response *kernel_address_response = kernel_address.response;
167 platform_info->k_basepfn = kernel_address_response->physical_base / MOS_PAGE_SIZE;
168 platform_info->k_basevaddr = kernel_address_response->virtual_base;
169
170 if (rsdp.response)
171 {
172 platform_info->arch_info.rsdp_addr = (ptr_t) rsdp.response->address;
173 platform_info->arch_info.rsdp_revision = rsdp.response->revision;
174 pr_dinfo2(limine, "RSDP at " PTR_FMT ", revision %u", platform_info->arch_info.rsdp_addr, platform_info->arch_info.rsdp_revision);
175 }
176 else
177 {
178 pr_dinfo2(limine, "No RSDP found from limine");
179 }
180
181 if (dtb.response)
182 {
183#if MOS_PLATFORM_HAS_FDT
184 platform_info->arch_info.fdt = dtb.response->dtb_ptr;
185 pr_dinfo2(limine, "DTB at " PTR_FMT, (ptr_t) platform_info->arch_info.fdt);
186#endif
187 }
188 else
189 {
190 pr_dinfo2(limine, "No DTB found from limine");
191 }
192
193 mos_start_kernel();
194}
195