quark/src/kernel/arch/i686/mm/vmm.c

143 líneas
4,7 KiB
C

#include "vmm.h"
#include "pmm.h"
#include "../../../lib/memory.h"
i686_vmm_page_directory_t *g_vmm_current_dir = 0;
i686_phys_addr g_vmm_current_pdbr = 0;
void __attribute__((cdecl)) i686_vmm_flush_tlb_entry(i686_virt_addr addr);
static inline i686_pt_entry_t *i686_vmm_ptable_lookup_entry(i686_vmm_page_table_t *p, i686_virt_addr addr){
if(p) return &p->entries[i686_PAGE_TABLE_INDEX(addr)];
return 0;
}
static inline i686_pd_entry_t *i686_vmm_pdirectory_lookup_entry(i686_vmm_page_directory_t *p, i686_virt_addr addr){
if(p) return &p->entries[i686_PAGE_DIRECTORY_INDEX(addr)];
return 0;
}
static inline bool i686_vmm_switch_pdirectory(i686_vmm_page_directory_t *dir){
if(!dir) return false;
g_vmm_current_dir = dir;
i686_pmm_load_pdbr(g_vmm_current_pdbr);
return true;
}
static inline i686_vmm_page_directory_t *i686_vmm_get_pdirectory(){
return g_vmm_current_dir;
}
bool i686_vmm_alloc_page(i686_pt_entry_t *entry){
void *p = i686_pmm_alloc_block();
if(!p) return false;
i686_pt_entry_set_frame(entry, (i686_phys_addr)p);
i686_pt_entry_add_attr(entry, i686_PTE_PRESENT);
return true;
}
void i686_vmm_free_page(i686_pt_entry_t *entry){
void *p = (void *)i686_pt_entry_get_frame(*entry);
if(p) i686_pmm_free_block(p);
i686_pt_entry_del_attr(entry, i686_PTE_PRESENT);
}
void i686_vmm_map_page(void *phys, void *virt){
// Get page directory
i686_vmm_page_directory_t *page_dir = i686_vmm_get_pdirectory();
// Get page table
i686_pd_entry_t *e = &page_dir->entries[i686_PAGE_DIRECTORY_INDEX((uint32_t)virt)];
if((*e & i686_PTE_PRESENT) != i686_PTE_PRESENT){
// Must allocate
i686_vmm_page_table_t *table = (i686_vmm_page_table_t *)i686_pmm_alloc_block();
if(!table) return;
// Clear page table
memset(table, 0, sizeof(i686_vmm_page_table_t));
// Create a new entry
i686_pd_entry_t *entry = &page_dir->entries[i686_PAGE_DIRECTORY_INDEX((uint32_t)virt)];
// Map in the table
i686_pd_entry_add_attr(entry, i686_PDE_PRESENT);
i686_pd_entry_add_attr(entry, i686_PDE_WRITABLE);
i686_pd_entry_set_frame(entry, (i686_phys_addr)table);
}
// Get table
i686_vmm_page_table_t *table = (i686_vmm_page_table_t *)i686_PAGE_GET_PHYS_ADDR(e);
// Get page
i686_pt_entry_t *page = &table->entries[i686_PAGE_TABLE_INDEX((uint32_t)virt)];
// Map it
i686_pt_entry_set_frame(page, (i686_phys_addr)phys);
i686_pt_entry_add_attr(page, i686_PTE_PRESENT);
}
void i686_vmm_initialize(){
// Allocate default page table
i686_vmm_page_table_t *table = (i686_vmm_page_table_t *)i686_pmm_alloc_block();
if(!table) return;
// Allocate 3GB page table
i686_vmm_page_table_t *table2 = (i686_vmm_page_table_t *)i686_pmm_alloc_block();
if(!table2) return;
// Clear default table
memset(table, 0, sizeof(i686_vmm_page_table_t));
// First 4MB are identity mapped
for(int i = 0, frame = 0x0, virt = 0x00000000; i<1024; i++, frame += 4096, virt += 4096){
// Create a new page
i686_pt_entry_t page = 0;
i686_pt_entry_add_attr(&page, i686_PTE_PRESENT);
i686_pt_entry_set_frame(&page, frame);
// Add the page to the page table
table2->entries[i686_PAGE_TABLE_INDEX(virt)] = page;
}
// Map 1MB to 3GB
for(int i = 0, frame = 0x100000, virt = 0xc0000000; i<1024; i++, frame += 4096, virt += 4096){
// Create a new page
i686_pt_entry_t page = 0;
i686_pt_entry_add_attr(&page, i686_PTE_PRESENT);
i686_pt_entry_set_frame(&page, frame);
// Add the page to the page table
table->entries[i686_PAGE_TABLE_INDEX(virt)] = page;
}
// Create default directory table
i686_vmm_page_directory_t *dir = (i686_vmm_page_directory_t *)i686_pmm_alloc_blocks(3);
if(!dir) return;
// Clear directory table and set it as current
memset(dir, 0, sizeof(i686_vmm_page_directory_t));
i686_pd_entry_t *entry = &dir->entries[i686_PAGE_DIRECTORY_INDEX(0xc0000000)];
i686_pd_entry_add_attr(entry, i686_PDE_PRESENT);
i686_pd_entry_add_attr(entry, i686_PDE_WRITABLE);
i686_pd_entry_set_frame(entry, (i686_phys_addr)table);
i686_pd_entry_t *entry2 = &dir->entries[i686_PAGE_DIRECTORY_INDEX(0x00000000)];
i686_pd_entry_add_attr(entry2, i686_PDE_PRESENT);
i686_pd_entry_add_attr(entry2, i686_PDE_WRITABLE);
i686_pd_entry_set_frame(entry2, (i686_phys_addr)table2);
// Store current PDBR
g_vmm_current_pdbr = (i686_phys_addr)&dir->entries;
// Switch to our page directory
i686_vmm_switch_pdirectory(dir);
// Enable paging
i686_pmm_paging_enable(true);
}