2022-03-12 21:40:49 +03:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <config.h>
|
|
|
|
#include <protos/stivale.h>
|
|
|
|
#include <protos/stivale2.h>
|
|
|
|
#include <lib/elf.h>
|
|
|
|
#include <lib/blib.h>
|
|
|
|
#include <lib/acpi.h>
|
|
|
|
#include <lib/config.h>
|
|
|
|
#include <lib/time.h>
|
|
|
|
#include <lib/print.h>
|
|
|
|
#include <lib/real.h>
|
|
|
|
#include <lib/libc.h>
|
|
|
|
#include <lib/gterm.h>
|
|
|
|
#include <lib/uri.h>
|
|
|
|
#include <sys/smp.h>
|
|
|
|
#include <sys/cpu.h>
|
|
|
|
#include <sys/gdt.h>
|
|
|
|
#include <lib/fb.h>
|
|
|
|
#include <lib/term.h>
|
|
|
|
#include <sys/pic.h>
|
|
|
|
#include <sys/lapic.h>
|
|
|
|
#include <fs/file.h>
|
|
|
|
#include <mm/pmm.h>
|
|
|
|
#include <stivale2.h>
|
|
|
|
#include <pxe/tftp.h>
|
|
|
|
#include <drivers/edid.h>
|
|
|
|
#include <drivers/vga_textmode.h>
|
|
|
|
#include <lib/rand.h>
|
|
|
|
#define LIMINE_NO_POINTERS
|
|
|
|
#include <protos/limine.h>
|
|
|
|
#include <limine.h>
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
#define MAX_REQUESTS 128
|
2022-03-15 23:34:47 +03:00
|
|
|
#define MAX_MEMMAP 256
|
2022-03-13 07:35:29 +03:00
|
|
|
|
|
|
|
static uint64_t physical_base, virtual_base, slide, direct_map_offset;
|
|
|
|
static size_t requests_count;
|
|
|
|
static void *requests[MAX_REQUESTS];
|
2022-03-12 21:40:49 +03:00
|
|
|
|
|
|
|
static uint64_t reported_addr(void *addr) {
|
|
|
|
return (uint64_t)(uintptr_t)addr + direct_map_offset;
|
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
/*
|
2022-03-12 21:40:49 +03:00
|
|
|
static uintptr_t get_phys_addr(uint64_t addr) {
|
|
|
|
return physical_base + (addr - virtual_base);
|
|
|
|
}
|
2022-03-13 07:35:29 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static void *_get_request(uint64_t id[4]) {
|
|
|
|
for (size_t i = 0; i < requests_count; i++) {
|
|
|
|
uint64_t *p = requests[i];
|
2022-03-12 21:40:49 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
if (p[2] != id[2]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (p[3] != id[3]) {
|
|
|
|
continue;
|
2022-03-12 21:40:49 +03:00
|
|
|
}
|
2022-03-13 07:35:29 +03:00
|
|
|
|
|
|
|
return p;
|
2022-03-12 21:40:49 +03:00
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
return NULL;
|
2022-03-12 21:40:49 +03:00
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
#define get_request(REQ) _get_request((uint64_t[4])REQ)
|
|
|
|
|
2022-03-12 21:40:49 +03:00
|
|
|
#define FEAT_START do {
|
|
|
|
#define FEAT_END } while (0);
|
|
|
|
|
|
|
|
bool limine_load(char *config, char *cmdline) {
|
|
|
|
(void)cmdline;
|
|
|
|
|
|
|
|
uint32_t eax, ebx, ecx, edx;
|
|
|
|
|
|
|
|
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
|
|
|
if (kernel_path == NULL)
|
|
|
|
panic(true, "limine: KERNEL_PATH not specified");
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
uint8_t *kernel = freadall(kernel_file, MEMMAP_BOOTLOADER_RECLAIMABLE);
|
|
|
|
|
|
|
|
size_t kernel_file_size = kernel_file->size;
|
|
|
|
|
|
|
|
//struct volume *kernel_volume = kernel_file->vol;
|
|
|
|
|
|
|
|
fclose(kernel_file);
|
|
|
|
|
|
|
|
char *kaslr_s = config_get_value(config, 0, "KASLR");
|
|
|
|
bool kaslr = true;
|
|
|
|
if (kaslr_s != NULL && strcmp(kaslr_s, "no") == 0)
|
|
|
|
kaslr = false;
|
|
|
|
|
|
|
|
int bits = elf_bits(kernel);
|
|
|
|
|
|
|
|
if (bits == -1 || bits == 32) {
|
2022-03-13 07:35:29 +03:00
|
|
|
printv("limine: Kernel in unrecognised format");
|
|
|
|
return false;
|
2022-03-12 21:40:49 +03:00
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
// ELF loading
|
2022-03-12 21:40:49 +03:00
|
|
|
uint64_t entry_point = 0;
|
|
|
|
struct elf_range *ranges;
|
|
|
|
uint64_t ranges_count;
|
|
|
|
|
|
|
|
if (elf64_load(kernel, &entry_point, NULL, &slide,
|
|
|
|
MEMMAP_KERNEL_AND_MODULES, kaslr, false,
|
|
|
|
&ranges, &ranges_count,
|
|
|
|
true, &physical_base, &virtual_base)) {
|
2022-03-13 07:35:29 +03:00
|
|
|
return false;
|
2022-03-12 21:40:49 +03:00
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
// 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;
|
2022-03-12 21:40:49 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
if (p[0] != common_magic[0]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (p[1] != common_magic[1]) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-03-12 21:40:49 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
if (requests_count == MAX_REQUESTS) {
|
|
|
|
panic(true, "limine: Maximum requests exceeded");
|
|
|
|
}
|
2022-03-12 21:40:49 +03:00
|
|
|
|
2022-03-13 23:20:24 +03:00
|
|
|
// Check for a conflict
|
|
|
|
if (_get_request(p) != NULL) {
|
|
|
|
panic(true, "limine: Conflict detected for request ID %X %X", p[2], p[3]);
|
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
requests[requests_count++] = p;
|
|
|
|
}
|
2022-03-12 21:40:49 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
if (requests_count == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-03-12 21:40:49 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
// 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.");
|
2022-03-12 21:40:49 +03:00
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
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);
|
2022-03-12 21:40:49 +03:00
|
|
|
|
|
|
|
// 5 level paging feature & HHDM slide
|
|
|
|
bool want_5lv;
|
|
|
|
FEAT_START
|
|
|
|
// Check if 5-level paging is available
|
|
|
|
bool level5pg = false;
|
|
|
|
if (cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 16))) {
|
|
|
|
printv("limine: CPU has 5-level paging support\n");
|
|
|
|
level5pg = true;
|
|
|
|
}
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
struct limine_5_level_paging_request *lv5pg_request = get_request(LIMINE_5_LEVEL_PAGING_REQUEST);
|
|
|
|
want_5lv = lv5pg_request != NULL && level5pg;
|
2022-03-12 21:40:49 +03:00
|
|
|
|
|
|
|
direct_map_offset = want_5lv ? 0xff00000000000000 : 0xffff800000000000;
|
|
|
|
|
|
|
|
if (kaslr) {
|
|
|
|
direct_map_offset += (rand64() & ~((uint64_t)0x40000000 - 1)) & 0xfffffffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (want_5lv) {
|
|
|
|
void *lv5pg_response = ext_mem_alloc(sizeof(struct limine_5_level_paging_response));
|
2022-03-13 07:35:29 +03:00
|
|
|
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;
|
2022-03-12 21:40:49 +03:00
|
|
|
}
|
2022-03-13 07:35:29 +03:00
|
|
|
|
|
|
|
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);
|
2022-03-12 21:40:49 +03:00
|
|
|
FEAT_END
|
|
|
|
|
|
|
|
// Boot info feature
|
|
|
|
FEAT_START
|
2022-03-13 07:35:29 +03:00
|
|
|
struct limine_boot_info_request *boot_info_request = get_request(LIMINE_BOOT_INFO_REQUEST);
|
|
|
|
if (boot_info_request == NULL) {
|
2022-03-12 21:40:49 +03:00
|
|
|
break; // next feature
|
|
|
|
}
|
|
|
|
|
|
|
|
struct limine_boot_info_response *boot_info_response =
|
|
|
|
ext_mem_alloc(sizeof(struct limine_boot_info_response));
|
|
|
|
|
|
|
|
boot_info_response->loader = reported_addr("Limine " LIMINE_VERSION);
|
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
boot_info_request->response = reported_addr(boot_info_response);
|
2022-03-12 21:40:49 +03:00
|
|
|
FEAT_END
|
|
|
|
|
2022-03-15 04:46:39 +03:00
|
|
|
// Command line
|
|
|
|
FEAT_START
|
|
|
|
struct limine_cmdline_request *cmdline_request = get_request(LIMINE_CMDLINE_REQUEST);
|
|
|
|
if (cmdline_request == NULL) {
|
|
|
|
break; // next feature
|
|
|
|
}
|
|
|
|
|
|
|
|
struct limine_cmdline_response *cmdline_response =
|
|
|
|
ext_mem_alloc(sizeof(struct limine_cmdline_response));
|
|
|
|
|
|
|
|
cmdline_response->cmdline = reported_addr(cmdline);
|
|
|
|
|
|
|
|
cmdline_request->response = reported_addr(cmdline_response);
|
|
|
|
FEAT_END
|
|
|
|
|
2022-03-12 21:40:49 +03:00
|
|
|
// Framebuffer feature
|
|
|
|
FEAT_START
|
|
|
|
term_deinit();
|
|
|
|
|
2022-03-14 14:05:59 +03:00
|
|
|
size_t req_width = 0, req_height = 0, req_bpp = 0;
|
|
|
|
|
|
|
|
char *resolution = config_get_value(config, 0, "RESOLUTION");
|
|
|
|
if (resolution != NULL) {
|
|
|
|
parse_resolution(&req_width, &req_height, &req_bpp, resolution);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct fb_info fb;
|
|
|
|
|
|
|
|
if (!fb_init(&fb, req_width, req_height, req_bpp)) {
|
|
|
|
panic(true, "limine: Could not acquire framebuffer");
|
|
|
|
}
|
|
|
|
|
|
|
|
struct limine_framebuffer_request *framebuffer_request = get_request(LIMINE_FRAMEBUFFER_REQUEST);
|
|
|
|
if (framebuffer_request == NULL) {
|
|
|
|
break; // next feature
|
|
|
|
}
|
|
|
|
|
|
|
|
memmap_alloc_range(fb.framebuffer_addr,
|
|
|
|
(uint64_t)fb.framebuffer_pitch * fb.framebuffer_height,
|
|
|
|
MEMMAP_FRAMEBUFFER, false, false, false, true);
|
|
|
|
|
|
|
|
struct limine_framebuffer_response *framebuffer_response =
|
|
|
|
ext_mem_alloc(sizeof(struct limine_framebuffer_response));
|
|
|
|
|
|
|
|
// For now we only support 1 framebuffer
|
|
|
|
struct limine_framebuffer *fbp = ext_mem_alloc(sizeof(struct limine_framebuffer));
|
|
|
|
framebuffer_response->fbs = reported_addr(fbp);
|
|
|
|
framebuffer_response->fbs_count = 1;
|
|
|
|
|
|
|
|
fbp->memory_model = LIMINE_FRAMEBUFFER_RGB;
|
|
|
|
fbp->address = reported_addr((void *)(uintptr_t)fb.framebuffer_addr);
|
|
|
|
fbp->width = fb.framebuffer_width;
|
|
|
|
fbp->height = fb.framebuffer_height;
|
|
|
|
fbp->bpp = fb.framebuffer_bpp;
|
|
|
|
fbp->pitch = fb.framebuffer_pitch;
|
|
|
|
fbp->red_mask_size = fb.red_mask_size;
|
|
|
|
fbp->red_mask_shift = fb.red_mask_shift;
|
|
|
|
fbp->green_mask_size = fb.green_mask_size;
|
|
|
|
fbp->green_mask_shift = fb.green_mask_shift;
|
|
|
|
fbp->blue_mask_size = fb.blue_mask_size;
|
|
|
|
fbp->blue_mask_shift = fb.blue_mask_shift;
|
|
|
|
|
|
|
|
framebuffer_request->response = reported_addr(framebuffer_response);
|
2022-03-12 21:40:49 +03:00
|
|
|
FEAT_END
|
|
|
|
|
|
|
|
// Wrap-up stuff before memmap close
|
|
|
|
struct gdtr *local_gdt = ext_mem_alloc(sizeof(struct gdtr));
|
|
|
|
local_gdt->limit = gdt.limit;
|
|
|
|
uint64_t local_gdt_base = (uint64_t)gdt.ptr;
|
|
|
|
local_gdt_base += direct_map_offset;
|
|
|
|
local_gdt->ptr = local_gdt_base;
|
|
|
|
#if defined (__i386__)
|
|
|
|
local_gdt->ptr_hi = local_gdt_base >> 32;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void *stack = ext_mem_alloc(8192) + 8192;
|
|
|
|
|
|
|
|
pagemap_t pagemap = {0};
|
|
|
|
pagemap = stivale_build_pagemap(want_5lv, true, ranges, ranges_count, true,
|
|
|
|
physical_base, virtual_base, direct_map_offset);
|
|
|
|
|
|
|
|
// Memmap
|
|
|
|
FEAT_START
|
2022-03-13 07:35:29 +03:00
|
|
|
struct limine_memmap_request *memmap_request = get_request(LIMINE_MEMMAP_REQUEST);
|
2022-03-12 23:41:36 +03:00
|
|
|
struct limine_memmap_response *memmap_response;
|
2022-03-15 23:34:47 +03:00
|
|
|
struct limine_memmap_entry *_memmap;
|
2022-03-12 23:41:36 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
if (memmap_request != NULL) {
|
2022-03-12 23:41:36 +03:00
|
|
|
memmap_response = ext_mem_alloc(sizeof(struct limine_memmap_response));
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap = ext_mem_alloc(sizeof(struct limine_memmap_entry) * MAX_MEMMAP);
|
2022-03-12 23:41:36 +03:00
|
|
|
}
|
|
|
|
|
2022-03-12 21:40:49 +03:00
|
|
|
size_t mmap_entries;
|
|
|
|
struct e820_entry_t *mmap = get_memmap(&mmap_entries);
|
2022-03-12 23:41:36 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
if (memmap_request == NULL) {
|
2022-03-12 23:41:36 +03:00
|
|
|
break; // next feature
|
|
|
|
}
|
|
|
|
|
2022-03-15 23:34:47 +03:00
|
|
|
if (mmap_entries > MAX_MEMMAP) {
|
|
|
|
panic(false, "limine: Too many memmap entries");
|
|
|
|
}
|
|
|
|
|
2022-03-12 23:41:36 +03:00
|
|
|
for (size_t i = 0; i < mmap_entries; i++) {
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].base = mmap[i].base;
|
|
|
|
_memmap[i].length = mmap[i].length;
|
|
|
|
|
2022-03-12 23:41:36 +03:00
|
|
|
switch (mmap[i].type) {
|
|
|
|
case MEMMAP_USABLE:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_USABLE;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
case MEMMAP_ACPI_RECLAIMABLE:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_ACPI_RECLAIMABLE;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
case MEMMAP_ACPI_NVS:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_ACPI_NVS;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
case MEMMAP_BAD_MEMORY:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_BAD_MEMORY;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
case MEMMAP_BOOTLOADER_RECLAIMABLE:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
case MEMMAP_KERNEL_AND_MODULES:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_KERNEL_AND_MODULES;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
case MEMMAP_FRAMEBUFFER:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_FRAMEBUFFER;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case MEMMAP_RESERVED:
|
2022-03-15 23:34:47 +03:00
|
|
|
_memmap[i].type = LIMINE_MEMMAP_RESERVED;
|
2022-03-12 23:41:36 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memmap_response->entries_count = mmap_entries;
|
2022-03-15 23:34:47 +03:00
|
|
|
memmap_response->entries = reported_addr(_memmap);
|
2022-03-12 23:41:36 +03:00
|
|
|
|
2022-03-13 07:35:29 +03:00
|
|
|
memmap_request->response = reported_addr(memmap_response);
|
2022-03-12 21:40:49 +03:00
|
|
|
FEAT_END
|
|
|
|
|
|
|
|
// Final wrap-up
|
|
|
|
#if uefi == 1
|
|
|
|
efi_exit_boot_services();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
stivale_spinup(64, want_5lv, &pagemap, entry_point, 0,
|
|
|
|
reported_addr(stack), true, (uintptr_t)local_gdt);
|
|
|
|
|
|
|
|
__builtin_unreachable();
|
|
|
|
}
|