luxos/SysCore/memory/mmngr_vi.c

193 lines
6.0 KiB
C

// +==============================================+
// | HEADERS |
// +===================================== cta os =+
#include "mmngr_vi.h"
#include "mmngr_ph.h"
// +==============================================+
// | DEFINITIONS & MACROS |
// +===================================== cta os =+
#define PAGE_SIZE 4096
#define PTABLE_ADDR_SPACE_SIZE 0x400000
#define DTABLE_ADDR_SPACE_SIZE 0xffffffff
#define PAGE_DIRECTORY_INDEX(x) (((x) >> 22) & 0x3ff)
#define PAGE_TABLE_INDEX(x) (((x) >> 12) & 0x3ff)
#define PAGE_GET_PHYSICAL_ADDRESS(x) (*x & ~0xfff)
pdirectory* _current_directory;
unsigned _current_page_directory_base_register;
extern unsigned char *memset (unsigned char *dest, unsigned char val, int count);
// +==============================================+
// | PAGE FUNCTIONS |
// +===================================== cta os =+
unsigned char vmmngr_alloc_page (pt_entry* entry)
{
void* p = pmmngr_alloc_block ();
if (!p) return 0;
pt_entry_set_frame(entry, (unsigned)p);
pt_entry_add_attrib (entry, _I86_PTE_PRESENT);
return 1;
}
void vmmngr_free_page (pt_entry* entry)
{
void* p = (void*) pt_entry_get_frame(*entry);
if (p) pmmngr_free_block (p);
pt_entry_del_attrib (entry, _I86_PTE_PRESENT);
}
// +==============================================+
// | PAGE TABLE FUNCTIONS |
// +===================================== cta os =+
inline void vmmngr_ptable_clear(ptable* p)
{
if(p) memset ((unsigned char*)p, 0, sizeof(ptable));
}
inline unsigned vmmngr_ptable_virt_to_index (unsigned addr)
{
return (addr >= PTABLE_ADDR_SPACE_SIZE) ? 0 : addr/PAGE_SIZE;
}
inline pt_entry* vmmngr_ptable_lookup_entry (ptable* p, unsigned addr)
{
if (p) return &p->m_entries[vmmngr_ptable_virt_to_index(addr)];
return 0;
}
// +==============================================+
// | PAGE DIRECTORY FUNCTIONS |
// +===================================== cta os =+
inline void vmmngr_pdirectory_clear(pdirectory* dir)
{
if(dir) memset ((unsigned char*)dir, 0, sizeof(pdirectory));
}
inline unsigned vmmngr_pdirectory_virt_to_index (unsigned addr)
{
return (addr > DTABLE_ADDR_SPACE_SIZE) ? 0 : addr/PAGE_SIZE;
}
inline pd_entry* vmmngr_pdirectory_lookup_entry (pdirectory* dir, unsigned addr)
{
if (dir) return &dir->m_entries[vmmngr_ptable_virt_to_index(addr)];
return 0;
}
// +==============================================+
// | VIRTUAL MEMORY MANAGER |
// +===================================== cta os =+
inline unsigned char vmmngr_switch_pdirectory (pdirectory* dir)
{
if (!dir) return 0;
_current_directory = dir;
write_cr3 (_current_page_directory_base_register);
return 1;
}
pdirectory* vmmngr_get_directory() {
return _current_directory;
}
unsigned char vmmngr_map_page (unsigned phys, unsigned virt)
{
pdirectory* dir = _current_directory; // get page directory
pd_entry* e = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt)]; // get page table
if ((*e & _I86_PTE_PRESENT) != _I86_PTE_PRESENT) {
// Page table not present, allocate it
ptable* table = (ptable *)pmmngr_alloc_block();
if (!table) return 0;
// Clear it
vmmngr_ptable_clear(table);
// Create new entry
pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt)];
// Map in the table
pd_entry_add_attrib (entry, _I86_PDE_PRESENT);
pd_entry_add_attrib (entry, _I86_PDE_WRITABLE);
pd_entry_set_frame (entry, (unsigned) table);
}
// get table
ptable* table = (ptable*) PAGE_GET_PHYSICAL_ADDRESS(e);
// get page
pt_entry* page = &table->m_entries [PAGE_TABLE_INDEX (virt)];
pt_entry_set_frame (page, phys);
pt_entry_add_attrib (page, _I86_PTE_PRESENT);
return 1;
}
unsigned char vmmngr_initialize()
{
unsigned int i, virt, frame;
// Allocate default page & directory table(s)
ptable* table = (ptable*) pmmngr_alloc_block();
ptable* table2 = (ptable*) pmmngr_alloc_block();
pdirectory* dir = (pdirectory*) pmmngr_alloc_blocks(3);
if (!table || !table2 || !dir) return 0;
// Clear page & directory tables
vmmngr_ptable_clear(table);
vmmngr_ptable_clear(table2);
vmmngr_pdirectory_clear(dir);
// Identity map the first page table
virt = 0; frame = 0;
for (i = 0; i < 1024; i++, virt+=4096, frame += 4096)
{
pt_entry* page = &table2->m_entries[PAGE_TABLE_INDEX(virt)];
*page = 0;
pt_entry_add_attrib (page, _I86_PTE_PRESENT);
pt_entry_set_frame (page, frame);
}
// Map 0x100000 to 0xC0000000
virt = 0xC0000000; frame = 0x100000;
for (i = 0; i < 1024; i++, virt+=4096, frame += 4096)
{
pt_entry* page = &table->m_entries[PAGE_TABLE_INDEX(virt)];
*page = 0;
pt_entry_add_attrib (page, _I86_PTE_PRESENT);
pt_entry_set_frame (page, frame);
}
// Get tables in dir table and point them to our tables
pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (0xC0000000)];
pd_entry_add_attrib (entry, _I86_PDE_PRESENT);
pd_entry_add_attrib (entry, _I86_PDE_WRITABLE);
pd_entry_set_frame (entry, (unsigned) table);
entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (0x00000000)];
pd_entry_add_attrib (entry, _I86_PDE_PRESENT);
pd_entry_add_attrib (entry, _I86_PDE_WRITABLE);
pd_entry_set_frame (entry, (unsigned) table2);
// Store current PDBR
_current_page_directory_base_register = (unsigned) &dir->m_entries;
// Switch to our page directory
vmmngr_switch_pdirectory (dir);
// Enable paging
pmmngr_paging_enable (1);
return 1;
}