diff --git a/src/bootsect/gdt.inc b/src/bootsect/gdt.inc index 15045d27..d4d6b6a4 100644 --- a/src/bootsect/gdt.inc +++ b/src/bootsect/gdt.inc @@ -56,4 +56,20 @@ db 10010010b ; Access db 11001111b ; Granularity db 0x00 ; Base (high 8 bits) +; 64 bit code +dw 0x0000 ; Limit +dw 0x0000 ; Base (low 16 bits) +db 0x00 ; Base (mid 8 bits) +db 10011010b ; Access +db 00100000b ; Granularity +db 0x00 ; Base (high 8 bits) + +; 64 bit data +dw 0x0000 ; Limit +dw 0x0000 ; Base (low 16 bits) +db 0x00 ; Base (mid 8 bits) +db 10010010b ; Access +db 00000000b ; Granularity +db 0x00 ; Base (high 8 bits) + .GDTEnd: diff --git a/src/lib/elf.c b/src/lib/elf.c index dcfb7974..1cbcbb5c 100644 --- a/src/lib/elf.c +++ b/src/lib/elf.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -46,9 +47,11 @@ struct elf_phdr { uint64_t p_align; }; -int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count); +#define FIXED_HIGHER_HALF_OFFSET ((uint64_t)0xffffffff80000000) int elf_load(struct echfs_file_handle *fd) { + bool elf_higher_half = false; + struct elf_hdr hdr; echfs_read(fd, &hdr, 0, sizeof(struct elf_hdr)); @@ -75,6 +78,12 @@ int elf_load(struct echfs_file_handle *fd) { if (phdr.p_type != PT_LOAD) continue; + if (phdr.p_vaddr & (1ull << 63)) { + print("elf: This is a higher half kernel!\n"); + elf_higher_half = true; + phdr.p_vaddr -= FIXED_HIGHER_HALF_OFFSET; + } + echfs_read(fd, (void *)(uint32_t)phdr.p_vaddr, phdr.p_offset, phdr.p_filesz); @@ -86,10 +95,63 @@ int elf_load(struct echfs_file_handle *fd) { } } + volatile struct { + uint64_t pml4[512]; + uint64_t pml3_lo[512]; + uint64_t pml3_hi[512]; + uint64_t pml2_0gb[512]; + uint64_t pml2_1gb[512]; + uint64_t pml2_2gb[512]; + uint64_t pml2_3gb[512]; + } *pagemap = (void *)0x10000; + + // first, zero out the pagemap + for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++) + *p = 0; + + pagemap->pml4[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03; + pagemap->pml4[0] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03; + pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03; + pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03; + pagemap->pml3_lo[0] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03; + pagemap->pml3_lo[1] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03; + pagemap->pml3_lo[2] = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03; + pagemap->pml3_lo[3] = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03; + + // populate the page directories + for (size_t i = 0; i < 512 * 4; i++) + (&pagemap->pml2_0gb[0])[i] = (i * 0x1000) | 0x03 | (1 << 7); + + uint32_t entry_point = elf_higher_half + ? (uint32_t)(hdr.entry - FIXED_HIGHER_HALF_OFFSET) + : (uint32_t)hdr.entry; + asm volatile ( - "jmp %0\n\t" + "cli\n\t" + "mov cr3, eax\n\t" + "mov eax, cr4\n\t" + "or eax, 1 << 5 | 1 << 7\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" + "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" + "jmp rbx\n\t" + ".code32\n\t" : - : "r" ((uint32_t)hdr.entry) - : "memory" + : "a" (pagemap), "b" (entry_point) ); + + for (;;); } diff --git a/test/linker.ld b/test/linker.ld index 92cdcf66..a1f8fbd3 100644 --- a/test/linker.ld +++ b/test/linker.ld @@ -1,7 +1,7 @@ ENTRY(_start) SECTIONS { - . = 0x100000; + . = 0xffffffff80100000; .text : { *(.text*) diff --git a/test/test.asm b/test/test.asm index f378f478..68ce5412 100644 --- a/test/test.asm +++ b/test/test.asm @@ -6,9 +6,8 @@ section .text ; Entry point -bits 32 global _start _start: - mov eax, 0xdeadbeef + mov rax, 0xcafebabedeadbeef jmp $