Lots of fussing about getting the PageEntry stuff right

I think I got something I am mostly happy with... :-)
This commit is contained in:
Eryn Wells 2016-04-25 10:34:16 -04:00
parent 7414aec667
commit 65513588f8
2 changed files with 90 additions and 50 deletions

View file

@ -1,4 +1,4 @@
/* Pager.cc /* PageAllocator.cc
* vim: set tw=80: * vim: set tw=80:
* Eryn Wells <eryn@erynwells.me> * Eryn Wells <eryn@erynwells.me>
*/ */
@ -7,89 +7,123 @@
*/ */
#include "Attributes.hh" #include "Attributes.hh"
#include "Pager.hh"
#include "kstd/Bitmap.hh" #include "kstd/Bitmap.hh"
#include "kstd/Memory.hh"
#include "kstd/PrintFormat.hh"
#include "memory/Memory.hh" #include "memory/Memory.hh"
#include "memory/PageAllocator.hh"
namespace kernel { namespace kernel {
struct PageDirectoryEntry struct PageEntry
{ {
PageDirectoryEntry(); PageEntry();
/** Mark the whole entry not present. */ enum class Present { No = 0, Yes = 1 };
void setNotPresent(); enum class ReadWrite { No = 0, Yes = 1 };
bool isNotPresent() const; enum class UserAccess { No = 0, Yes = 1 };
void set(Present present);
void set(ReadWrite readWrite);
void set(UserAccess user);
void setAddress(void* address); void setAddress(void* address);
private: protected:
static const u8 OneBit = 0; struct Flag {
static const u8 ReadWriteBit = 1; static const u8 Present = 0;
static const u8 UserAccessBit = 2; static const u8 ReadWrite = 1;
static const u8 PageWriteThroughBit = 3; static const u8 UserAccess = 2;
static const u8 PageCacheDisabledBit = 4; static const u8 PageWriteThrough = 3;
static const u8 AccessedBit = 5; static const u8 PageCacheDisabled = 4;
static const u8 DirtyBit = 6; static const u8 Accessed = 5;
static const u8 ZeroBit = 7; static const u8 Dirty = 6;
static const u32 IgnoredMask = 0x00000F00; static const u8 PageAttributeTable = 7;
static const u8 Global = 8;
};
static const u32 AddressMask = 0xFFFFF000; static const u32 AddressMask = 0xFFFFF000;
static const u32 FlagMask = 0x00000FFF;
u32 mEntry; u32 mEntry;
void setRequiredBits();
}; };
PageEntry::PageEntry()
PageDirectoryEntry::PageDirectoryEntry()
: mEntry(0) : mEntry(0)
{ {
static_assert(sizeof(PageDirectoryEntry) == 4, "PageDirectoryEntry must be 4 bytes long."); static_assert(sizeof(PageEntry) == 4, "PageEntry must be 4 bytes long.");
} }
bool
PageDirectoryEntry::isNotPresent()
const
{
return mEntry == 0;
}
void void
PageDirectoryEntry::setNotPresent() PageEntry::set(Present present)
{ {
mEntry = 0; if (present == Present::Yes) {
kstd::Bit::set(mEntry, Flag::Present);
} else {
kstd::Bit::clear(mEntry, Flag::Present);
}
} }
void
PageEntry::set(ReadWrite rw)
{
if (rw == ReadWrite::Yes) {
kstd::Bit::set(mEntry, Flag::ReadWrite);
} else {
kstd::Bit::clear(mEntry, Flag::ReadWrite);
}
}
void void
PageDirectoryEntry::setAddress(void* address) PageEntry::set(UserAccess user)
{
if (user == UserAccess::Yes) {
kstd::Bit::set(mEntry, Flag::UserAccess);
} else {
kstd::Bit::clear(mEntry, Flag::UserAccess);
}
}
void
PageEntry::setAddress(void* address)
{ {
kstd::Bit::setMask(mEntry, memory::pageAlignDown(uptr(address)), AddressMask); kstd::Bit::setMask(mEntry, memory::pageAlignDown(uptr(address)), AddressMask);
} }
void
PageDirectoryEntry::setRequiredBits() struct PageDirectoryEntry
: public PageEntry
{ {
kstd::Bit::set(mEntry, OneBit); void setFlagsForSystemDirectory();
kstd::Bit::clear(mEntry, ZeroBit); };
kstd::Bit::clearMask(mEntry, IgnoredMask);
void
PageDirectoryEntry::setFlagsForSystemDirectory()
{
set(PageEntry::Present::Yes);
set(PageEntry::ReadWrite::Yes);
set(PageEntry::UserAccess::No);
} }
struct PageTableEntry
: public PageEntry
{ };
/* /*
* Public * Public
*/ */
void void
PageAllocator::initialize(const StartupInformation& startupInformation, PageAllocator::initialize(const StartupInformation& startupInformation,
void* pageDirectory) FrameAllocator* frameAllocator)
{ {
mPageDirectory = reinterpret_cast<PageDirectoryEntry*>(pageDirectory); mPageDirectory = reinterpret_cast<PageDirectoryEntry*>(frameAllocator->allocate());
for (usize i = 0; i < NumberOfEntries; i++) { kstd::printFormat("Page directory at 0x%08lX\n", uptr(mPageDirectory));
mPageDirectory[i].setNotPresent(); kstd::Memory::zero(mPageDirectory, memory::pageSize * (memory::pageSize / sizeof(PageDirectoryEntry)));
}
auto& firstPageTable = mPageDirectory[0];
firstPageTable.setAddress(frameAllocator->allocate());
firstPageTable.setFlagsForSystemDirectory();
} }
/* /*

View file

@ -1,4 +1,4 @@
/* Pager.hh /* PageAllocator.hh
* vim: set tw=80: * vim: set tw=80:
* Eryn Wells <eryn@erynwells.me> * Eryn Wells <eryn@erynwells.me>
*/ */
@ -6,8 +6,8 @@
* Page tables 'n stuff. * Page tables 'n stuff.
*/ */
#ifndef __MEMORY_PAGE_HH__ #ifndef __MEMORY_PAGEALLOCATOR_HH__
#define __MEMORY_PAGE_HH__ #define __MEMORY_PAGEALLOCATOR_HH__
#include "StartupInformation.hh" #include "StartupInformation.hh"
#include "kstd/Types.hh" #include "kstd/Types.hh"
@ -21,7 +21,13 @@ struct PageDirectoryEntry;
*/ */
struct PageAllocator struct PageAllocator
{ {
void initialize(const StartupInformation& startupInformation, void* pageDirectory); /**
* Initialize the page allocator.
*
* @param [in] startupInformation The kernel startup information struct.
* @param [in] frameAllocator The kernel's page frame allocator.
*/
void initialize(const StartupInformation& startupInformation, FrameAllocator* frameAllocator);
// TODO: A method to install a page table into the system. For per-process page tables, I'll need a way to set the current page table so the system knows where to look. // TODO: A method to install a page table into the system. For per-process page tables, I'll need a way to set the current page table so the system knows where to look.
@ -34,4 +40,4 @@ private:
} /* namespace kernel */ } /* namespace kernel */
#endif /* __MEMORY_PAGE_HH__ */ #endif /* __MEMORY_PAGEALLOCATOR_HH__ */