Massive backlog of changes
This commit is contained in:
196
src/x86/paging.c
Normal file
196
src/x86/paging.c
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "platform/paging.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct page_table_entry_t
|
||||
{
|
||||
uint32_t present : 1;
|
||||
uint32_t rw : 1;
|
||||
uint32_t usermode : 1;
|
||||
uint32_t write_through : 1;
|
||||
uint32_t cache_disable : 1;
|
||||
uint32_t accessed : 1;
|
||||
uint32_t dirty : 1;
|
||||
uint32_t pat : 1;
|
||||
uint32_t global : 1;
|
||||
uint32_t shared : 1;
|
||||
uint32_t type : 2;
|
||||
uint32_t physical_address : 20;
|
||||
};
|
||||
|
||||
extern int _kernel_start;
|
||||
|
||||
const size_t page_size = 4096;
|
||||
|
||||
const size_t page_bits = 12;
|
||||
|
||||
const size_t page_table_levels = 2;
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned int directory_index = (unsigned int)page >> 22;
|
||||
struct page_table_entry_t *entry = NULL;
|
||||
if(level == 0)
|
||||
{
|
||||
entry = &page_directory[directory_index];
|
||||
}
|
||||
else if(level == 1 && page_directory[directory_index].present)
|
||||
{
|
||||
unsigned int page_index = (unsigned int)page >> page_bits;
|
||||
entry = &page_tables[page_index];
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
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;
|
||||
physaddr_t p = start;
|
||||
size_t count = 0;
|
||||
while (p < end)
|
||||
{
|
||||
uint32_t table_entry = p + 3;
|
||||
int index = p / page_size;
|
||||
table[index - start / page_size] = table_entry;
|
||||
identity_table[index] = table_entry;
|
||||
p += page_size;
|
||||
count++;
|
||||
}
|
||||
directory[0] = ((uint32_t)identity_table) + 3;
|
||||
directory[directory_index] = ((uint32_t)table) + 3 + 1024;
|
||||
directory[1023] = ((uint32_t)directory) + 3;
|
||||
asm("mov %0, %%cr3"
|
||||
:
|
||||
: "r"(directory));
|
||||
asm("mov %%cr0, %%eax \n"
|
||||
"or $0x80010000, %%eax \n"
|
||||
"mov %%eax, %%cr0"
|
||||
:
|
||||
:
|
||||
: "eax");
|
||||
return count;
|
||||
}
|
||||
|
||||
int paging_init_top_table(physaddr_t table)
|
||||
{
|
||||
struct page_table_entry_t buffer = page_directory[0];
|
||||
page_directory[0].physical_address = table >> page_bits;
|
||||
asm volatile("invlpg 0xFFC00000" ::
|
||||
: "memory");
|
||||
memset((void *)page_tables, 0, page_size);
|
||||
int last_index = (page_size / sizeof(struct page_table_entry_t)) - 1;
|
||||
int kernel_index = (size_t)&_kernel_start >> 22;
|
||||
for(int i = kernel_index; i < last_index; i++)
|
||||
{
|
||||
page_tables[i] = page_directory[i];
|
||||
}
|
||||
page_tables[last_index].physical_address = table >> page_bits;
|
||||
page_tables[last_index].present = 1;
|
||||
page_tables[last_index].rw = 1;
|
||||
page_directory[0] = buffer;
|
||||
asm volatile("invlpg 0xFFC00000" ::
|
||||
: "memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
physaddr_t paging_current_address_space()
|
||||
{
|
||||
return page_directory[1023].physical_address << page_bits;
|
||||
}
|
||||
|
||||
void paging_load_address_space(physaddr_t table)
|
||||
{
|
||||
asm volatile("mov %0, %%cr3"
|
||||
:
|
||||
: "r"(table)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
int get_pte_type(void *page, int level)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
int flags = (entry->present ? PAGE_PRESENT | PAGE_EXECUTABLE : 0)
|
||||
| (entry->rw ? PAGE_RW : 0)
|
||||
| (entry->usermode ? PAGE_USERMODE : 0);
|
||||
return flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int set_pte_type(void *page, int level, int flags)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
entry->present = PAGE_PRESENT ? 1 : 0;
|
||||
entry->rw = PAGE_RW ? 1 : 0;
|
||||
entry->usermode = PAGE_USERMODE ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
physaddr_t get_pte_address(void *page, int level)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
return entry->physical_address << page_bits | ((size_t)page & 0xFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int set_pte_address(void *page, int level, physaddr_t addr)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
entry->physical_address = addr >> page_bits;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int set_pte(void *page, int level, int flags, physaddr_t addr)
|
||||
{
|
||||
if(set_pte_address(page, level, addr) == 0)
|
||||
{
|
||||
return set_pte_type(page, level, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void wipe_page_table(void *page, int level)
|
||||
{
|
||||
if(level == 1 && (get_pte_type(page, 0) & PAGE_PRESENT) != 0)
|
||||
{
|
||||
unsigned int table_index = ((unsigned int)page >> page_bits) & ~0x3FF;
|
||||
for(int i = 0; i < 1024; i++)
|
||||
{
|
||||
page_tables[table_index + i].present = 0;
|
||||
page_tables[table_index + i].physical_address = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user