Files
quark-kernel/src/x86/mmap.cpp

285 lines
6.0 KiB
C++

#include "../mmap.hpp"
#include "../kernelstate.hpp"
class PageTableEntry {
public:
PageTableEntry()
{
this->present = 0;
this->rw = 0;
this->usermode = 0;
this->writeThrough = 0;
this->cacheDisable = 0;
this->accessed = 0;
this->dirty = 0;
this->pat = 0;
this->global = 0;
this->shared = 0;
this->ignored = 0;
this->physicalAddress = 0;
}
bool getAccessed() const
{
return accessed == 1;
}
bool getCacheDisable() const
{
return cacheDisable == 1;
}
void setCacheDisable(bool cacheDisable)
{
this->cacheDisable = cacheDisable ? 1 : 0;
}
bool getDirty() const
{
return dirty == 1;
}
bool getGlobal() const
{
return global == 1;
}
void setGlobal(bool global)
{
this->global = global ? 1 : 0;
}
bool getPat() const
{
return pat == 1;
}
void setPat(bool pat)
{
this->pat = pat ? 1 : 0;
}
physaddr_t getPhysicalAddress() const
{
physaddr_t physicalAddress = this->physicalAddress;
return physicalAddress << 12;
}
physaddr_t setPhysicalAddress(physaddr_t physicalAddress)
{
this->physicalAddress = physicalAddress >> 12;
return this->physicalAddress << 12;
}
bool getPresent() const
{
return present == 1;
}
void setPresent(bool present)
{
this->present = present ? 1 : 0;
}
bool getRw() const
{
return rw == 1;
}
void setRw(bool rw)
{
this->rw = rw ? 1 : 0;
}
bool getShared() const
{
return shared == 1;
}
void setShared(bool shared)
{
this->shared = shared ? 1 : 0;
}
bool getUsermode() const
{
return usermode == 1;
}
void setUsermode(bool usermode)
{
this->usermode = usermode ? 1 : 0;
}
bool getWriteThrough() const
{
return writeThrough == 1;
}
void setWriteThrough(bool writeThrough)
{
this->writeThrough = writeThrough ? 1 : 0;
}
physaddr_t operator=(physaddr_t rhs)
{
return setPhysicalAddress(rhs);
}
PageTableEntry operator=(PageTableEntry rhs)
{
uint32_t* iThis = (uint32_t*) this;
uint32_t* iThat = (uint32_t*) &rhs;
*iThis = *iThat;
return rhs;
}
private:
uint32_t present : 1;
uint32_t rw : 1;
uint32_t usermode : 1;
uint32_t writeThrough : 1;
uint32_t cacheDisable : 1;
uint32_t accessed : 1;
uint32_t dirty : 1;
uint32_t pat : 1;
uint32_t global : 1;
uint32_t shared : 1;
uint32_t ignored : 2;
uint32_t physicalAddress : 20;
};
int kernel::mmap(void* start, size_t length, int flags)
{
if((size_t) start % 4096 != 0)
return -1;
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
size_t tableIndex = (size_t) start / 4096;
for(int i = (int) length; i > 0; i -= 4096)
{
size_t directoryIndex = tableIndex / 1024;
if(!pageDirectory[directoryIndex].getPresent())
{
physaddr_t newPT = State::pageAllocator.allocate(4096);
if(newPT == 0)
return -1;
pageDirectory[directoryIndex] = newPT;
pageDirectory[directoryIndex].setPresent(true);
pageDirectory[directoryIndex].setUsermode(false);
pageDirectory[directoryIndex].setRw(true);
}
if(!pageTables[tableIndex].getPresent())
{
physaddr_t page = State::pageAllocator.allocate(4096);
pageTables[tableIndex] = page;
pageTables[tableIndex].setPresent(true);
pageTables[tableIndex].setUsermode(false);
if(flags & MMAP_RW)
pageTables[tableIndex].setRw(true);
}
tableIndex++;
}
return 0;
}
int kernel::mmap(void* start, physaddr_t p_start, size_t length, int flags)
{
if((size_t) start % 4096 != 0 || p_start % 4096 != 0)
return -1;
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
size_t tableIndex = (size_t) start / 4096;
physaddr_t page = p_start;
for(int i = (int) length; i > 0; i -= 4096)
{
size_t directoryIndex = tableIndex / 1024;
if(!pageDirectory[directoryIndex].getPresent())
{
physaddr_t newPT = State::pageAllocator.allocate(4096);
if(newPT == 0)
return -1;
pageDirectory[directoryIndex] = newPT;
pageDirectory[directoryIndex].setPresent(true);
pageDirectory[directoryIndex].setUsermode(false);
pageDirectory[directoryIndex].setRw(true);
}
if(!pageTables[tableIndex].getPresent())
{
pageTables[tableIndex] = page;
pageTables[tableIndex].setPresent(true);
pageTables[tableIndex].setUsermode(false);
if(flags & MMAP_RW)
pageTables[tableIndex].setRw(true);
}
tableIndex++;
page += 4096;
}
return 0;
}
int kernel::munmap(void* start, size_t length)
{
if((size_t) start % 4096 != 0)
return -1;
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
size_t tableIndex = (size_t) start / 4096;
for(int i = (int) length; i > 0; i -= 4096)
{
size_t directoryIndex = tableIndex / 1024;
if(pageDirectory[directoryIndex].getPresent())
{
pageTables[tableIndex] = 0;
pageTables[tableIndex].setPresent(false);
pageTables[tableIndex].setUsermode(false);
pageTables[tableIndex].setRw(false);
}
tableIndex++;
}
return 0;
}
bool kernel::isMapped(void* addr)
{
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
size_t tableIndex = (size_t) addr / 4096;
size_t directoryIndex = tableIndex / 1024;
if(pageDirectory[directoryIndex].getPresent())
{
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
return pageTables[tableIndex].getPresent();
}
return false;
}
physaddr_t kernel::getPhysicalAddress(void* addr)
{
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
size_t tableIndex = (size_t) addr / 4096;
return pageTables[tableIndex].getPhysicalAddress() + ((size_t) addr & 0xFFF);
}
int kernel::createAddressSpace(void* table)
{
if(((size_t) table & 0xFFF) != 0)
return -1;
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
PageTableEntry* newDirectory = (PageTableEntry*) table;
newDirectory[1022] = pageDirectory[1022];
newDirectory[1023] = pageDirectory[1023];
return 0;
}
int kernel::loadAddressSpace(physaddr_t table)
{
if((table & 0xFFF) != 0)
return -1;
asm("mov %0, %%cr3"
:
: "r" (table));
return 0;
}