Revert "protos/limine: Drop support for base revisions 0-3, require 4 on x86"
This reverts commit f0e8264e1a4cfa067192a37cdeda2cce2b15c53a.
diff --git a/common/lib/elf.c b/common/lib/elf.c
index f7f3dd3b..ee686bd3 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -650,6 +650,73 @@ end_of_pt_segment:
return true;
}
+bool elf64_load_section(uint8_t *elf, size_t file_size, void *buffer, const char *name, size_t limit, uint64_t slide) {
+ struct elf64_hdr *hdr = (void *)elf;
+
+ elf64_validate(hdr);
+
+ if (hdr->sh_num == 0) {
+ return false;
+ }
+
+ if (hdr->shdr_size < sizeof(struct elf64_shdr)) {
+ panic(true, "elf: shdr_size < sizeof(struct elf64_shdr)");
+ }
+
+ if (hdr->shstrndx >= hdr->sh_num) {
+ return false;
+ }
+
+ // Validate section header table is within file bounds
+ uint64_t shdr_table_end = (uint64_t)hdr->shoff + (uint64_t)hdr->sh_num * hdr->shdr_size;
+ if (shdr_table_end > file_size) {
+ return false;
+ }
+
+ struct elf64_shdr *shstrtab = (void *)elf + (hdr->shoff + hdr->shstrndx * hdr->shdr_size);
+
+ // Validate shstrtab offset and size are within file bounds
+ if (shstrtab->sh_offset >= file_size || shstrtab->sh_size > file_size - shstrtab->sh_offset) {
+ return false;
+ }
+
+ char *names = (void *)elf + shstrtab->sh_offset;
+
+ for (uint16_t i = 0; i < hdr->sh_num; i++) {
+ struct elf64_shdr *section = (void *)elf + (hdr->shoff + i * hdr->shdr_size);
+
+ // Validate sh_name is within the string table
+ if (section->sh_name >= shstrtab->sh_size) {
+ continue;
+ }
+
+ // Ensure the string is NUL-terminated within the string table
+ if (!memchr(&names[section->sh_name], '\0', shstrtab->sh_size - section->sh_name)) {
+ continue;
+ }
+
+ if (strcmp(&names[section->sh_name], name) == 0) {
+ // Validate section data is within file bounds
+ if (section->sh_offset >= file_size || section->sh_size > file_size - section->sh_offset) {
+ return false;
+ }
+
+ if (limit == 0) {
+ *(void **)buffer = ext_mem_alloc(section->sh_size);
+ buffer = *(void **)buffer;
+ limit = section->sh_size;
+ }
+ if (section->sh_size > limit) {
+ return false;
+ }
+ memcpy(buffer, elf + section->sh_offset, section->sh_size);
+ return elf64_apply_relocations(elf, hdr, buffer, section->sh_addr, section->sh_size, slide);
+ }
+ }
+
+ return false;
+}
+
static uint64_t elf64_max_align(uint8_t *elf) {
uint64_t ret = 0;
diff --git a/common/lib/elf.h b/common/lib/elf.h
index f2931660..e8d5b280 100644
--- a/common/lib/elf.h
+++ b/common/lib/elf.h
@@ -24,6 +24,7 @@ int elf_bits(uint8_t *elf);
struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf);
struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf);
+bool elf64_load_section(uint8_t *elf, size_t file_size, void *buffer, const char *name, size_t limit, uint64_t slide);
bool elf64_load(uint8_t *elf, size_t file_size, uint64_t *entry_point, uint64_t *_slide, uint32_t alloc_type, bool kaslr, struct mem_range **ranges, uint64_t *ranges_count, uint64_t *physical_base, uint64_t *virtual_base, uint64_t *image_size, uint64_t *image_size_before_bss, bool *is_reloc);
bool elf32_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 2e35209c..8cc17bdd 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -59,11 +59,21 @@ static enum executable_format detect_kernel_format(uint8_t *kernel, size_t kerne
static int paging_mode;
-static uint64_t get_hhdm_span_top(void) {
- uint64_t ret = 0;
+static uint64_t get_hhdm_span_top(int base_revision) {
+ uint64_t ret = base_revision >= 3 ? 0 : 0x100000000;
for (size_t i = 0; i < memmap_entries; i++) {
- if (memmap[i].type == MEMMAP_RESERVED
- || memmap[i].type == MEMMAP_BAD_MEMORY) {
+ if (((base_revision >= 1 && base_revision < 3) || base_revision >= 4) && (
+ memmap[i].type == MEMMAP_RESERVED
+ || memmap[i].type == MEMMAP_BAD_MEMORY)) {
+ continue;
+ }
+
+ if (base_revision == 3 && (
+ memmap[i].type != MEMMAP_USABLE
+ && memmap[i].type != MEMMAP_BOOTLOADER_RECLAIMABLE
+ && memmap[i].type != MEMMAP_KERNEL_AND_MODULES
+ && memmap[i].type != MEMMAP_FRAMEBUFFER
+ && memmap[i].type != MEMMAP_EFI_RECLAIMABLE)) {
continue;
}
@@ -71,6 +81,10 @@ static uint64_t get_hhdm_span_top(void) {
uint64_t length = memmap[i].length;
uint64_t top = base + length;
+ if (base_revision < 3 && base < 0x100000000) {
+ base = 0x100000000;
+ }
+
if (base >= top) {
continue;
}
@@ -144,7 +158,8 @@ static void limine_memcpy_to_64(uint64_t dst, void *src, size_t count) {
}
#endif
-static pagemap_t build_pagemap(bool nx, struct mem_range *ranges, size_t ranges_count,
+static pagemap_t build_pagemap(int base_revision,
+ bool nx, struct mem_range *ranges, size_t ranges_count,
uint64_t physical_base, uint64_t virtual_base,
uint64_t direct_map_offset) {
pagemap_t pagemap = new_pagemap(paging_mode);
@@ -170,6 +185,16 @@ static pagemap_t build_pagemap(bool nx, struct mem_range *ranges, size_t ranges_
map_pages(pagemap, virt, phys, pf, ranges[i].length);
}
+ // Map 0x1000->4GiB range to identity if base revision == 0
+ if (base_revision == 0) {
+ map_pages(pagemap, 0x1000, 0x1000, VMM_FLAG_WRITE, 0x100000000 - 0x1000);
+ }
+
+ // Map 0->4GiB range to HHDM if base revision < 3
+ if (base_revision < 3) {
+ map_pages(pagemap, direct_map_offset, 0, VMM_FLAG_WRITE, 0x100000000);
+ }
+
size_t _memmap_entries = memmap_entries;
struct memmap_entry *_memmap =
ext_mem_alloc(_memmap_entries * sizeof(struct memmap_entry));
@@ -178,8 +203,18 @@ static pagemap_t build_pagemap(bool nx, struct mem_range *ranges, size_t ranges_
// Map all free memory regions to the higher half direct map offset
for (size_t i = 0; i < _memmap_entries; i++) {
- if (_memmap[i].type == MEMMAP_RESERVED
- || _memmap[i].type == MEMMAP_BAD_MEMORY) {
+ if (((base_revision >= 1 && base_revision < 3) || base_revision >= 4) && (
+ _memmap[i].type == MEMMAP_RESERVED
+ || _memmap[i].type == MEMMAP_BAD_MEMORY)) {
+ continue;
+ }
+
+ if (base_revision == 3 && (
+ _memmap[i].type != MEMMAP_USABLE
+ && _memmap[i].type != MEMMAP_BOOTLOADER_RECLAIMABLE
+ && _memmap[i].type != MEMMAP_KERNEL_AND_MODULES
+ && _memmap[i].type != MEMMAP_FRAMEBUFFER
+ && _memmap[i].type != MEMMAP_EFI_RECLAIMABLE)) {
continue;
}
@@ -187,6 +222,10 @@ static pagemap_t build_pagemap(bool nx, struct mem_range *ranges, size_t ranges_
uint64_t length = _memmap[i].length;
uint64_t top = base + length;
+ if (base_revision < 3 && base < 0x100000000) {
+ base = 0x100000000;
+ }
+
if (base >= top) {
continue;
}
@@ -195,6 +234,9 @@ static pagemap_t build_pagemap(bool nx, struct mem_range *ranges, size_t ranges_
uint64_t aligned_top = ALIGN_UP(top, 0x1000);
uint64_t aligned_length = aligned_top - aligned_base;
+ if (base_revision == 0) {
+ map_pages(pagemap, aligned_base, aligned_base, VMM_FLAG_WRITE, aligned_length);
+ }
map_pages(pagemap, direct_map_offset + aligned_base, aligned_base, VMM_FLAG_WRITE, aligned_length);
}
@@ -212,12 +254,17 @@ static pagemap_t build_pagemap(bool nx, struct mem_range *ranges, size_t ranges_
uint64_t aligned_top = ALIGN_UP(top, 0x1000);
uint64_t aligned_length = aligned_top - aligned_base;
+ if (base_revision == 0) {
+ map_pages(pagemap, aligned_base, aligned_base, VMM_FLAG_WRITE | VMM_FLAG_FB, aligned_length);
+ }
map_pages(pagemap, direct_map_offset + aligned_base, aligned_base, VMM_FLAG_WRITE | VMM_FLAG_FB, aligned_length);
}
// XXX we do this as a quick and dirty way to switch to the higher half
#if defined (__x86_64__) || defined (__i386__)
- map_pages(pagemap, 0, 0, VMM_FLAG_WRITE, 0x100000000);
+ if (base_revision >= 1) {
+ map_pages(pagemap, 0, 0, VMM_FLAG_WRITE, 0x100000000);
+ }
#endif
return pagemap;
@@ -499,11 +546,12 @@ noreturn void limine_load(char *config, char *cmdline) {
}
base_revision_found = true;
base_revision = p[2];
- if (p[2] > SUPPORTED_BASE_REVISION) {
- panic(true, "limine: Requested base revision %u is too new (maximum supported: %u)", (int)p[2], SUPPORTED_BASE_REVISION);
+ if (p[2] <= SUPPORTED_BASE_REVISION) {
+ // Set to 0 to mean "supported"
+ base_rev_p2_ptr = &p[2];
+ } else {
+ base_revision = SUPPORTED_BASE_REVISION;
}
- // Set to 0 to mean "supported"
- base_rev_p2_ptr = &p[2];
base_rev_p1_ptr = &p[1];
}
}
@@ -514,52 +562,62 @@ noreturn void limine_load(char *config, char *cmdline) {
*base_rev_p2_ptr = 0;
}
-#if defined (__x86_64__) || defined (__i386__)
- if (base_revision < 4) {
- panic(true, "limine: Base revision %u is no longer supported (minimum: 4)", base_revision);
- }
-#else
+#if !defined (__x86_64__) && !defined (__i386__)
if (base_revision < 6) {
panic(true, "limine: Base revision %u is no longer supported on this architecture (minimum: 6)", base_revision);
}
#endif
// Load requests
+ uint64_t *limine_reqs = NULL;
requests = ext_mem_alloc(MAX_REQUESTS * sizeof(void *));
requests_count = 0;
- uint64_t common_magic[2] = { LIMINE_COMMON_MAGIC };
- for (size_t i = 0; i < ALIGN_DOWN(image_size_before_bss, 8); i += 8) {
- uint64_t *p = (void *)(uintptr_t)physical_base + i;
-
- // Check if start marker hit
- if (p[0] == limine_requests_start_marker[0] && p[1] == limine_requests_start_marker[1]
- && p[2] == limine_requests_start_marker[2] && p[3] == limine_requests_start_marker[3]) {
- requests_count = 0;
- continue;
+ if (base_revision == 0 && kernel_format == EXECUTABLE_FORMAT_ELF && elf64_load_section(kernel, kernel_file->size, &limine_reqs, ".limine_reqs", 0, slide)) {
+ for (size_t i = 0; ; i++) {
+ if (i >= MAX_REQUESTS) {
+ panic(true, "limine: Maximum requests exceeded");
+ }
+ if (limine_reqs[i] == 0) {
+ break;
+ }
+ requests[i] = (void *)(uintptr_t)((limine_reqs[i] - virtual_base) + physical_base);
+ requests_count++;
}
+ } else {
+ uint64_t common_magic[2] = { LIMINE_COMMON_MAGIC };
+ for (size_t i = 0; i < ALIGN_DOWN(image_size_before_bss, 8); i += 8) {
+ uint64_t *p = (void *)(uintptr_t)physical_base + i;
+
+ // Check if start marker hit
+ if (p[0] == limine_requests_start_marker[0] && p[1] == limine_requests_start_marker[1]
+ && p[2] == limine_requests_start_marker[2] && p[3] == limine_requests_start_marker[3]) {
+ requests_count = 0;
+ continue;
+ }
- // Check if end marker hit
- if (p[0] == limine_requests_end_marker[0] && p[1] == limine_requests_end_marker[1]) {
- break;
- }
+ // Check if end marker hit
+ if (p[0] == limine_requests_end_marker[0] && p[1] == limine_requests_end_marker[1]) {
+ break;
+ }
- if (p[0] != common_magic[0]) {
- continue;
- }
- if (p[1] != common_magic[1]) {
- continue;
- }
+ if (p[0] != common_magic[0]) {
+ continue;
+ }
+ if (p[1] != common_magic[1]) {
+ continue;
+ }
- if (requests_count == MAX_REQUESTS) {
- panic(true, "limine: Maximum requests exceeded");
- }
+ if (requests_count == MAX_REQUESTS) {
+ panic(true, "limine: Maximum requests exceeded");
+ }
- // Check for a conflict
- if (_get_request(p) != NULL) {
- panic(true, "limine: Conflict detected for request ID %X %X", p[2], p[3]);
- }
+ // Check for a conflict
+ if (_get_request(p) != NULL) {
+ panic(true, "limine: Conflict detected for request ID %X %X", p[2], p[3]);
+ }
- requests[requests_count++] = p;
+ requests[requests_count++] = p;
+ }
}
#if defined (__x86_64__) || defined (__i386__)
@@ -569,7 +627,7 @@ noreturn void limine_load(char *config, char *cmdline) {
}
#endif
- uint64_t hhdm_span_top = get_hhdm_span_top();
+ uint64_t hhdm_span_top = get_hhdm_span_top(base_revision);
#if defined (__x86_64__) || defined (__i386__)
uint64_t maxphyaddr;
@@ -983,7 +1041,7 @@ FEAT_START
struct limine_rsdp_response *rsdp_response =
ext_mem_alloc(sizeof(struct limine_rsdp_response));
- rsdp_response->address = reported_addr(rsdp);
+ rsdp_response->address = (base_revision <= 2 || base_revision >= 4) ? reported_addr(rsdp) : (uintptr_t)rsdp;
rsdp_request->response = reported_addr(rsdp_response);
FEAT_END
@@ -1005,10 +1063,10 @@ FEAT_START
ext_mem_alloc(sizeof(struct limine_smbios_response));
if (smbios_entry_32) {
- smbios_response->entry_32 = (base_revision >= 5) ? reported_addr(smbios_entry_32) : (uintptr_t)smbios_entry_32;
+ smbios_response->entry_32 = (base_revision <= 2 || base_revision >= 5) ? reported_addr(smbios_entry_32) : (uintptr_t)smbios_entry_32;
}
if (smbios_entry_64) {
- smbios_response->entry_64 = (base_revision >= 5) ? reported_addr(smbios_entry_64) : (uintptr_t)smbios_entry_64;
+ smbios_response->entry_64 = (base_revision <= 2 || base_revision >= 5) ? reported_addr(smbios_entry_64) : (uintptr_t)smbios_entry_64;
}
smbios_request->response = reported_addr(smbios_response);
@@ -1025,7 +1083,7 @@ FEAT_START
struct limine_efi_system_table_response *est_response =
ext_mem_alloc(sizeof(struct limine_efi_system_table_response));
- est_response->address = (base_revision >= 5) ? reported_addr(gST) : (uintptr_t)gST;
+ est_response->address = (base_revision <= 2 || base_revision >= 5) ? reported_addr(gST) : (uintptr_t)gST;
est_request->response = reported_addr(est_response);
FEAT_END
@@ -1557,17 +1615,24 @@ FEAT_START
FEAT_END
#endif
- acpi_map_tables();
- if (base_revision >= 5) {
- smbios_map_tables();
+ if (base_revision < 3) {
+ pmm_sanitiser_keep_first_page = false;
+ pmm_sanitise_entries(memmap, &memmap_entries, true);
+ }
+
+ if (base_revision >= 4) {
+ acpi_map_tables();
+ if (base_revision >= 5) {
+ smbios_map_tables();
#if defined (UEFI)
- efi_map_runtime_entries();
+ efi_map_runtime_entries();
#endif
+ }
+ pmm_sanitise_entries(memmap, &memmap_entries, true);
}
- pmm_sanitise_entries(memmap, &memmap_entries, true);
pagemap_t pagemap = {0};
- pagemap = build_pagemap(nx_available, ranges, ranges_count,
+ pagemap = build_pagemap(base_revision, nx_available, ranges, ranges_count,
physical_base, virtual_base, direct_map_offset);
#if defined (__aarch64__)
@@ -1786,12 +1851,13 @@ FEAT_END
uint64_t reported_stack = reported_addr(stack);
- common_spinup(limine_spinup_32, 10,
+ common_spinup(limine_spinup_32, 11,
paging_mode, (uint32_t)(uintptr_t)pagemap.top_level,
(uint32_t)entry_point, (uint32_t)(entry_point >> 32),
(uint32_t)reported_stack, (uint32_t)(reported_stack >> 32),
(uint32_t)(uintptr_t)local_gdt, nx_available,
- (uint32_t)direct_map_offset, (uint32_t)(direct_map_offset >> 32)
+ (uint32_t)direct_map_offset, (uint32_t)(direct_map_offset >> 32),
+ (uint32_t)base_revision
);
#elif defined (__aarch64__)
vmm_assert_4k_pages();
diff --git a/common/protos/limine_32.asm_x86 b/common/protos/limine_32.asm_x86
index 79b6b424..75819e4b 100644
--- a/common/protos/limine_32.asm_x86
+++ b/common/protos/limine_32.asm_x86
@@ -90,6 +90,9 @@ bits 64
retq
.hh:
+ cmp dword [rsp+44], 1
+ jb .no_unmap_lower_half
+
; Unmap lower half entirely
mov rsi, cr3
lea rdi, [rsi + rax]
@@ -98,6 +101,8 @@ bits 64
rep stosq
mov cr3, rsi
+ .no_unmap_lower_half:
+
; Push fake return address
mov rsi, [rsp+20] ; stack
sub rsi, 8
