Page fault handler now allocates new page tables
Rather than contantly checking if a page table exists before access, the fault handler will automatically allocate them as needed.
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
#include "stdio.h"
|
||||
#include "x86/apic.h"
|
||||
#include "platform/interrupts.h"
|
||||
#include "mmgr.h"
|
||||
#include "string.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -14,6 +17,18 @@ struct interrupt_frame_t
|
||||
uint32_t ss;
|
||||
};
|
||||
|
||||
typedef struct page_fault_code_t
|
||||
{
|
||||
uint32_t present : 1;
|
||||
uint32_t write : 1;
|
||||
uint32_t usermode : 1;
|
||||
uint32_t reserved : 1;
|
||||
uint32_t inst_fetch : 1;
|
||||
uint32_t pk : 1;
|
||||
uint32_t shadow_stack : 1;
|
||||
uint32_t padding : 25;
|
||||
} page_fault_code_t;
|
||||
|
||||
void isr_generic(struct interrupt_frame_t *frame)
|
||||
{
|
||||
printf("Generic interrupt.\n");
|
||||
@@ -46,6 +61,7 @@ void isr_gp_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
|
||||
void isr_page_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
{
|
||||
page_fault_code_t *code = &error;
|
||||
uint32_t addr;
|
||||
asm("mov %%cr2, %0"
|
||||
: "=r"(addr));
|
||||
@@ -55,8 +71,28 @@ void isr_page_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
"mov %%ax, %%fs; "
|
||||
"mov %%ax, %%gs; " ::
|
||||
: "ax");
|
||||
printf("Exception: Page fault, code %08x, linear address %08x\n", error, addr);
|
||||
asm("hlt");
|
||||
if(code->usermode == 0
|
||||
&& code->present == 0
|
||||
&& addr >= 0xFFC00000
|
||||
&& addr < 0xFFFFF000)
|
||||
{
|
||||
printf("Allocating new page table %08x within fault handler.\n", addr);
|
||||
physaddr_t new_table = reserve_page();
|
||||
if(new_table == ENOMEM)
|
||||
{
|
||||
kernel_panic("Out of memory while allocating page table.\n");
|
||||
}
|
||||
set_pte((void*)addr, 1, PAGE_PRESENT | PAGE_USERMODE | PAGE_RW, new_table);
|
||||
asm volatile("mov %%cr3, %%eax;"
|
||||
"mov %%eax, %%cr3" ::
|
||||
: "eax", "memory");
|
||||
memset((void*)(addr & ~0xFFF), 0, page_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Exception: Page fault, code %08x, linear address %08x\n", error, addr);
|
||||
kernel_panic("Unhandled page fault.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void isr_double_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
|
||||
@@ -32,7 +32,7 @@ struct page_table_entry_t *page_tables = (struct page_table_entry_t *)0xFFC00000
|
||||
|
||||
struct page_table_entry_t *page_directory = (struct page_table_entry_t *)0xFFFFF000;
|
||||
|
||||
struct page_table_entry_t *get_pte_pointer(void *page, int level)
|
||||
struct page_table_entry_t *get_pte_pointer_chk(void *page, int level)
|
||||
{
|
||||
unsigned int directory_index = (unsigned int)page >> 22;
|
||||
struct page_table_entry_t *entry = NULL;
|
||||
@@ -48,6 +48,22 @@ struct page_table_entry_t *get_pte_pointer(void *page, int level)
|
||||
return entry;
|
||||
}
|
||||
|
||||
struct page_table_entry_t *get_pte_pointer(void *page, int level)
|
||||
{
|
||||
if(level == 0)
|
||||
{
|
||||
return &page_directory[(unsigned int)page >> 22];
|
||||
}
|
||||
else if(level == 1)
|
||||
{
|
||||
return &page_tables[(unsigned int)page >> page_bits];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int start_paging(void *linear_addr, physaddr_t start, physaddr_t end, uint32_t *directory, uint32_t *table, uint32_t *identity_table)
|
||||
{
|
||||
unsigned int directory_index = (unsigned int) linear_addr >> 22;
|
||||
@@ -114,7 +130,7 @@ void paging_load_address_space(physaddr_t table)
|
||||
|
||||
int get_pte_type(void *page, int level)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
struct page_table_entry_t *entry = get_pte_pointer_chk(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
int flags = (entry->present ? PAGE_PRESENT | PAGE_EXECUTABLE : 0)
|
||||
@@ -146,7 +162,7 @@ int set_pte_type(void *page, int level, int flags)
|
||||
|
||||
physaddr_t get_pte_address(void *page, int level)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
struct page_table_entry_t *entry = get_pte_pointer_chk(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
return entry->physical_address << page_bits | ((size_t)page & 0xFFF);
|
||||
|
||||
Reference in New Issue
Block a user