| 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 | const auto hhdm_response = hhdm.response; |
| 84 | if (hhdm_response && hhdm_response->offset) |
| 85 | platform_info->direct_map_base = hhdm_response->offset; // early-populate direct_map_base for pa_va |
| 86 | invoke_constructors(); |
| 87 | |
| 88 | if (platform_info->boot_console) |
| 89 | platform_info->boot_console->Register(); |
| 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 | |