limine: Rework request-response system
This commit is contained in:
parent
e33a76bd99
commit
f9c9ec84d5
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue