Kernel: Replace Paging{.h,.cpp} with better MMU{.h,.cpp}
This commit is contained in:
parent
67308c36ad
commit
8fd51fb47d
|
@ -3,7 +3,7 @@
|
|||
#include <kernel/IDT.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/kprint.h>
|
||||
#include <kernel/Paging.h>
|
||||
#include <kernel/MMU.h>
|
||||
#include <kernel/Panic.h>
|
||||
#include <kernel/PIC.h>
|
||||
#include <kernel/Serial.h>
|
||||
|
@ -211,7 +211,7 @@ namespace APIC
|
|||
static void ParseMADT(RSDPDescriptor* rsdp)
|
||||
{
|
||||
RSDT* root = (RSDT*)(rsdp->revision == 2 ? ((RSDPDescriptor20*)rsdp)->xsdt_address : rsdp->rsdt_address);
|
||||
Paging::MapPage((uint32_t)root);
|
||||
MMU::Get().AllocatePage((uint32_t)root);
|
||||
uint32_t sdt_entry_count = (root->header.length - sizeof(root->header)) / (rsdp->revision == 2 ? 8 : 4);
|
||||
|
||||
for (uint32_t i = 0; i < sdt_entry_count; i++)
|
||||
|
@ -366,8 +366,8 @@ namespace APIC
|
|||
if (s_local_apic == 0 || s_io_apic == 0)
|
||||
return false;
|
||||
|
||||
Paging::MapPage(s_io_apic);
|
||||
Paging::MapPage(s_local_apic);
|
||||
MMU::Get().AllocatePage(s_io_apic);
|
||||
MMU::Get().AllocatePage(s_local_apic);
|
||||
|
||||
// Enable Local APIC
|
||||
SetMSR(IA32_APIC_BASE, (s_local_apic & 0xFFFFF000) | IA32_APIC_BASE_ENABLE, 0);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
#include <BAN/Errors.h>
|
||||
#include <kernel/MMU.h>
|
||||
#include <kernel/kmalloc.h>
|
||||
#include <kernel/Serial.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define PRESENT (1 << 0)
|
||||
#define READ_WRITE (1 << 1)
|
||||
|
||||
// bits 31-12 set
|
||||
#define PAGE_MASK 0xfffff000
|
||||
#define PAGE_SIZE 0x00001000
|
||||
|
||||
static MMU* s_instance = nullptr;
|
||||
|
||||
void MMU::Intialize()
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
s_instance = new MMU();
|
||||
}
|
||||
|
||||
MMU& MMU::Get()
|
||||
{
|
||||
ASSERT(s_instance);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
static uint64_t* allocate_page_aligned_page()
|
||||
{
|
||||
uint64_t* page_directory = (uint64_t*)kmalloc(PAGE_SIZE, PAGE_SIZE);
|
||||
ASSERT(page_directory);
|
||||
ASSERT(((uintptr_t)page_directory % PAGE_SIZE) == 0);
|
||||
memset(page_directory, 0, PAGE_SIZE);
|
||||
return page_directory;
|
||||
}
|
||||
|
||||
MMU::MMU()
|
||||
{
|
||||
m_page_descriptor_pointer_table = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
|
||||
ASSERT(m_page_descriptor_pointer_table);
|
||||
ASSERT(((uintptr_t)m_page_descriptor_pointer_table % 32) == 0);
|
||||
|
||||
// create and zero out all page directories
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
uint64_t* page_directory = allocate_page_aligned_page();
|
||||
m_page_descriptor_pointer_table[i] = (uint64_t)page_directory | PRESENT;
|
||||
}
|
||||
|
||||
// create and identity map first 4 MiB
|
||||
uint64_t* page_directory1 = (uint64_t*)(m_page_descriptor_pointer_table[0] & PAGE_MASK);
|
||||
for (uint64_t i = 0; i < 2; i++)
|
||||
{
|
||||
uint64_t* page_table = allocate_page_aligned_page();
|
||||
for (uint64_t j = 0; j < 512; j++)
|
||||
page_table[j] = (i << 21) | (j << 12) | READ_WRITE | PRESENT;
|
||||
|
||||
page_directory1[i] = (uint64_t)page_table | READ_WRITE | PRESENT;
|
||||
}
|
||||
|
||||
// dont map first page (0 -> 4 KiB) so that nullptr dereference
|
||||
// causes page fault :)
|
||||
uint64_t* page_table1 = (uint64_t*)page_directory1[0];
|
||||
page_table1[0] = 0;
|
||||
|
||||
// reload this new pdpt
|
||||
asm volatile("movl %0, %%cr3" :: "r"(m_page_descriptor_pointer_table));
|
||||
}
|
||||
|
||||
void MMU::AllocatePage(uintptr_t address)
|
||||
{
|
||||
uint32_t pdpte = (address & 0xC0000000) >> 30;
|
||||
uint32_t pde = (address & 0x3FE00000) >> 21;
|
||||
uint32_t pte = (address & 0x001FF000) >> 12;
|
||||
|
||||
ASSERT(pdpte < 4);
|
||||
|
||||
uint64_t* page_directory = (uint64_t*)(m_page_descriptor_pointer_table[pdpte] & PAGE_MASK);
|
||||
if (!(page_directory[pde] & PRESENT))
|
||||
{
|
||||
uint64_t* page_table = allocate_page_aligned_page();
|
||||
page_directory[pde] = (uint64_t)page_table | READ_WRITE | PRESENT;
|
||||
}
|
||||
|
||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||
page_table[pte] = (address & PAGE_MASK) | READ_WRITE | PRESENT;
|
||||
|
||||
asm volatile("invlpg (%0)" :: "r"(address & PAGE_MASK) : "memory");
|
||||
}
|
||||
|
||||
void MMU::AllocateRange(uintptr_t address, ptrdiff_t size)
|
||||
{
|
||||
uintptr_t s_page = address & PAGE_MASK;
|
||||
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
|
||||
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
||||
AllocatePage(page);
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
#include <kernel/CPUID.h>
|
||||
#include <kernel/Paging.h>
|
||||
#include <kernel/Panic.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define PRESENT (1 << 0)
|
||||
#define READ_WRITE (1 << 1)
|
||||
#define PAGE_SIZE (1 << 7)
|
||||
|
||||
namespace Paging
|
||||
{
|
||||
|
||||
static uint64_t s_page_directory_pointer_table[4] __attribute__((aligned(0x20)));
|
||||
static uint64_t s_page_directory[4 * 512] __attribute__((aligned(4096)));
|
||||
|
||||
static bool HasRequirements()
|
||||
{
|
||||
uint32_t ecx, edx;
|
||||
CPUID::GetFeatures(ecx, edx);
|
||||
if (!(edx & CPUID::Features::EDX_PAE))
|
||||
{
|
||||
derrorln("PAE not supported, halting");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
if (!HasRequirements())
|
||||
asm volatile("hlt");
|
||||
|
||||
// Disable paging
|
||||
asm volatile(
|
||||
"movl %cr0, %ebx;"
|
||||
"andl $0x7fffffff, %ebx;"
|
||||
"movl %ebx, %cr0;"
|
||||
);
|
||||
|
||||
// Identity map first 2 (2 MiB) pages
|
||||
memset(s_page_directory, 0x00, sizeof(s_page_directory));
|
||||
s_page_directory[0] = (0x00 << 21) | PAGE_SIZE | READ_WRITE | PRESENT;
|
||||
s_page_directory[1] = (0x01 << 21) | PAGE_SIZE | READ_WRITE | PRESENT;
|
||||
|
||||
// Initialize PDPTEs
|
||||
for (int i = 0; i < 4; i++)
|
||||
s_page_directory_pointer_table[i] = (uint64_t)(&s_page_directory[512 * i]) | PRESENT;
|
||||
|
||||
asm volatile(
|
||||
// Enable PAE
|
||||
"movl %%cr4, %%eax;"
|
||||
"orl $0x20, %%eax;"
|
||||
"movl %%eax, %%cr4;"
|
||||
|
||||
// Load PDPT address to cr3
|
||||
"movl %0, %%cr3;"
|
||||
|
||||
// Enable paging
|
||||
"movl %%cr0, %%eax;"
|
||||
"orl $0x80000000, %%eax;"
|
||||
"movl %%eax, %%cr0;"
|
||||
|
||||
:: "r" (s_page_directory_pointer_table)
|
||||
: "eax"
|
||||
);
|
||||
}
|
||||
|
||||
void MapPage(uintptr_t address)
|
||||
{
|
||||
if (address != ((address >> 21) << 21))
|
||||
{
|
||||
dprintln("aligning 0x{8H} to 2 MiB boundary -> 0x{8H}", address, (address >> 21) << 21);
|
||||
address = (address >> 21) << 21;
|
||||
}
|
||||
|
||||
uint32_t pde = address >> 21;
|
||||
|
||||
dprintln("mapping pde {} (0x{8H} - 0x{8H})", pde, pde << 21, ((pde + 1) << 21) - 1);
|
||||
|
||||
if (s_page_directory[pde] & PRESENT)
|
||||
{
|
||||
dprintln("page already mapped");
|
||||
return;
|
||||
}
|
||||
|
||||
// Map and flush the given address
|
||||
s_page_directory[pde] = address | PAGE_SIZE | READ_WRITE | PRESENT;
|
||||
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
|
||||
}
|
||||
|
||||
void MapPages(uintptr_t address, size_t size)
|
||||
{
|
||||
address = (address >> 21) << 21;
|
||||
for (size_t offset = 0; offset < size; offset += 1 << 21)
|
||||
MapPage(address + offset);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#include <kernel/font.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/kmalloc.h>
|
||||
#include <kernel/MMU.h>
|
||||
#include <kernel/multiboot.h>
|
||||
#include <kernel/Paging.h>
|
||||
#include <kernel/Panic.h>
|
||||
#include <kernel/Serial.h>
|
||||
#include <kernel/VESA.h>
|
||||
|
@ -104,7 +104,7 @@ namespace VESA
|
|||
s_height = framebuffer.height;
|
||||
s_mode = framebuffer.type;
|
||||
|
||||
Paging::MapPages(s_addr, s_pitch * s_height);
|
||||
MMU::Get().AllocateRange(s_addr, s_pitch * s_height);
|
||||
|
||||
if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS)
|
||||
{
|
||||
|
|
|
@ -10,5 +10,4 @@ $(ARCHDIR)/CPUID.o \
|
|||
$(ARCHDIR)/GDT.o \
|
||||
$(ARCHDIR)/IDT.o \
|
||||
$(ARCHDIR)/MMU.o \
|
||||
$(ARCHDIR)/Paging.o \
|
||||
$(ARCHDIR)/VESA.o \
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class MMU
|
||||
{
|
||||
public:
|
||||
static void Intialize();
|
||||
static MMU& Get();
|
||||
|
||||
void AllocatePage(uintptr_t);
|
||||
void AllocateRange(uintptr_t, ptrdiff_t);
|
||||
|
||||
private:
|
||||
MMU();
|
||||
|
||||
private:
|
||||
uint64_t* m_page_descriptor_pointer_table;
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Paging
|
||||
{
|
||||
|
||||
void Initialize();
|
||||
|
||||
void MapPage(uintptr_t address);
|
||||
void MapPages(uintptr_t address, size_t size);
|
||||
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
#include <kernel/kprint.h>
|
||||
#include <kernel/MMU.h>
|
||||
#include <kernel/multiboot.h>
|
||||
#include <kernel/Paging.h>
|
||||
#include <kernel/PIC.h>
|
||||
#include <kernel/PIT.h>
|
||||
#include <kernel/RTC.h>
|
||||
|
@ -28,70 +27,66 @@ struct ParsedCommandLine
|
|||
bool force_pic = false;
|
||||
};
|
||||
|
||||
ParsedCommandLine ParseCommandLine(const char* command_line)
|
||||
ParsedCommandLine ParseCommandLine()
|
||||
{
|
||||
ParsedCommandLine result;
|
||||
|
||||
const char* start = command_line;
|
||||
if (!(g_multiboot_info->flags & 0x02))
|
||||
return result;
|
||||
|
||||
const char* start = g_kernel_cmdline;
|
||||
const char* current = g_kernel_cmdline;
|
||||
while (true)
|
||||
{
|
||||
if (!*command_line || *command_line == ' ' || *command_line == '\t')
|
||||
if (!*current || *current == ' ' || *current == '\t')
|
||||
{
|
||||
if (command_line - start == 6 && memcmp(start, "noapic", 6) == 0)
|
||||
if (current - start == 6 && memcmp(start, "noapic", 6) == 0)
|
||||
result.force_pic = true;
|
||||
|
||||
if (!*command_line)
|
||||
if (!*current)
|
||||
break;
|
||||
start = command_line + 1;
|
||||
start = current + 1;
|
||||
}
|
||||
command_line++;
|
||||
current++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic)
|
||||
extern "C" void kernel_main()
|
||||
{
|
||||
DISABLE_INTERRUPTS();
|
||||
|
||||
Serial::initialize();
|
||||
if (magic != 0x2BADB002)
|
||||
if (g_multiboot_magic != 0x2BADB002)
|
||||
{
|
||||
dprintln("Invalid multiboot magic number");
|
||||
return;
|
||||
}
|
||||
|
||||
auto cmdline = ParseCommandLine();
|
||||
|
||||
dprintln("hello from 64 bit protected mode!");
|
||||
kmalloc_initialize();
|
||||
dprintln("kmalloc initialized");
|
||||
|
||||
Paging::Initialize();
|
||||
MMU::Intialize();
|
||||
dprintln("MMU initialized");
|
||||
|
||||
dprintln("paging enabled");
|
||||
|
||||
return;
|
||||
|
||||
s_multiboot_info = mbi;
|
||||
APIC::Initialize(cmdline.force_pic);
|
||||
dprintln("APIX initialized");
|
||||
gdt_initialize();
|
||||
dprintln("GDT initialized");
|
||||
IDT::initialize();
|
||||
dprintln("IDT initialized");
|
||||
|
||||
if (!VESA::Initialize())
|
||||
return;
|
||||
|
||||
ParsedCommandLine cmdline;
|
||||
if (mbi->flags & 0x02)
|
||||
cmdline = ParseCommandLine((const char*)mbi->cmdline);
|
||||
|
||||
APIC::Initialize(cmdline.force_pic);
|
||||
gdt_initialize();
|
||||
IDT::initialize();
|
||||
|
||||
kmalloc_initialize();
|
||||
|
||||
TTY* tty1 = new TTY;
|
||||
|
||||
PIT::initialize();
|
||||
if (!Input::initialize())
|
||||
return;
|
||||
|
||||
TTY* tty1 = new TTY;
|
||||
tty1->SetCursorPosition(0, 2);
|
||||
|
||||
ENABLE_INTERRUPTS();
|
||||
|
||||
kprintln("Hello from the kernel!");
|
||||
|
|
Loading…
Reference in New Issue