2018-10-17 23:13:55 +02:00
|
|
|
#pragma once
|
|
|
|
|
2018-10-18 13:05:00 +02:00
|
|
|
#include "types.h"
|
|
|
|
#include "i386.h"
|
|
|
|
#include <AK/Retainable.h>
|
|
|
|
#include <AK/RetainPtr.h>
|
|
|
|
#include <AK/Vector.h>
|
2018-10-28 10:26:07 +01:00
|
|
|
#include <AK/HashTable.h>
|
2018-10-22 15:42:39 +02:00
|
|
|
#include "Task.h"
|
2018-10-18 13:05:00 +02:00
|
|
|
|
|
|
|
class Task;
|
|
|
|
|
|
|
|
enum class PageFaultResponse {
|
|
|
|
ShouldCrash,
|
|
|
|
Continue,
|
2018-10-17 23:13:55 +02:00
|
|
|
};
|
|
|
|
|
2018-10-18 13:05:00 +02:00
|
|
|
struct Zone : public Retainable<Zone> {
|
2018-10-28 10:36:59 +01:00
|
|
|
friend ByteBuffer procfs$mm();
|
2018-10-17 23:13:55 +02:00
|
|
|
public:
|
2018-10-28 10:26:07 +01:00
|
|
|
~Zone();
|
2018-10-18 13:05:00 +02:00
|
|
|
size_t size() const { return m_pages.size() * PAGE_SIZE; }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-10-18 13:05:00 +02:00
|
|
|
const Vector<PhysicalAddress>& pages() const { return m_pages; }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
|
|
|
private:
|
2018-10-18 13:05:00 +02:00
|
|
|
friend class MemoryManager;
|
|
|
|
friend bool copyToZone(Zone&, const void* data, size_t);
|
2018-10-28 10:26:07 +01:00
|
|
|
explicit Zone(Vector<PhysicalAddress>&&);
|
2018-10-18 13:05:00 +02:00
|
|
|
|
|
|
|
Vector<PhysicalAddress> m_pages;
|
2018-10-17 23:13:55 +02:00
|
|
|
};
|
|
|
|
|
2018-10-18 13:05:00 +02:00
|
|
|
bool copyToZone(Zone&, const void* data, size_t);
|
|
|
|
|
2018-10-27 14:56:52 +02:00
|
|
|
#define MM MemoryManager::the()
|
|
|
|
|
2018-10-17 23:13:55 +02:00
|
|
|
class MemoryManager {
|
2018-10-31 23:19:15 +01:00
|
|
|
AK_MAKE_ETERNAL
|
2018-10-28 10:26:07 +01:00
|
|
|
friend ByteBuffer procfs$mm();
|
2018-10-17 23:13:55 +02:00
|
|
|
public:
|
2018-10-26 18:43:25 +02:00
|
|
|
static MemoryManager& the() PURE;
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-11-01 11:30:48 +01:00
|
|
|
PhysicalAddress pageDirectoryBase() const { return PhysicalAddress(reinterpret_cast<dword>(m_kernel_page_directory)); }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
|
|
|
static void initialize();
|
2018-10-18 13:05:00 +02:00
|
|
|
|
|
|
|
PageFaultResponse handlePageFault(const PageFault&);
|
|
|
|
|
|
|
|
RetainPtr<Zone> createZone(size_t);
|
|
|
|
|
|
|
|
// HACK: don't use this jeez :(
|
|
|
|
byte* quickMapOnePage(PhysicalAddress);
|
|
|
|
|
2018-10-27 14:56:52 +02:00
|
|
|
bool mapSubregion(Task&, Task::Subregion&);
|
|
|
|
bool unmapSubregion(Task&, Task::Subregion&);
|
|
|
|
bool mapSubregionsForTask(Task&);
|
|
|
|
bool unmapSubregionsForTask(Task&);
|
|
|
|
|
2018-10-22 15:42:39 +02:00
|
|
|
bool mapRegion(Task&, Task::Region&);
|
2018-10-23 10:12:50 +02:00
|
|
|
bool unmapRegion(Task&, Task::Region&);
|
2018-10-18 14:53:00 +02:00
|
|
|
bool mapRegionsForTask(Task&);
|
|
|
|
bool unmapRegionsForTask(Task&);
|
2018-10-18 13:05:00 +02:00
|
|
|
|
2018-10-28 10:26:07 +01:00
|
|
|
void registerZone(Zone&);
|
|
|
|
void unregisterZone(Zone&);
|
|
|
|
|
2018-11-01 11:30:48 +01:00
|
|
|
void populate_page_directory(Task&);
|
|
|
|
|
|
|
|
byte* create_kernel_alias_for_region(Task::Region&);
|
|
|
|
void remove_kernel_alias_for_region(Task::Region&, byte*);
|
|
|
|
|
|
|
|
void enter_kernel_paging_scope();
|
|
|
|
void enter_task_paging_scope(Task&);
|
2018-11-01 09:01:51 +01:00
|
|
|
|
2018-10-17 23:13:55 +02:00
|
|
|
private:
|
|
|
|
MemoryManager();
|
|
|
|
~MemoryManager();
|
|
|
|
|
2018-11-01 11:30:48 +01:00
|
|
|
LinearAddress allocate_linear_address_range(size_t);
|
|
|
|
void map_region_at_address(dword* page_directory, Task::Region&, LinearAddress);
|
|
|
|
void unmap_range(dword* page_directory, LinearAddress, size_t);
|
|
|
|
|
2018-10-17 23:13:55 +02:00
|
|
|
void initializePaging();
|
2018-10-23 15:53:11 +02:00
|
|
|
void flushEntireTLB();
|
|
|
|
void flushTLB(LinearAddress);
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-10-27 14:56:52 +02:00
|
|
|
void* allocatePageTable();
|
|
|
|
|
2018-10-21 21:57:59 +02:00
|
|
|
void protectMap(LinearAddress, size_t length);
|
2018-10-17 23:13:55 +02:00
|
|
|
void identityMap(LinearAddress, size_t length);
|
|
|
|
|
2018-10-18 13:05:00 +02:00
|
|
|
Vector<PhysicalAddress> allocatePhysicalPages(size_t count);
|
|
|
|
|
2018-10-17 23:13:55 +02:00
|
|
|
struct PageDirectoryEntry {
|
|
|
|
explicit PageDirectoryEntry(dword* pde) : m_pde(pde) { }
|
|
|
|
|
|
|
|
dword* pageTableBase() { return reinterpret_cast<dword*>(raw() & 0xfffff000u); }
|
|
|
|
void setPageTableBase(dword value)
|
|
|
|
{
|
|
|
|
*m_pde &= 0xfff;
|
|
|
|
*m_pde |= value & 0xfffff000;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword raw() const { return *m_pde; }
|
|
|
|
dword* ptr() { return m_pde; }
|
|
|
|
|
|
|
|
enum Flags {
|
|
|
|
Present = 1 << 0,
|
|
|
|
ReadWrite = 1 << 1,
|
|
|
|
UserSupervisor = 1 << 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
bool isPresent() const { return raw() & Present; }
|
|
|
|
void setPresent(bool b) { setBit(Present, b); }
|
|
|
|
|
|
|
|
bool isUserAllowed() const { return raw() & UserSupervisor; }
|
|
|
|
void setUserAllowed(bool b) { setBit(UserSupervisor, b); }
|
|
|
|
|
|
|
|
bool isWritable() const { return raw() & ReadWrite; }
|
|
|
|
void setWritable(bool b) { setBit(ReadWrite, b); }
|
|
|
|
|
|
|
|
void setBit(byte bit, bool value)
|
|
|
|
{
|
|
|
|
if (value)
|
|
|
|
*m_pde |= bit;
|
|
|
|
else
|
|
|
|
*m_pde &= ~bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword* m_pde;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PageTableEntry {
|
|
|
|
explicit PageTableEntry(dword* pte) : m_pte(pte) { }
|
|
|
|
|
|
|
|
dword* physicalPageBase() { return reinterpret_cast<dword*>(raw() & 0xfffff000u); }
|
|
|
|
void setPhysicalPageBase(dword value)
|
|
|
|
{
|
|
|
|
*m_pte &= 0xfffu;
|
|
|
|
*m_pte |= value & 0xfffff000u;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword raw() const { return *m_pte; }
|
|
|
|
dword* ptr() { return m_pte; }
|
|
|
|
|
|
|
|
enum Flags {
|
|
|
|
Present = 1 << 0,
|
|
|
|
ReadWrite = 1 << 1,
|
|
|
|
UserSupervisor = 1 << 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
bool isPresent() const { return raw() & Present; }
|
|
|
|
void setPresent(bool b) { setBit(Present, b); }
|
|
|
|
|
|
|
|
bool isUserAllowed() const { return raw() & UserSupervisor; }
|
|
|
|
void setUserAllowed(bool b) { setBit(UserSupervisor, b); }
|
|
|
|
|
|
|
|
bool isWritable() const { return raw() & ReadWrite; }
|
|
|
|
void setWritable(bool b) { setBit(ReadWrite, b); }
|
|
|
|
|
|
|
|
void setBit(byte bit, bool value)
|
|
|
|
{
|
|
|
|
if (value)
|
|
|
|
*m_pte |= bit;
|
|
|
|
else
|
|
|
|
*m_pte &= ~bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword* m_pte;
|
|
|
|
};
|
|
|
|
|
2018-11-01 09:01:51 +01:00
|
|
|
PageTableEntry ensurePTE(dword* pageDirectory, LinearAddress);
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-11-01 11:30:48 +01:00
|
|
|
dword* m_kernel_page_directory;
|
2018-10-17 23:13:55 +02:00
|
|
|
dword* m_pageTableZero;
|
2018-10-18 13:05:00 +02:00
|
|
|
dword* m_pageTableOne;
|
|
|
|
|
2018-11-01 11:30:48 +01:00
|
|
|
LinearAddress m_next_laddr;
|
|
|
|
|
2018-10-28 10:26:07 +01:00
|
|
|
HashTable<Zone*> m_zones;
|
2018-10-18 13:05:00 +02:00
|
|
|
|
|
|
|
Vector<PhysicalAddress> m_freePages;
|
2018-10-17 23:13:55 +02:00
|
|
|
};
|