limine: Rework request-response system

This commit is contained in:
mintsuki 2022-03-13 05:35:29 +01:00
parent e33a76bd99
commit f9c9ec84d5
3 changed files with 157 additions and 131 deletions

View File

@ -9,58 +9,58 @@
# define LIMINE_PTR(TYPE) TYPE
#endif
#define LIMINE_MAGIC { 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b }
struct limine_header {
uint64_t magic[2];
LIMINE_PTR(void *) entry;
uint64_t features_count;
LIMINE_PTR(void *) features;
};
#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b
// Boot info
#define LIMINE_BOOT_INFO_REQUEST ((LIMINE_PTR(void *)) 1 )
#define LIMINE_BOOT_INFO_REQUEST { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 }
struct limine_boot_info_response {
uint64_t flags;
LIMINE_PTR(char *) loader;
};
struct limine_boot_info_request {
uint64_t id[4];
uint64_t flags;
LIMINE_PTR(struct limine_boot_info_response *) response;
};
// Framebuffer
#define LIMINE_FRAMEBUFFER_REQUEST ((LIMINE_PTR(void *)) 2 )
#define LIMINE_FRAMEBUFFER_REQUEST { LIMINE_COMMON_MAGIC, 0xcbfe81d7dd2d1977, 0x063150319ebc9b71 }
struct limine_framebuffer_request {
LIMINE_PTR(void *) id;
struct limine_framebuffer_response {
uint64_t flags;
};
#define LIMINE_FRAMEBUFFER_PREFER_LFB 0
#define LIMINE_FRAMEBUFFER_PREFER_TEXT 1
#define LIMINE_FRAMEBUFFER_ENFORCE_PREFER (1 << 8)
struct limine_framebuffer_request {
uint64_t id[4];
uint64_t flags;
uint16_t width;
uint16_t height;
uint16_t bpp;
uint16_t unused;
LIMINE_PTR(struct limine_framebuffer_response *) response;
};
// 5-level paging
#define LIMINE_5_LEVEL_PAGING_REQUEST ((LIMINE_PTR(void *)) 3 )
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
struct limine_5_level_paging_response {
uint64_t flags;
};
// PMRs
#define LIMINE_PMR_REQUEST ((LIMINE_PTR(void *)) 4 )
struct limine_5_level_paging_request {
uint64_t id[4];
uint64_t flags;
LIMINE_PTR(struct limine_5_level_paging_response *) response;
};
// Memory map
#define LIMINE_MEMMAP_REQUEST ((LIMINE_PTR(void *)) 5 )
#define LIMINE_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 }
#define LIMINE_MEMMAP_USABLE 0
#define LIMINE_MEMMAP_RESERVED 1
@ -84,4 +84,26 @@ struct limine_memmap_response {
LIMINE_PTR(struct limine_memmap_entry *) entries;
};
struct limine_memmap_request {
uint64_t id[4];
uint64_t flags;
LIMINE_PTR(struct limine_memmap_response *) response;
};
// Entry point
#define LIMINE_ENTRY_POINT_REQUEST { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a }
struct limine_entry_point_response {
uint64_t flags;
};
struct limine_entry_point_request {
uint64_t id[4];
uint64_t flags;
LIMINE_PTR(struct limine_entry_point_response *) response;
LIMINE_PTR(void *) entry;
};
#endif

View File

@ -32,50 +32,41 @@
#include <protos/limine.h>
#include <limine.h>
static uint64_t features_count, physical_base, virtual_base, slide, direct_map_offset;
static uint64_t *features, *features_orig;
#define MAX_REQUESTS 128
static uint64_t physical_base, virtual_base, slide, direct_map_offset;
static size_t requests_count;
static void *requests[MAX_REQUESTS];
static uint64_t reported_addr(void *addr) {
return (uint64_t)(uintptr_t)addr + direct_map_offset;
}
/*
static uintptr_t get_phys_addr(uint64_t addr) {
return physical_base + (addr - virtual_base);
}
*/
struct feature {
bool found;
size_t index;
void *request;
};
static void *_get_request(uint64_t id[4]) {
for (size_t i = 0; i < requests_count; i++) {
uint64_t *p = requests[i];
static struct feature get_feature(uint64_t id) {
for (size_t i = 0; i < features_count; i++) {
if (features[i] < 0xffffffff80000000 && features[i] == id) {
return (struct feature){
.found = true,
.index = i,
.request = NULL
};
} else {
uint64_t *id_ptr = (void *)get_phys_addr(features[i] + slide);
if (*id_ptr == id) {
return (struct feature){
.found = true,
.index = i,
.request = (void *)id_ptr
};
}
if (p[2] != id[2]) {
continue;
}
if (p[3] != id[3]) {
continue;
}
return p;
}
return (struct feature){
.found = false,
.index = 0,
.request = NULL
};
return NULL;
}
#define get_request(REQ) _get_request((uint64_t[4])REQ)
#define FEAT_START do {
#define FEAT_END } while (0);
@ -88,8 +79,6 @@ bool limine_load(char *config, char *cmdline) {
if (kernel_path == NULL)
panic(true, "limine: KERNEL_PATH not specified");
print("limine: Loading kernel `%s`...\n", kernel_path);
struct file_handle *kernel_file;
if ((kernel_file = uri_open(kernel_path)) == NULL)
panic(true, "limine: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
@ -102,26 +91,6 @@ bool limine_load(char *config, char *cmdline) {
fclose(kernel_file);
// Search for header
struct limine_header *limine_header = NULL;
uint64_t limine_magic[2] = LIMINE_MAGIC;
for (size_t i = 0; i < kernel_file_size; i += 16) {
if (memcmp(kernel + i, limine_magic, 16) == 0) {
limine_header = (void *)(kernel + i);
}
}
if (limine_header == NULL) {
panic(true, "limine: Magic number not found");
}
printv("limine: Header found at %p\n", (size_t)limine_header - (size_t)kernel);
// Check if 64 bit CPU
if (!cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx) || !(edx & (1 << 29))) {
panic(true, "limine: This CPU does not support 64-bit mode.");
}
char *kaslr_s = config_get_value(config, 0, "KASLR");
bool kaslr = true;
if (kaslr_s != NULL && strcmp(kaslr_s, "no") == 0)
@ -130,9 +99,11 @@ bool limine_load(char *config, char *cmdline) {
int bits = elf_bits(kernel);
if (bits == -1 || bits == 32) {
panic(true, "limine: Kernel in unrecognised format");
printv("limine: Kernel in unrecognised format");
return false;
}
// ELF loading
uint64_t entry_point = 0;
struct elf_range *ranges;
uint64_t ranges_count;
@ -141,32 +112,45 @@ bool limine_load(char *config, char *cmdline) {
MEMMAP_KERNEL_AND_MODULES, kaslr, false,
&ranges, &ranges_count,
true, &physical_base, &virtual_base)) {
panic(true, "limine: ELF64 load failure");
return false;
}
if (limine_header->entry != 0) {
entry_point = limine_header->entry + slide;
// Load requests
requests_count = 0;
uint64_t common_magic[2] = { LIMINE_COMMON_MAGIC };
for (size_t i = 0; i < ALIGN_DOWN(kernel_file_size, 8); i += 8) {
uint64_t *p = (void *)(uintptr_t)physical_base + i;
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");
}
requests[requests_count++] = p;
}
printv("limine: Physical base: %X\n", physical_base);
printv("limine: Virtual base: %X\n", virtual_base);
printv("limine: Slide: %X\n", slide);
printv("limine: Entry point: %X\n", entry_point);
// Prepare features
features_count = limine_header->features_count;
features_orig = (void *)get_phys_addr(limine_header->features + slide);
features = ext_mem_alloc(features_count * sizeof(uint64_t));
memcpy(features, features_orig, features_count * sizeof(uint64_t));
for (size_t i = 0; i < features_count; i++) {
features_orig[i] = 0;
if (requests_count == 0) {
return false;
}
printv("limine: Features count: %U\n", features_count);
printv("limine: Features list at %X (%p)\n", limine_header->features, features_orig);
// Check if 64 bit CPU
if (!cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx) || !(edx & (1 << 29))) {
panic(true, "limine: This CPU does not support 64-bit mode.");
}
print("limine: Loading kernel `%s`...\n", kernel_path);
printv("limine: Physical base: %X\n", physical_base);
printv("limine: Virtual base: %X\n", virtual_base);
printv("limine: Slide: %X\n", slide);
printv("limine: ELF entry point: %X\n", entry_point);
printv("limine: Requests count: %u\n", requests_count);
// 5 level paging feature & HHDM slide
bool want_5lv;
@ -178,8 +162,8 @@ FEAT_START
level5pg = true;
}
struct feature lv5pg_feat = get_feature(LIMINE_5_LEVEL_PAGING_REQUEST);
want_5lv = lv5pg_feat.found && level5pg;
struct limine_5_level_paging_request *lv5pg_request = get_request(LIMINE_5_LEVEL_PAGING_REQUEST);
want_5lv = lv5pg_request != NULL && level5pg;
direct_map_offset = want_5lv ? 0xff00000000000000 : 0xffff800000000000;
@ -189,14 +173,31 @@ FEAT_START
if (want_5lv) {
void *lv5pg_response = ext_mem_alloc(sizeof(struct limine_5_level_paging_response));
features_orig[lv5pg_feat.index] = reported_addr(lv5pg_response);
lv5pg_request->response = reported_addr(lv5pg_response);
}
FEAT_END
// Entry point feature
FEAT_START
struct limine_entry_point_request *entrypoint_request = get_request(LIMINE_ENTRY_POINT_REQUEST);
if (entrypoint_request == NULL) {
break;
}
entry_point = entrypoint_request->entry;
print("limine: Entry point at %X\n", entry_point);
struct limine_entry_point_response *entrypoint_response =
ext_mem_alloc(sizeof(struct limine_entry_point_response));
entrypoint_request->response = reported_addr(entrypoint_response);
FEAT_END
// Boot info feature
FEAT_START
struct feature boot_info_feat = get_feature(LIMINE_BOOT_INFO_REQUEST);
if (boot_info_feat.found == false) {
struct limine_boot_info_request *boot_info_request = get_request(LIMINE_BOOT_INFO_REQUEST);
if (boot_info_request == NULL) {
break; // next feature
}
@ -205,7 +206,7 @@ FEAT_START
boot_info_response->loader = reported_addr("Limine " LIMINE_VERSION);
features_orig[boot_info_feat.index] = reported_addr(boot_info_response);
boot_info_request->response = reported_addr(boot_info_response);
FEAT_END
// Framebuffer feature
@ -234,17 +235,17 @@ FEAT_END
// Memmap
FEAT_START
struct feature memmap_feat = get_feature(LIMINE_MEMMAP_REQUEST);
struct limine_memmap_request *memmap_request = get_request(LIMINE_MEMMAP_REQUEST);
struct limine_memmap_response *memmap_response;
if (memmap_feat.found == true) {
if (memmap_request != NULL) {
memmap_response = ext_mem_alloc(sizeof(struct limine_memmap_response));
}
size_t mmap_entries;
struct e820_entry_t *mmap = get_memmap(&mmap_entries);
if (memmap_feat.found == false) {
if (memmap_request == NULL) {
break; // next feature
}
@ -281,7 +282,7 @@ FEAT_START
memmap_response->entries_count = mmap_entries;
memmap_response->entries = reported_addr(mmap);
features_orig[memmap_feat.index] = reported_addr(memmap_response);
memmap_request->response = reported_addr(memmap_response);
FEAT_END
// Final wrap-up

View File

@ -3,30 +3,33 @@
#include <limine.h>
#include <e9print.h>
static struct limine_framebuffer_request framebuffer_request = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.flags = LIMINE_FRAMEBUFFER_PREFER_LFB | LIMINE_FRAMEBUFFER_ENFORCE_PREFER,
.height = 0, .width = 0, .bpp = 0
};
static void *features_array[] = {
LIMINE_BOOT_INFO_REQUEST,
&framebuffer_request,
LIMINE_MEMMAP_REQUEST,
LIMINE_5_LEVEL_PAGING_REQUEST,
LIMINE_PMR_REQUEST
};
static void limine_main(void);
__attribute__((used, aligned(16)))
static struct limine_header limine_header = {
.magic = LIMINE_MAGIC,
.entry = limine_main,
.features_count = sizeof(features_array) / sizeof(void *),
.features = features_array
__attribute__((used))
static struct limine_framebuffer_request framebuffer_request = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.flags = LIMINE_FRAMEBUFFER_PREFER_LFB | LIMINE_FRAMEBUFFER_ENFORCE_PREFER,
.response = NULL
};
__attribute__((used))
static struct limine_entry_point_request entry_point_request = {
.id = LIMINE_ENTRY_POINT_REQUEST,
.flags = 0, .response = NULL,
.entry = limine_main
};
__attribute__((used))
static struct limine_boot_info_request boot_info_request = {
.id = LIMINE_BOOT_INFO_REQUEST,
.flags = 0, .response = NULL
};
__attribute__((used))
static struct limine_memmap_request memmap_request = {
.id = LIMINE_MEMMAP_REQUEST,
.flags = 0, .response = NULL
};
static char *get_memmap_type(uint64_t type) {
@ -59,21 +62,21 @@ static void limine_main(void) {
e9_printf("We're alive");
FEAT_START
if (features_array[0] == NULL) {
if (boot_info_request.response == NULL) {
e9_printf("Boot info not passed");
break;
}
struct limine_boot_info_response *boot_info_response = features_array[0];
struct limine_boot_info_response *boot_info_response = boot_info_request.response;
e9_printf("Boot info response:");
e9_printf("Bootloader name: %s", boot_info_response->loader);
FEAT_END
FEAT_START
if (features_array[2] == NULL) {
if (memmap_request.response == NULL) {
e9_printf("Memory map not passed");
break;
}
struct limine_memmap_response *memmap_response = features_array[2];
struct limine_memmap_response *memmap_response = memmap_request.response;
e9_printf("%d memory map entries", memmap_response->entries_count);
for (size_t i = 0; i < memmap_response->entries_count; i++) {
struct limine_memmap_entry *e = &memmap_response->entries[i];