luxos/Kernel/memory/mem-paging.c

129 lines
2.9 KiB
C

/*
* memory-vi.c
*
* Created on: Aug 23, 2011
* Author: Tiberiu
*/
#include <memory-add.h>
#include <stdio.h>
/*******************************
* Data *
*******************************/
PageDirectory* CurrentDirectory;
PageDirectory* KernelDirectory;
void PagingEnable()
{
uint32 tmp;
asm volatile ("mov %%cr0, %0" : "=r"(tmp));
tmp |= 0x80000000;
asm volatile ("mov %0, %%cr0" : : "r"(tmp));
}
void PagingDisable()
{
uint32 tmp;
asm volatile ("mov %%cr0, %0" : "=r"(tmp));
tmp &= 0x7FFFFFFF;
asm volatile ("mov %0, %%cr0" : : "r"(tmp));
}
void PagingSwitchDirectory(PageDirectory* dir)
{
CurrentDirectory = dir;
asm volatile ("mov %0, %%cr3" : : "r"(dir->PhysicalAddr));
}
void PagingFlushTlb ()
{
uint32 tmp;
asm volatile ("mov %%cr3, %0" : "=r"(tmp));
asm volatile ("mov %0, %%cr3" : : "r" (tmp));
}
void PagingInitialize(uint32* kernelEnd)
{
// Create the kernel page directory
PageDirectory* kdir = kmalloc_a(sizeof(PageDirectory));
memset(kdir, 0, sizeof(PageDirectory));
KernelDirectory = kdir;
// Set up physical address of PDEs.
kdir->PhysicalAddr = (uint32) kdir->TablesPhysical;
// Identity map the kernel
uint32 i = 0;
while (i <= *kernelEnd + 1024)
{
PagingMapPage(i, i, PageWriteable, kdir);
i += 0x1000;
}
// Reserve the identity mapped blocks
MemPhReserveBlocks(0x0, *kernelEnd);
PagingSwitchDirectory(kdir);
PagingEnable();
}
void PagingMapPage (uint32 phys, uint32 virt, uint32 flags, PageDirectory* pd)
{
// Calculate pde and pte
uint32 pde = virt >> 22;
uint32 pte = (virt >> 12) & 0x3ff;
phys &= 0xFFFFF000; // Make sure address is page aligned
flags &= 0xFFF; // Make sure flags don't overflow
// See if page table exists
if (!pd->Tables[pde])
{
// No? allocate it
uint32 ph;
PageTable* pt = kmalloc_ap(sizeof(PageTable), &ph);
memset(pt, 0, sizeof(PageTable));
pd->Tables[pde] = pt;
pd->TablesPhysical[pde] = ph | 0x7;
}
// Set up the page
pd->Tables[pde]->Pages[pte] = phys | flags | 0x1; // Present, and flags
// If it is the current directory, flush the tlb to notice the change
if (pd == CurrentDirectory) PagingFlushTlb();
}
void PagingUnmapPage (uint32 virt, PageDirectory* pd)
{
// Calculate pde and pte
uint32 pde = virt >> 22;
uint32 pte = (virt >> 12) & 0x3ff;
if (!pd->Tables[pde] || !pd->Tables[pde]->Pages[pte]) return;
// Get physical address
uint32 phys = pd->Tables[pde]->Pages[pte] & PageFrame;
// Free page
pd->Tables[pde]->Pages[pte] = 0;
MemPhFreeBlock(phys);
// If it is the current directory, flush the tlb to notice the change
if (pd == CurrentDirectory) PagingFlushTlb();
}
uint32 PagingGetPhysical (uint32 virt, PageDirectory* pd)
{
// Calculate pde and pte
uint32 pde = virt >> 22;
uint32 pte = (virt >> 12) & 0x3ff;
// Not mapped
if (!pd->Tables[pde] || !pd->Tables[pde]->Pages[pte]) return NULL;
return (pd->Tables[pde]->Pages[pte] & PageFrame);
}