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 | |
17 | MOS_WARNING_PUSH |
18 | MOS_WARNING_DISABLE("-Wextra-semi" ) |
19 | MOS_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; |
22 | limine_request LIMINE_BASE_REVISION(2); |
23 | MOS_WARNING_POP |
24 | |
25 | limine_request struct limine_bootloader_info_request bootloader_info = { .id = LIMINE_BOOTLOADER_INFO_REQUEST, .revision = 0 }; |
26 | limine_request struct limine_dtb_request dtb = { .id = LIMINE_DTB_REQUEST, .revision = 0 }; |
27 | limine_request struct limine_efi_system_table_request efi_system_table = { .id = LIMINE_EFI_SYSTEM_TABLE_REQUEST, .revision = 0 }; |
28 | limine_request struct limine_framebuffer_request framebuffer = { .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0 }; |
29 | limine_request struct limine_hhdm_request hhdm = { .id = LIMINE_HHDM_REQUEST, .revision = 0 }; |
30 | limine_request struct limine_kernel_address_request kernel_address = { .id = LIMINE_KERNEL_ADDRESS_REQUEST, .revision = 0 }; |
31 | limine_request struct limine_kernel_file_request kernel_file = { .id = LIMINE_KERNEL_FILE_REQUEST, .revision = 0 }; |
32 | limine_request struct limine_memmap_request memmap = { .id = LIMINE_MEMMAP_REQUEST, .revision = 0 }; |
33 | limine_request struct limine_module_request module = { .id = LIMINE_MODULE_REQUEST, .revision = 0 }; |
34 | limine_request struct limine_paging_mode_request paging_mode = { .id = LIMINE_PAGING_MODE_REQUEST, .revision = 0, .mode = LIMINE_PAGING_MODE_DEFAULT }; |
35 | limine_request struct limine_rsdp_request rsdp = { .id = LIMINE_RSDP_REQUEST, .revision = 0 }; |
36 | limine_request struct limine_smp_request smp = { .id = LIMINE_SMP_REQUEST, .revision = 0, .flags = 0 }; |
37 | limine_request struct limine_stack_size_request stack_size = { .id = LIMINE_STACK_SIZE_REQUEST, .revision = 0, .stack_size = 16 MB }; |
38 | |
39 | static 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 | |
59 | static 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 | |
66 | void 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 | |