Add 5-level paging support

This commit is contained in:
mintsuki 2020-05-03 22:37:24 +02:00
parent cffdc2f0cf
commit 00e313d0d7
2 changed files with 92 additions and 35 deletions

View File

@ -56,6 +56,8 @@ IF flag, VM flag, and direction flag are cleared on entry. Other flags undefined
PG is enabled (`cr0`), PE is enabled (`cr0`), PAE is enabled (`cr4`),
LME is enabled (`EFER`).
If stivale header flag bit 1 is set, then, if available, 5-level paging is enabled
(LA57 bit in `cr4`).
The A20 gate is enabled.
@ -98,7 +100,10 @@ struct stivale_header {
// when the kernel is loaded.
uint16_t flags; // Flags
// bit 0 0 = text mode, 1 = graphics mode
// bit 0 0 = text mode, 1 = graphics framebuffer mode
// bit 1 0 = 4-level paging, 1 = use 5-level paging (if
available)
Ignored if booting a 32-bit kernel.
// All other bits undefined.
uint16_t framebuffer_width; // These 3 values are parsed if a graphics mode

View File

@ -1,5 +1,6 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <protos/stivale.h>
#include <lib/elf.h>
#include <lib/blib.h>
@ -52,18 +53,24 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
int ret;
bool level5pg = false;
switch (bits) {
case 64:
case 64: {
// Check if 64 bit CPU
{
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.");
}
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;
}
ret = elf64_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
break;
}
case 32:
ret = elf32_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
break;
@ -155,7 +162,7 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
stivale_struct.framebuffer_height = stivale_hdr.framebuffer_height;
stivale_struct.framebuffer_bpp = stivale_hdr.framebuffer_bpp;
if ((stivale_hdr.flags & 1) == 1) {
if (stivale_hdr.flags & (1 << 0)) {
init_vbe(&stivale_struct.framebuffer_addr,
&stivale_struct.framebuffer_pitch,
&stivale_struct.framebuffer_width,
@ -166,34 +173,79 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
}
if (bits == 64) {
struct pagemap {
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];
};
struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
void *pagemap_ptr;
if (level5pg && (stivale_hdr.flags & (1 << 1))) {
// Enable CR4.LA57
asm volatile (
"mov eax, cr4\n\t"
"bts eax, 12\n\t"
"mov cr4, eax\n\t"
);
// first, zero out the pagemap
for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
*p = 0;
struct pagemap {
uint64_t pml5[512];
uint64_t pml4_lo[512];
uint64_t pml4_hi[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];
};
struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
pagemap_ptr = (void *)pagemap;
pagemap->pml4[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03;
pagemap->pml4[256] = (uint64_t)(size_t)pagemap->pml3_lo | 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;
// zero out the pagemap
for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
*p = 0;
// populate the page directories
for (size_t i = 0; i < 512 * 4; i++)
(&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
pagemap->pml5[511] = (uint64_t)(size_t)pagemap->pml4_hi | 0x03;
pagemap->pml5[0] = (uint64_t)(size_t)pagemap->pml4_lo | 0x03;
pagemap->pml4_hi[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03;
pagemap->pml4_hi[256] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
pagemap->pml4_lo[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 * 0x200000) | 0x03 | (1 << 7);
} else {
struct pagemap {
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];
};
struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
pagemap_ptr = (void *)pagemap;
// 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[256] = (uint64_t)(size_t)pagemap->pml3_lo | 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 * 0x200000) | 0x03 | (1 << 7);
}
asm volatile (
"cli\n\t"
@ -221,7 +273,7 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
"call [rbx]\n\t"
".code32\n\t"
:
: "a" (pagemap), "b" (&entry_point),
: "a" (pagemap_ptr), "b" (&entry_point),
"D" (&stivale_struct), "S" (&stivale_hdr.stack)
);
} else if (bits == 32) {