rulimine/stage2/protos/stivale.c

381 lines
12 KiB
C
Raw Normal View History

#include <stdint.h>
#include <stddef.h>
2020-05-03 23:37:24 +03:00
#include <stdbool.h>
#include <protos/stivale.h>
#include <lib/elf.h>
2020-03-26 02:46:35 +03:00
#include <lib/blib.h>
2020-03-26 03:37:56 +03:00
#include <lib/acpi.h>
2020-03-30 23:27:15 +03:00
#include <lib/config.h>
2020-04-30 22:19:12 +03:00
#include <lib/time.h>
2020-05-10 01:38:27 +03:00
#include <lib/print.h>
2020-06-01 11:20:34 +03:00
#include <lib/rand.h>
#include <lib/real.h>
2020-03-26 05:13:19 +03:00
#include <drivers/vbe.h>
2020-09-02 10:55:56 +03:00
#include <lib/term.h>
2020-09-18 21:02:10 +03:00
#include <sys/pic.h>
2020-04-14 06:20:55 +03:00
#include <fs/file.h>
2020-09-21 13:15:55 +03:00
#include <mm/vmm.h>
2020-09-20 13:03:44 +03:00
#include <mm/pmm.h>
#include <stivale/stivale.h>
2020-03-26 02:46:35 +03:00
#define KASLR_SLIDE_BITMASK 0x03FFFF000u
2020-03-26 06:06:23 +03:00
struct stivale_struct stivale_struct = {0};
2020-05-06 17:38:45 +03:00
void stivale_load(char *cmdline, int boot_drive) {
stivale_struct.flags |= (1 << 0); // set bit 0 since we are BIOS and not UEFI
2020-05-15 06:47:38 +03:00
2020-05-06 17:38:45 +03:00
int kernel_drive; {
char buf[32];
if (!config_get_value(buf, 0, 32, "KERNEL_DRIVE")) {
kernel_drive = boot_drive;
} else {
kernel_drive = (int)strtoui(buf);
}
}
int kernel_part; {
char buf[32];
if (!config_get_value(buf, 0, 32, "KERNEL_PARTITION")) {
panic("KERNEL_PARTITION not specified");
} else {
kernel_part = (int)strtoui(buf);
}
}
2020-09-20 13:03:44 +03:00
char *kernel_path = conv_mem_alloc(128);
2020-05-06 17:38:45 +03:00
if (!config_get_value(kernel_path, 0, 128, "KERNEL_PATH")) {
panic("KERNEL_PATH not specified");
}
2020-09-20 13:03:44 +03:00
struct file_handle *fd = conv_mem_alloc(sizeof(struct file_handle));
2020-05-06 17:38:45 +03:00
if (fopen(fd, kernel_drive, kernel_part, kernel_path)) {
panic("Could not open kernel file");
}
2020-03-26 02:46:35 +03:00
struct stivale_header stivale_hdr;
2020-04-18 19:01:29 +03:00
int bits = elf_bits(fd);
int ret;
uint64_t slide = 0;
2020-05-03 23:37:24 +03:00
bool level5pg = false;
2020-04-18 19:01:29 +03:00
switch (bits) {
2020-05-03 23:37:24 +03:00
case 64: {
2020-04-30 14:03:04 +03:00
// Check if 64 bit CPU
2020-05-03 23:37:24 +03:00
uint32_t eax, ebx, ecx, edx;
cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx);
if (!(edx & (1 << 29))) {
panic("stivale: This CPU does not support 64-bit mode.");
}
// Check if 5-level paging is available
cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx);
if (ecx & (1 << 16)) {
print("stivale: CPU has 5-level paging support\n");
level5pg = true;
2020-04-30 14:03:04 +03:00
}
ret = elf64_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header), slide);
if (!ret && ((stivale_hdr.flags >> 2) & 1)) {
// KASLR is enabled, set the slide
2020-06-01 11:20:34 +03:00
slide = rand64() & KASLR_SLIDE_BITMASK;
// Re-read the .stivalehdr with slid relocations
ret = elf64_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header), slide);
}
2020-04-18 19:01:29 +03:00
break;
2020-05-03 23:37:24 +03:00
}
2020-04-18 19:01:29 +03:00
case 32:
ret = elf32_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
break;
2020-04-29 17:53:05 +03:00
default:
2020-04-30 14:03:04 +03:00
panic("stivale: Not 32 nor 64 bit x86 ELF file.");
2020-04-18 19:01:29 +03:00
}
2020-04-29 17:53:05 +03:00
print("stivale: %u-bit ELF file detected\n", bits);
2020-03-26 02:46:35 +03:00
switch (ret) {
case 1:
2020-05-10 01:48:58 +03:00
panic("stivale: File is not a valid ELF.");
2020-03-26 02:46:35 +03:00
case 2:
2020-05-10 01:48:58 +03:00
panic("stivale: Section .stivalehdr not found.");
2020-03-26 02:46:35 +03:00
case 3:
2020-05-10 01:48:58 +03:00
panic("stivale: Section .stivalehdr exceeds the size of the struct.");
case 4:
panic("stivale: Section .stivalehdr is smaller than size of the struct.");
2020-03-26 02:46:35 +03:00
}
print("stivale: Requested stack at %X\n", stivale_hdr.stack);
2020-04-18 19:01:29 +03:00
uint64_t entry_point = 0;
uint64_t top_used_addr = 0;
2020-04-18 19:01:29 +03:00
switch (bits) {
case 64:
2020-08-11 19:00:51 +03:00
elf64_load(fd, &entry_point, &top_used_addr, slide, 10);
2020-04-18 19:01:29 +03:00
break;
case 32:
2020-08-11 19:00:51 +03:00
elf32_load(fd, (uint32_t *)&entry_point, (uint32_t *)&top_used_addr, 10);
2020-04-18 19:01:29 +03:00
break;
}
2020-03-30 23:27:15 +03:00
if (stivale_hdr.entry_point != 0)
entry_point = stivale_hdr.entry_point;
print("stivale: Kernel slide: %X\n", slide);
2020-03-30 23:27:15 +03:00
print("stivale: Top used address in ELF: %X\n", top_used_addr);
2020-03-30 23:27:15 +03:00
stivale_struct.module_count = 0;
uint64_t *prev_mod_ptr = &stivale_struct.modules;
for (int i = 0; ; i++) {
char module_file[64];
if (!config_get_value(module_file, i, 64, "MODULE_PATH"))
break;
stivale_struct.module_count++;
2020-09-20 13:03:44 +03:00
struct stivale_module *m = conv_mem_alloc(sizeof(struct stivale_module));
2020-03-30 23:27:15 +03:00
2020-06-05 18:51:33 +03:00
if (!config_get_value(m->string, i, 128, "MODULE_STRING")) {
m->string[0] = '\0';
}
2020-03-30 23:27:15 +03:00
int part; {
char buf[32];
2020-06-05 18:51:33 +03:00
if (!config_get_value(buf, i, 32, "MODULE_PARTITION")) {
part = kernel_part;
} else {
part = (int)strtoui(buf);
}
2020-03-30 23:27:15 +03:00
}
2020-04-14 06:20:55 +03:00
struct file_handle f;
if (fopen(&f, fd->disk, part, module_file)) {
panic("Requested module with path \"%s\" not found!\n", module_file);
}
2020-03-30 23:27:15 +03:00
void *module_addr = (void *)(((uint32_t)top_used_addr & 0xfff) ?
((uint32_t)top_used_addr & ~((uint32_t)0xfff)) + 0x1000 :
(uint32_t)top_used_addr);
2020-08-11 19:00:51 +03:00
memmap_alloc_range((size_t)module_addr, f.size, 10);
2020-04-14 06:20:55 +03:00
fread(&f, module_addr, 0, f.size);
2020-03-30 23:27:15 +03:00
m->begin = (uint64_t)(size_t)module_addr;
2020-04-14 06:20:55 +03:00
m->end = m->begin + f.size;
2020-03-30 23:27:15 +03:00
m->next = 0;
top_used_addr = (uint64_t)(size_t)m->end;
*prev_mod_ptr = (uint64_t)(size_t)m;
prev_mod_ptr = &m->next;
print("stivale: Requested module %u:\n", i);
print(" Path: %s\n", module_file);
print(" String: %s\n", m->string);
print(" Begin: %X\n", m->begin);
print(" End: %X\n", m->end);
}
stivale_struct.rsdp = (uint64_t)(size_t)acpi_get_rsdp();
2020-03-26 03:37:56 +03:00
stivale_struct.cmdline = (uint64_t)(size_t)cmdline;
2020-04-30 22:19:12 +03:00
stivale_struct.epoch = time();
print("stivale: Current epoch: %U\n", stivale_struct.epoch);
2020-04-30 22:19:12 +03:00
2020-03-26 05:13:19 +03:00
stivale_struct.framebuffer_width = stivale_hdr.framebuffer_width;
stivale_struct.framebuffer_height = stivale_hdr.framebuffer_height;
2020-03-27 07:58:37 +03:00
stivale_struct.framebuffer_bpp = stivale_hdr.framebuffer_bpp;
2020-03-26 05:13:19 +03:00
2020-09-02 10:55:56 +03:00
term_deinit();
2020-05-03 23:37:24 +03:00
if (stivale_hdr.flags & (1 << 0)) {
2020-09-02 08:16:05 +03:00
uint32_t *fb32;
init_vbe(&fb32,
2020-03-26 05:13:19 +03:00
&stivale_struct.framebuffer_pitch,
&stivale_struct.framebuffer_width,
2020-03-27 07:58:37 +03:00
&stivale_struct.framebuffer_height,
&stivale_struct.framebuffer_bpp);
2020-09-02 08:16:05 +03:00
stivale_struct.framebuffer_addr = (uint64_t)(size_t)fb32;
2020-03-26 05:13:19 +03:00
}
2020-06-05 18:51:33 +03:00
size_t memmap_entries;
struct e820_entry_t *memmap = get_memmap(&memmap_entries);
2020-09-18 15:39:29 +03:00
bool want_5lv = level5pg && (stivale_hdr.flags & (1 << 1));
pagemap_t pagemap = stivale_build_pagemap(want_5lv, memmap, memmap_entries);
memmap = get_memmap(&memmap_entries);
stivale_struct.memory_map_entries = (uint64_t)memmap_entries;
stivale_struct.memory_map_addr = (uint64_t)(size_t)memmap;
2020-09-18 15:39:29 +03:00
stivale_spinup(bits, want_5lv, pagemap,
entry_point, &stivale_struct, stivale_hdr.stack);
2020-09-02 10:55:56 +03:00
}
2020-09-18 15:39:29 +03:00
pagemap_t stivale_build_pagemap(bool level5pg, struct e820_entry_t *memmap,
size_t memmap_entries) {
pagemap_t pagemap = new_pagemap(level5pg ? 5 : 4);
uint64_t higher_half_base = level5pg ? 0xff00000000000000 : 0xffff800000000000;
// Map 0 to 2GiB at 0xffffffff80000000
for (uint64_t i = 0; i < 0x80000000; i += PAGE_SIZE) {
map_page(pagemap, 0xffffffff80000000 + i, i, 0x03);
}
// Map 0 to 4GiB at higher half base and 0
for (uint64_t i = 0; i < 0x100000000; i += PAGE_SIZE) {
map_page(pagemap, i, i, 0x03);
map_page(pagemap, higher_half_base + i, i, 0x03);
}
// Map any other region of memory from the memmap
for (size_t i = 0; i < memmap_entries; i++) {
uint64_t base = memmap[i].base;
uint64_t length = memmap[i].length;
uint64_t top = base + length;
uint64_t aligned_base = ALIGN_DOWN(base, PAGE_SIZE);
uint64_t aligned_top = ALIGN_UP(top, PAGE_SIZE);
uint64_t aligned_length = aligned_top - aligned_base;
for (uint64_t i = 0; i < aligned_length; i += PAGE_SIZE) {
uint64_t page = aligned_base + i;
map_page(pagemap, page, page, 0x03);
map_page(pagemap, higher_half_base + page, page, 0x03);
}
}
return pagemap;
}
__attribute__((noreturn)) void stivale_spinup(
int bits, bool level5pg, pagemap_t pagemap,
uint64_t entry_point, void *stivale_struct, uint64_t stack) {
if (bits == 64) {
// If we're going 64, we might as well call this BIOS interrupt
// to tell the BIOS that we are entering Long Mode, since it is in
// the specification.
struct rm_regs r = {0};
r.eax = 0xec00;
r.ebx = 0x02; // Long mode only
rm_int(0x15, &r, &r);
}
2020-09-02 03:32:04 +03:00
pic_mask_all();
pic_flush();
2020-04-18 19:01:29 +03:00
if (bits == 64) {
2020-09-02 10:55:56 +03:00
if (level5pg) {
2020-05-03 23:37:24 +03:00
// Enable CR4.LA57
asm volatile (
2020-05-03 23:37:24 +03:00
"mov eax, cr4\n\t"
"bts eax, 12\n\t"
"mov cr4, eax\n\t" ::: "eax", "memory"
2020-05-03 23:37:24 +03:00
);
}
2020-05-03 23:37:24 +03:00
asm volatile (
2020-04-18 19:01:29 +03:00
"cli\n\t"
"cld\n\t"
"mov cr3, eax\n\t"
"mov eax, cr4\n\t"
"or eax, 1 << 5\n\t"
"mov cr4, eax\n\t"
"mov ecx, 0xc0000080\n\t"
"rdmsr\n\t"
"or eax, 1 << 8\n\t"
"wrmsr\n\t"
"mov eax, cr0\n\t"
"or eax, 1 << 31\n\t"
"mov cr0, eax\n\t"
"jmp 0x28:1f\n\t"
2020-04-18 19:01:29 +03:00
"1: .code64\n\t"
"mov ax, 0x30\n\t"
"mov ds, ax\n\t"
"mov es, ax\n\t"
"mov fs, ax\n\t"
"mov gs, ax\n\t"
"mov ss, ax\n\t"
// Since we don't really know what is now present in the upper
// 32 bits of the 64 bit registers, clear up the upper bits
// of the registers we use to store stack pointer and instruction
// pointer
"mov esi, esi\n\t"
"mov ebx, ebx\n\t"
"mov edi, edi\n\t"
// Let's pretend we push a return address
"mov rsi, qword ptr [rsi]\n\t"
"test rsi, rsi\n\t"
"jz 1f\n\t"
"sub rsi, 8\n\t"
"mov qword ptr [rsi], 0\n\t"
"1:\n\t"
"push 0x30\n\t"
"push rsi\n\t"
"pushfq\n\t"
"push 0x28\n\t"
"push [rbx]\n\t"
"xor rax, rax\n\t"
"xor rbx, rbx\n\t"
"xor rcx, rcx\n\t"
"xor rdx, rdx\n\t"
"xor rsi, rsi\n\t"
"xor rbp, rbp\n\t"
"xor r8, r8\n\t"
"xor r9, r9\n\t"
"xor r10, r10\n\t"
"xor r11, r11\n\t"
"xor r12, r12\n\t"
"xor r13, r13\n\t"
"xor r14, r14\n\t"
"xor r15, r15\n\t"
"iretq\n\t"
".code32\n\t"
:
: "a" (pagemap.top_level), "b" (&entry_point),
2020-09-02 10:55:56 +03:00
"D" (stivale_struct), "S" (&stack)
: "memory"
2020-04-18 19:01:29 +03:00
);
} else if (bits == 32) {
asm volatile (
2020-04-18 19:01:29 +03:00
"cli\n\t"
"cld\n\t"
2020-09-18 00:22:53 +03:00
"mov esp, dword ptr [esi]\n\t"
"push edi\n\t"
"push 0\n\t"
"pushfd\n\t"
"push 0x18\n\t"
"push [ebx]\n\t"
"xor eax, eax\n\t"
"xor ebx, ebx\n\t"
"xor ecx, ecx\n\t"
"xor edx, edx\n\t"
"xor esi, esi\n\t"
"xor edi, edi\n\t"
"xor ebp, ebp\n\t"
"iret\n\t"
:
: "b"(&entry_point), "D"(stivale_struct), "S"(&stack)
: "memory"
);
2020-04-18 19:01:29 +03:00
}
2020-09-02 10:55:56 +03:00
for (;;);
}