2018-10-18 00:13:55 +03:00
|
|
|
#pragma once
|
|
|
|
|
2018-10-18 14:05:00 +03:00
|
|
|
#include "types.h"
|
|
|
|
#include "i386.h"
|
2018-11-05 15:48:07 +03:00
|
|
|
#include <AK/Bitmap.h>
|
2018-11-01 15:21:02 +03:00
|
|
|
#include <AK/ByteBuffer.h>
|
2018-10-18 14:05:00 +03:00
|
|
|
#include <AK/Retainable.h>
|
|
|
|
#include <AK/RetainPtr.h>
|
|
|
|
#include <AK/Vector.h>
|
2018-10-28 12:26:07 +03:00
|
|
|
#include <AK/HashTable.h>
|
2018-11-01 15:21:02 +03:00
|
|
|
#include <AK/String.h>
|
2018-11-08 13:37:01 +03:00
|
|
|
#include <VirtualFileSystem/VirtualFileSystem.h>
|
2018-10-18 14:05:00 +03:00
|
|
|
|
2018-11-01 15:15:46 +03:00
|
|
|
class Process;
|
2018-11-01 15:21:02 +03:00
|
|
|
extern Process* current;
|
2018-10-18 14:05:00 +03:00
|
|
|
|
|
|
|
enum class PageFaultResponse {
|
|
|
|
ShouldCrash,
|
|
|
|
Continue,
|
2018-10-18 00:13:55 +03:00
|
|
|
};
|
|
|
|
|
2018-11-05 12:23:00 +03:00
|
|
|
class PhysicalPage {
|
|
|
|
friend class MemoryManager;
|
2018-10-18 00:13:55 +03:00
|
|
|
public:
|
2018-11-05 12:23:00 +03:00
|
|
|
~PhysicalPage() { }
|
|
|
|
PhysicalAddress paddr() const { return m_paddr; }
|
|
|
|
|
|
|
|
void retain()
|
|
|
|
{
|
|
|
|
ASSERT(m_retain_count);
|
|
|
|
++m_retain_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void release()
|
|
|
|
{
|
|
|
|
ASSERT(m_retain_count);
|
|
|
|
if (!--m_retain_count)
|
|
|
|
return_to_freelist();
|
|
|
|
}
|
2018-10-18 00:13:55 +03:00
|
|
|
|
2018-11-05 16:10:18 +03:00
|
|
|
unsigned retain_count() const { return m_retain_count; }
|
|
|
|
|
2018-10-18 00:13:55 +03:00
|
|
|
private:
|
2018-11-05 12:23:00 +03:00
|
|
|
PhysicalPage(PhysicalAddress paddr)
|
|
|
|
: m_paddr(paddr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void return_to_freelist();
|
2018-10-18 14:05:00 +03:00
|
|
|
|
2018-11-05 12:23:00 +03:00
|
|
|
unsigned m_retain_count { 1 };
|
|
|
|
PhysicalAddress m_paddr;
|
|
|
|
};
|
|
|
|
|
2018-11-09 14:20:44 +03:00
|
|
|
class PageDirectory {
|
|
|
|
public:
|
2018-11-05 12:23:00 +03:00
|
|
|
dword entries[1024];
|
|
|
|
RetainPtr<PhysicalPage> physical_pages[1024];
|
2018-11-09 03:25:31 +03:00
|
|
|
|
|
|
|
bool is_active() const;
|
2018-10-18 00:13:55 +03:00
|
|
|
};
|
|
|
|
|
2018-11-08 16:35:30 +03:00
|
|
|
class VMObject : public Retainable<VMObject> {
|
|
|
|
public:
|
|
|
|
static RetainPtr<VMObject> create_file_backed(RetainPtr<VirtualFileSystem::Node>&&, size_t);
|
|
|
|
static RetainPtr<VMObject> create_anonymous(size_t);
|
|
|
|
RetainPtr<VMObject> clone();
|
|
|
|
|
|
|
|
~VMObject();
|
|
|
|
bool is_anonymous() const { return m_anonymous; }
|
|
|
|
|
|
|
|
VirtualFileSystem::Node* vnode() { return m_vnode.ptr(); }
|
|
|
|
const VirtualFileSystem::Node* vnode() const { return m_vnode.ptr(); }
|
|
|
|
size_t vnode_offset() const { return m_vnode_offset; }
|
|
|
|
|
|
|
|
String name() const { return m_name; }
|
|
|
|
void set_name(const String& name) { m_name = name; }
|
|
|
|
|
|
|
|
size_t page_count() const { return m_size / PAGE_SIZE; }
|
|
|
|
const Vector<RetainPtr<PhysicalPage>>& physical_pages() const { return m_physical_pages; }
|
|
|
|
Vector<RetainPtr<PhysicalPage>>& physical_pages() { return m_physical_pages; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
VMObject(RetainPtr<VirtualFileSystem::Node>&&, size_t);
|
|
|
|
explicit VMObject(VMObject&);
|
|
|
|
explicit VMObject(size_t);
|
|
|
|
String m_name;
|
|
|
|
bool m_anonymous { false };
|
|
|
|
Unix::off_t m_vnode_offset { 0 };
|
|
|
|
size_t m_size { 0 };
|
|
|
|
RetainPtr<VirtualFileSystem::Node> m_vnode;
|
|
|
|
Vector<RetainPtr<PhysicalPage>> m_physical_pages;
|
|
|
|
};
|
|
|
|
|
2018-11-09 14:20:44 +03:00
|
|
|
class Region : public Retainable<Region> {
|
|
|
|
public:
|
2018-11-08 16:35:30 +03:00
|
|
|
Region(LinearAddress, size_t, String&&, bool r, bool w, bool cow = false);
|
2018-11-08 23:20:09 +03:00
|
|
|
Region(LinearAddress, size_t, RetainPtr<VMObject>&&, size_t offset_in_vmo, String&&, bool r, bool w, bool cow = false);
|
2018-11-08 16:35:30 +03:00
|
|
|
Region(LinearAddress, size_t, RetainPtr<VirtualFileSystem::Node>&&, String&&, bool r, bool w);
|
2018-11-01 15:21:02 +03:00
|
|
|
~Region();
|
2018-11-02 22:41:58 +03:00
|
|
|
|
2018-11-08 16:35:30 +03:00
|
|
|
const VMObject& vmo() const { return *m_vmo; }
|
|
|
|
VMObject& vmo() { return *m_vmo; }
|
|
|
|
|
2018-11-02 22:41:58 +03:00
|
|
|
RetainPtr<Region> clone();
|
2018-11-05 15:48:07 +03:00
|
|
|
bool contains(LinearAddress laddr) const
|
|
|
|
{
|
|
|
|
return laddr >= linearAddress && laddr < linearAddress.offset(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned page_index_from_address(LinearAddress laddr) const
|
|
|
|
{
|
|
|
|
return (laddr - linearAddress).get() / PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
2018-11-08 23:20:09 +03:00
|
|
|
size_t first_page_index() const
|
|
|
|
{
|
|
|
|
return m_offset_in_vmo / PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t last_page_index() const
|
|
|
|
{
|
|
|
|
return (first_page_index() + page_count()) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t page_count() const
|
|
|
|
{
|
|
|
|
return size / PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool page_in(PageDirectory&);
|
2018-11-08 16:35:30 +03:00
|
|
|
int commit(Process&);
|
|
|
|
int decommit(Process&);
|
2018-11-08 13:37:01 +03:00
|
|
|
|
2018-11-01 15:21:02 +03:00
|
|
|
LinearAddress linearAddress;
|
|
|
|
size_t size { 0 };
|
2018-11-08 23:20:09 +03:00
|
|
|
size_t m_offset_in_vmo { 0 };
|
2018-11-08 16:35:30 +03:00
|
|
|
RetainPtr<VMObject> m_vmo;
|
2018-11-01 15:21:02 +03:00
|
|
|
String name;
|
2018-11-03 13:36:45 +03:00
|
|
|
bool is_readable { true };
|
|
|
|
bool is_writable { true };
|
2018-11-05 15:48:07 +03:00
|
|
|
Bitmap cow_map;
|
2018-11-01 15:21:02 +03:00
|
|
|
};
|
|
|
|
|
2018-10-27 15:56:52 +03:00
|
|
|
#define MM MemoryManager::the()
|
|
|
|
|
2018-10-18 00:13:55 +03:00
|
|
|
class MemoryManager {
|
2018-11-01 01:19:15 +03:00
|
|
|
AK_MAKE_ETERNAL
|
2018-11-05 12:23:00 +03:00
|
|
|
friend class PhysicalPage;
|
2018-11-08 16:35:30 +03:00
|
|
|
friend class Region;
|
2018-11-08 23:20:09 +03:00
|
|
|
friend class VMObject;
|
2018-10-28 12:26:07 +03:00
|
|
|
friend ByteBuffer procfs$mm();
|
2018-11-09 00:24:02 +03:00
|
|
|
friend ByteBuffer procfs$regions();
|
2018-10-18 00:13:55 +03:00
|
|
|
public:
|
2018-10-26 19:43:25 +03:00
|
|
|
static MemoryManager& the() PURE;
|
2018-10-18 00:13:55 +03:00
|
|
|
|
2018-11-01 13:30:48 +03:00
|
|
|
PhysicalAddress pageDirectoryBase() const { return PhysicalAddress(reinterpret_cast<dword>(m_kernel_page_directory)); }
|
2018-10-18 00:13:55 +03:00
|
|
|
|
|
|
|
static void initialize();
|
2018-10-18 14:05:00 +03:00
|
|
|
|
2018-11-05 12:29:19 +03:00
|
|
|
PageFaultResponse handle_page_fault(const PageFault&);
|
2018-10-18 14:05:00 +03:00
|
|
|
|
2018-11-01 15:21:02 +03:00
|
|
|
bool mapRegion(Process&, Region&);
|
|
|
|
bool unmapRegion(Process&, Region&);
|
2018-10-18 14:05:00 +03:00
|
|
|
|
2018-11-03 03:49:40 +03:00
|
|
|
void populate_page_directory(PageDirectory&);
|
|
|
|
void release_page_directory(PageDirectory&);
|
2018-11-01 13:30:48 +03:00
|
|
|
|
2018-11-01 15:21:02 +03:00
|
|
|
byte* create_kernel_alias_for_region(Region&);
|
|
|
|
void remove_kernel_alias_for_region(Region&, byte*);
|
2018-11-01 13:30:48 +03:00
|
|
|
|
|
|
|
void enter_kernel_paging_scope();
|
2018-11-01 15:15:46 +03:00
|
|
|
void enter_process_paging_scope(Process&);
|
2018-11-01 11:01:51 +03:00
|
|
|
|
2018-11-01 15:15:46 +03:00
|
|
|
bool validate_user_read(const Process&, LinearAddress) const;
|
|
|
|
bool validate_user_write(const Process&, LinearAddress) const;
|
2018-11-01 14:45:51 +03:00
|
|
|
|
2018-11-08 14:59:16 +03:00
|
|
|
RetainPtr<PhysicalPage> allocate_physical_page();
|
2018-11-05 12:23:00 +03:00
|
|
|
|
2018-11-05 15:48:07 +03:00
|
|
|
void remap_region(Process&, Region&);
|
|
|
|
|
2018-10-18 00:13:55 +03:00
|
|
|
private:
|
|
|
|
MemoryManager();
|
|
|
|
~MemoryManager();
|
|
|
|
|
2018-11-08 23:20:09 +03:00
|
|
|
void register_vmo(VMObject&);
|
|
|
|
void unregister_vmo(VMObject&);
|
2018-11-09 00:24:02 +03:00
|
|
|
void register_region(Region&);
|
|
|
|
void unregister_region(Region&);
|
2018-11-08 23:20:09 +03:00
|
|
|
|
2018-11-01 13:30:48 +03:00
|
|
|
LinearAddress allocate_linear_address_range(size_t);
|
2018-11-02 01:04:34 +03:00
|
|
|
void map_region_at_address(PageDirectory*, Region&, LinearAddress, bool user_accessible);
|
|
|
|
void unmap_range(PageDirectory*, LinearAddress, size_t);
|
2018-11-05 15:48:07 +03:00
|
|
|
void remap_region_page(PageDirectory*, Region&, unsigned page_index_in_region, bool user_allowed);
|
2018-11-01 13:30:48 +03:00
|
|
|
|
2018-10-18 00:13:55 +03:00
|
|
|
void initializePaging();
|
2018-10-23 16:53:11 +03:00
|
|
|
void flushEntireTLB();
|
|
|
|
void flushTLB(LinearAddress);
|
2018-10-18 00:13:55 +03:00
|
|
|
|
2018-11-05 12:23:00 +03:00
|
|
|
RetainPtr<PhysicalPage> allocate_page_table(PageDirectory&, unsigned index);
|
|
|
|
void deallocate_page_table(PageDirectory&, unsigned index);
|
2018-10-27 15:56:52 +03:00
|
|
|
|
2018-10-21 22:57:59 +03:00
|
|
|
void protectMap(LinearAddress, size_t length);
|
2018-11-03 02:31:42 +03:00
|
|
|
|
|
|
|
void create_identity_mapping(LinearAddress, size_t length);
|
|
|
|
void remove_identity_mapping(LinearAddress, size_t);
|
2018-10-18 00:13:55 +03:00
|
|
|
|
2018-11-05 15:48:07 +03:00
|
|
|
static Region* region_from_laddr(Process&, LinearAddress);
|
|
|
|
|
|
|
|
bool copy_on_write(Process&, Region&, unsigned page_index_in_region);
|
2018-11-08 23:20:09 +03:00
|
|
|
bool page_in_from_vnode(PageDirectory&, Region&, unsigned page_index_in_region);
|
2018-11-05 15:48:07 +03:00
|
|
|
|
|
|
|
byte* quickmap_page(PhysicalPage&);
|
|
|
|
void unquickmap_page();
|
|
|
|
|
2018-10-18 00:13:55 +03: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-02 01:04:34 +03:00
|
|
|
PageTableEntry ensurePTE(PageDirectory*, LinearAddress);
|
2018-10-18 00:13:55 +03:00
|
|
|
|
2018-11-02 01:04:34 +03:00
|
|
|
PageDirectory* m_kernel_page_directory;
|
2018-10-18 00:13:55 +03:00
|
|
|
dword* m_pageTableZero;
|
2018-10-18 14:05:00 +03:00
|
|
|
dword* m_pageTableOne;
|
|
|
|
|
2018-11-01 13:30:48 +03:00
|
|
|
LinearAddress m_next_laddr;
|
|
|
|
|
2018-11-05 12:23:00 +03:00
|
|
|
Vector<RetainPtr<PhysicalPage>> m_free_physical_pages;
|
2018-11-08 23:20:09 +03:00
|
|
|
|
|
|
|
HashTable<VMObject*> m_vmos;
|
2018-11-09 00:24:02 +03:00
|
|
|
HashTable<Region*> m_regions;
|
2018-10-18 00:13:55 +03:00
|
|
|
};
|
2018-11-01 13:44:21 +03:00
|
|
|
|
|
|
|
struct KernelPagingScope {
|
|
|
|
KernelPagingScope() { MM.enter_kernel_paging_scope(); }
|
2018-11-01 15:15:46 +03:00
|
|
|
~KernelPagingScope() { MM.enter_process_paging_scope(*current); }
|
2018-11-01 13:44:21 +03:00
|
|
|
};
|
|
|
|
|
2018-11-02 01:04:34 +03:00
|
|
|
struct ProcessPagingScope {
|
|
|
|
ProcessPagingScope(Process& process) { MM.enter_process_paging_scope(process); }
|
|
|
|
~ProcessPagingScope() { MM.enter_process_paging_scope(*current); }
|
2018-11-01 13:44:21 +03:00
|
|
|
};
|