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