2018-10-17 23:13:55 +02:00
|
|
|
#pragma once
|
|
|
|
|
2018-10-18 13:05:00 +02:00
|
|
|
#include "i386.h"
|
2019-05-28 11:53:16 +02:00
|
|
|
#include <AK/AKString.h>
|
|
|
|
#include <AK/Badge.h>
|
2018-11-05 13:48:07 +01:00
|
|
|
#include <AK/Bitmap.h>
|
2018-11-01 13:21:02 +01:00
|
|
|
#include <AK/ByteBuffer.h>
|
2019-05-28 11:53:16 +02:00
|
|
|
#include <AK/HashTable.h>
|
2018-10-18 13:05:00 +02:00
|
|
|
#include <AK/RetainPtr.h>
|
2019-05-28 11:53:16 +02:00
|
|
|
#include <AK/Retainable.h>
|
|
|
|
#include <AK/Types.h>
|
2018-10-18 13:05:00 +02:00
|
|
|
#include <AK/Vector.h>
|
2019-02-08 16:40:48 +01:00
|
|
|
#include <AK/Weakable.h>
|
2019-05-28 11:53:16 +02:00
|
|
|
#include <Kernel/FileSystem/InodeIdentifier.h>
|
2019-04-06 14:29:29 +02:00
|
|
|
#include <Kernel/LinearAddress.h>
|
2019-04-03 15:13:07 +02:00
|
|
|
#include <Kernel/VM/PhysicalPage.h>
|
|
|
|
#include <Kernel/VM/Region.h>
|
|
|
|
#include <Kernel/VM/VMObject.h>
|
2018-10-18 13:05:00 +02:00
|
|
|
|
2019-05-28 11:53:16 +02:00
|
|
|
#define PAGE_ROUND_UP(x) ((((dword)(x)) + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)))
|
2019-01-13 00:27:25 +01:00
|
|
|
|
2019-01-18 15:01:40 +01:00
|
|
|
class SynthFSInode;
|
2018-10-18 13:05:00 +02:00
|
|
|
|
2019-05-28 11:53:16 +02:00
|
|
|
enum class PageFaultResponse
|
|
|
|
{
|
2018-10-18 13:05:00 +02:00
|
|
|
ShouldCrash,
|
|
|
|
Continue,
|
2018-10-17 23:13:55 +02:00
|
|
|
};
|
|
|
|
|
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-12-31 14:58:03 +01:00
|
|
|
friend class PageDirectory;
|
2018-11-05 10:23:00 +01:00
|
|
|
friend class PhysicalPage;
|
2018-11-08 14:35:30 +01:00
|
|
|
friend class Region;
|
2018-11-08 21:20:09 +01:00
|
|
|
friend class VMObject;
|
2019-02-03 12:33:11 +01:00
|
|
|
friend ByteBuffer procfs$mm(InodeIdentifier);
|
2019-03-10 12:13:22 +01:00
|
|
|
friend ByteBuffer procfs$memstat(InodeIdentifier);
|
2019-05-28 11:53:16 +02:00
|
|
|
|
2018-10-17 23:13:55 +02:00
|
|
|
public:
|
2019-02-15 12:30:48 +01:00
|
|
|
[[gnu::pure]] static MemoryManager& the();
|
2018-10-17 23:13:55 +02:00
|
|
|
|
|
|
|
static void initialize();
|
2018-10-18 13:05:00 +02:00
|
|
|
|
2018-11-05 10:29:19 +01:00
|
|
|
PageFaultResponse handle_page_fault(const PageFault&);
|
2018-10-18 13:05:00 +02:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
bool map_region(Process&, Region&);
|
2019-01-22 05:01:00 +01:00
|
|
|
bool unmap_region(Region&);
|
2018-10-18 13:05:00 +02:00
|
|
|
|
2018-11-03 01:49:40 +01:00
|
|
|
void populate_page_directory(PageDirectory&);
|
2018-11-01 11:30:48 +01:00
|
|
|
|
2018-11-01 13:15:46 +01:00
|
|
|
void enter_process_paging_scope(Process&);
|
2019-03-10 23:40:09 +01:00
|
|
|
void enter_kernel_paging_scope();
|
2018-11-01 09:01:51 +01:00
|
|
|
|
2018-11-01 13:15:46 +01:00
|
|
|
bool validate_user_read(const Process&, LinearAddress) const;
|
|
|
|
bool validate_user_write(const Process&, LinearAddress) const;
|
2018-11-01 12:45:51 +01:00
|
|
|
|
2019-05-28 11:53:16 +02:00
|
|
|
enum class ShouldZeroFill
|
|
|
|
{
|
|
|
|
No,
|
|
|
|
Yes
|
|
|
|
};
|
2019-01-31 03:57:06 +01:00
|
|
|
|
|
|
|
RetainPtr<PhysicalPage> allocate_physical_page(ShouldZeroFill);
|
2019-01-01 02:09:43 +01:00
|
|
|
RetainPtr<PhysicalPage> allocate_supervisor_physical_page();
|
2018-11-05 10:23:00 +01:00
|
|
|
|
2019-02-05 08:17:46 +01:00
|
|
|
void remap_region(PageDirectory&, Region&);
|
2018-11-05 13:48:07 +01:00
|
|
|
|
2019-01-27 10:17:27 +01:00
|
|
|
size_t ram_size() const { return m_ram_size; }
|
|
|
|
|
2019-03-10 12:13:22 +01:00
|
|
|
int user_physical_pages_in_existence() const { return s_user_physical_pages_in_existence; }
|
|
|
|
int super_physical_pages_in_existence() const { return s_super_physical_pages_in_existence; }
|
|
|
|
|
2019-03-10 15:25:33 +01:00
|
|
|
void map_for_kernel(LinearAddress, PhysicalAddress);
|
|
|
|
|
2019-05-14 11:51:00 +02:00
|
|
|
RetainPtr<Region> allocate_kernel_region(size_t, String&& name);
|
|
|
|
void map_region_at_address(PageDirectory&, Region&, LinearAddress, bool user_accessible);
|
|
|
|
|
2018-10-17 23:13:55 +02:00
|
|
|
private:
|
|
|
|
MemoryManager();
|
|
|
|
~MemoryManager();
|
|
|
|
|
2018-11-08 21:20:09 +01:00
|
|
|
void register_vmo(VMObject&);
|
|
|
|
void unregister_vmo(VMObject&);
|
2018-11-08 22:24:02 +01:00
|
|
|
void register_region(Region&);
|
|
|
|
void unregister_region(Region&);
|
2018-11-08 21:20:09 +01:00
|
|
|
|
2019-01-22 05:01:00 +01:00
|
|
|
void remap_region_page(Region&, unsigned page_index_in_region, bool user_allowed);
|
2018-11-01 11:30:48 +01:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
void initialize_paging();
|
|
|
|
void flush_entire_tlb();
|
|
|
|
void flush_tlb(LinearAddress);
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-11-05 10:23:00 +01:00
|
|
|
RetainPtr<PhysicalPage> allocate_page_table(PageDirectory&, unsigned index);
|
2018-10-27 14:56:52 +02:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
void map_protected(LinearAddress, size_t length);
|
2018-11-03 00:31:42 +01:00
|
|
|
|
2019-01-01 02:09:43 +01:00
|
|
|
void create_identity_mapping(PageDirectory&, LinearAddress, size_t length);
|
|
|
|
void remove_identity_mapping(PageDirectory&, LinearAddress, size_t);
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-11-05 13:48:07 +01:00
|
|
|
static Region* region_from_laddr(Process&, LinearAddress);
|
2019-01-25 01:39:15 +01:00
|
|
|
static const Region* region_from_laddr(const Process&, LinearAddress);
|
2018-11-05 13:48:07 +01:00
|
|
|
|
2019-01-22 05:01:00 +01:00
|
|
|
bool copy_on_write(Region&, unsigned page_index_in_region);
|
|
|
|
bool page_in_from_inode(Region&, unsigned page_index_in_region);
|
|
|
|
bool zero_page(Region& region, unsigned page_index_in_region);
|
2018-11-05 13:48:07 +01:00
|
|
|
|
|
|
|
byte* quickmap_page(PhysicalPage&);
|
|
|
|
void unquickmap_page();
|
|
|
|
|
2018-12-31 14:58:03 +01:00
|
|
|
PageDirectory& kernel_page_directory() { return *m_kernel_page_directory; }
|
|
|
|
|
2018-10-17 23:13:55 +02:00
|
|
|
struct PageDirectoryEntry {
|
2019-05-28 11:53:16 +02:00
|
|
|
explicit PageDirectoryEntry(dword* pde)
|
|
|
|
: m_pde(pde)
|
|
|
|
{
|
|
|
|
}
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2019-01-31 17:31:23 +01:00
|
|
|
dword* page_table_base() { return reinterpret_cast<dword*>(raw() & 0xfffff000u); }
|
|
|
|
void set_page_table_base(dword value)
|
2018-10-17 23:13:55 +02:00
|
|
|
{
|
|
|
|
*m_pde &= 0xfff;
|
|
|
|
*m_pde |= value & 0xfffff000;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword raw() const { return *m_pde; }
|
|
|
|
dword* ptr() { return m_pde; }
|
|
|
|
|
2019-05-28 11:53:16 +02:00
|
|
|
enum Flags
|
|
|
|
{
|
2018-10-17 23:13:55 +02:00
|
|
|
Present = 1 << 0,
|
|
|
|
ReadWrite = 1 << 1,
|
|
|
|
UserSupervisor = 1 << 2,
|
2019-02-07 09:24:41 +01:00
|
|
|
WriteThrough = 1 << 3,
|
|
|
|
CacheDisabled = 1 << 4,
|
2018-10-17 23:13:55 +02:00
|
|
|
};
|
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
bool is_present() const { return raw() & Present; }
|
|
|
|
void set_present(bool b) { set_bit(Present, b); }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
bool is_user_allowed() const { return raw() & UserSupervisor; }
|
|
|
|
void set_user_allowed(bool b) { set_bit(UserSupervisor, b); }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
bool is_writable() const { return raw() & ReadWrite; }
|
|
|
|
void set_writable(bool b) { set_bit(ReadWrite, b); }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2019-02-07 09:24:41 +01:00
|
|
|
bool is_write_through() const { return raw() & WriteThrough; }
|
|
|
|
void set_write_through(bool b) { set_bit(WriteThrough, b); }
|
|
|
|
|
|
|
|
bool is_cache_disabled() const { return raw() & CacheDisabled; }
|
|
|
|
void set_cache_disabled(bool b) { set_bit(CacheDisabled, b); }
|
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
void set_bit(byte bit, bool value)
|
2018-10-17 23:13:55 +02:00
|
|
|
{
|
|
|
|
if (value)
|
|
|
|
*m_pde |= bit;
|
|
|
|
else
|
|
|
|
*m_pde &= ~bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword* m_pde;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PageTableEntry {
|
2019-05-28 11:53:16 +02:00
|
|
|
explicit PageTableEntry(dword* pte)
|
|
|
|
: m_pte(pte)
|
|
|
|
{
|
|
|
|
}
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
dword* physical_page_base() { return reinterpret_cast<dword*>(raw() & 0xfffff000u); }
|
|
|
|
void set_physical_page_base(dword value)
|
2018-10-17 23:13:55 +02:00
|
|
|
{
|
|
|
|
*m_pte &= 0xfffu;
|
|
|
|
*m_pte |= value & 0xfffff000u;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword raw() const { return *m_pte; }
|
|
|
|
dword* ptr() { return m_pte; }
|
|
|
|
|
2019-05-28 11:53:16 +02:00
|
|
|
enum Flags
|
|
|
|
{
|
2018-10-17 23:13:55 +02:00
|
|
|
Present = 1 << 0,
|
|
|
|
ReadWrite = 1 << 1,
|
|
|
|
UserSupervisor = 1 << 2,
|
2019-02-07 09:24:41 +01:00
|
|
|
WriteThrough = 1 << 3,
|
|
|
|
CacheDisabled = 1 << 4,
|
2018-10-17 23:13:55 +02:00
|
|
|
};
|
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
bool is_present() const { return raw() & Present; }
|
|
|
|
void set_present(bool b) { set_bit(Present, b); }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
bool is_user_allowed() const { return raw() & UserSupervisor; }
|
|
|
|
void set_user_allowed(bool b) { set_bit(UserSupervisor, b); }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
bool is_writable() const { return raw() & ReadWrite; }
|
|
|
|
void set_writable(bool b) { set_bit(ReadWrite, b); }
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2019-02-07 09:24:41 +01:00
|
|
|
bool is_write_through() const { return raw() & WriteThrough; }
|
|
|
|
void set_write_through(bool b) { set_bit(WriteThrough, b); }
|
|
|
|
|
|
|
|
bool is_cache_disabled() const { return raw() & CacheDisabled; }
|
|
|
|
void set_cache_disabled(bool b) { set_bit(CacheDisabled, b); }
|
|
|
|
|
2018-12-03 01:38:22 +01:00
|
|
|
void set_bit(byte bit, bool value)
|
2018-10-17 23:13:55 +02:00
|
|
|
{
|
|
|
|
if (value)
|
|
|
|
*m_pte |= bit;
|
|
|
|
else
|
|
|
|
*m_pte &= ~bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
dword* m_pte;
|
|
|
|
};
|
|
|
|
|
2019-03-10 12:13:22 +01:00
|
|
|
static unsigned s_user_physical_pages_in_existence;
|
|
|
|
static unsigned s_super_physical_pages_in_existence;
|
|
|
|
|
2018-12-31 14:58:03 +01:00
|
|
|
PageTableEntry ensure_pte(PageDirectory&, LinearAddress);
|
2018-10-17 23:13:55 +02:00
|
|
|
|
2019-01-22 05:01:00 +01:00
|
|
|
RetainPtr<PageDirectory> m_kernel_page_directory;
|
2018-12-03 01:38:22 +01:00
|
|
|
dword* m_page_table_zero;
|
2018-10-18 13:05:00 +02:00
|
|
|
|
2019-01-01 02:09:43 +01:00
|
|
|
LinearAddress m_quickmap_addr;
|
2018-11-01 11:30:48 +01:00
|
|
|
|
2019-02-25 16:04:08 +01:00
|
|
|
Vector<Retained<PhysicalPage>> m_free_physical_pages;
|
|
|
|
Vector<Retained<PhysicalPage>> m_free_supervisor_physical_pages;
|
2018-11-08 21:20:09 +01:00
|
|
|
|
|
|
|
HashTable<VMObject*> m_vmos;
|
2019-05-14 11:51:00 +02:00
|
|
|
HashTable<Region*> m_user_regions;
|
|
|
|
HashTable<Region*> m_kernel_regions;
|
2019-01-27 10:17:27 +01:00
|
|
|
|
|
|
|
size_t m_ram_size { 0 };
|
2019-01-31 03:57:06 +01:00
|
|
|
bool m_quickmap_in_use { false };
|
2018-10-17 23:13:55 +02:00
|
|
|
};
|
2018-11-01 11:44:21 +01:00
|
|
|
|
2018-11-01 23:04:34 +01:00
|
|
|
struct ProcessPagingScope {
|
2019-03-23 22:03:17 +01:00
|
|
|
ProcessPagingScope(Process&);
|
|
|
|
~ProcessPagingScope();
|
2018-11-01 11:44:21 +01:00
|
|
|
};
|
2019-03-10 23:40:09 +01:00
|
|
|
|
|
|
|
struct KernelPagingScope {
|
2019-03-23 22:03:17 +01:00
|
|
|
KernelPagingScope();
|
|
|
|
~KernelPagingScope();
|
2019-03-10 23:40:09 +01:00
|
|
|
};
|