mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:47:45 +00:00
More paging stuff.
The test userspace process now runs at linear address 0x300000 which is mapped to a dynamically allocated page from the MemoryManager. Cool!
This commit is contained in:
parent
89851a9ded
commit
f67d695254
10 changed files with 339 additions and 66 deletions
|
@ -4,6 +4,7 @@
|
||||||
#include <AK/kmalloc.h>
|
#include <AK/kmalloc.h>
|
||||||
#include "i386.h"
|
#include "i386.h"
|
||||||
#include "StdLib.h"
|
#include "StdLib.h"
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
static MemoryManager* s_the;
|
static MemoryManager* s_the;
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ MemoryManager::MemoryManager()
|
||||||
{
|
{
|
||||||
m_pageDirectory = (dword*)0x5000;
|
m_pageDirectory = (dword*)0x5000;
|
||||||
m_pageTableZero = (dword*)0x6000;
|
m_pageTableZero = (dword*)0x6000;
|
||||||
|
m_pageTableOne = (dword*)0x7000;
|
||||||
|
|
||||||
initializePaging();
|
initializePaging();
|
||||||
}
|
}
|
||||||
|
@ -29,12 +31,19 @@ void MemoryManager::initializePaging()
|
||||||
static_assert(sizeof(MemoryManager::PageDirectoryEntry) == 4);
|
static_assert(sizeof(MemoryManager::PageDirectoryEntry) == 4);
|
||||||
static_assert(sizeof(MemoryManager::PageTableEntry) == 4);
|
static_assert(sizeof(MemoryManager::PageTableEntry) == 4);
|
||||||
memset(m_pageTableZero, 0, 4096);
|
memset(m_pageTableZero, 0, 4096);
|
||||||
|
memset(m_pageTableOne, 0, 4096);
|
||||||
memset(m_pageDirectory, 0, 4096);
|
memset(m_pageDirectory, 0, 4096);
|
||||||
|
|
||||||
kprintf("MM: Page directory @ %p\n", m_pageDirectory);
|
kprintf("MM: Page directory @ %p\n", m_pageDirectory);
|
||||||
kprintf("MM: Page table zero @ %p [0]=%x\n", m_pageTableZero, m_pageTableZero[0]);
|
kprintf("MM: Page table zero @ %p\n", m_pageTableZero);
|
||||||
// Build a basic PDB that identity maps the first 1MB.
|
kprintf("MM: Page table one @ %p\n", m_pageTableOne);
|
||||||
|
|
||||||
identityMap(LinearAddress(0), 4 * MB);
|
identityMap(LinearAddress(0), 4 * MB);
|
||||||
|
|
||||||
|
// Put pages between 4MB and 16MB in the page freelist.
|
||||||
|
for (size_t i = (4 * MB) + 1024; i < (16 * MB); i += PAGE_SIZE) {
|
||||||
|
m_freePages.append(PhysicalAddress(i));
|
||||||
|
}
|
||||||
|
|
||||||
asm volatile("movl %%eax, %%cr3"::"a"(m_pageDirectory));
|
asm volatile("movl %%eax, %%cr3"::"a"(m_pageDirectory));
|
||||||
asm volatile(
|
asm volatile(
|
||||||
|
@ -57,6 +66,11 @@ auto MemoryManager::ensurePTE(LinearAddress linearAddress) -> PageTableEntry
|
||||||
pde.setUserAllowed(true);
|
pde.setUserAllowed(true);
|
||||||
pde.setPresent(true);
|
pde.setPresent(true);
|
||||||
pde.setWritable(true);
|
pde.setWritable(true);
|
||||||
|
} else if (pageDirectoryIndex == 1) {
|
||||||
|
pde.setPageTableBase((dword)m_pageTableOne);
|
||||||
|
pde.setUserAllowed(false);
|
||||||
|
pde.setPresent(true);
|
||||||
|
pde.setWritable(false);
|
||||||
} else {
|
} else {
|
||||||
// FIXME: We need an allocator!
|
// FIXME: We need an allocator!
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
@ -75,10 +89,6 @@ void MemoryManager::identityMap(LinearAddress linearAddress, size_t length)
|
||||||
pte.setUserAllowed(true);
|
pte.setUserAllowed(true);
|
||||||
pte.setPresent(true);
|
pte.setPresent(true);
|
||||||
pte.setWritable(true);
|
pte.setWritable(true);
|
||||||
if (pteAddress.get() == 0x6023) {
|
|
||||||
kprintf("kek\n");
|
|
||||||
HANG;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,4 +97,86 @@ void MemoryManager::initialize()
|
||||||
s_the = new MemoryManager;
|
s_the = new MemoryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PageFaultResponse MemoryManager::handlePageFault(const PageFault& fault)
|
||||||
|
{
|
||||||
|
kprintf("MM: handlePageFault(%w) at laddr=%p\n", fault.code(), fault.address().get());
|
||||||
|
if (fault.isNotPresent()) {
|
||||||
|
kprintf(" >> NP fault!\n");
|
||||||
|
} else if (fault.isProtectionViolation()) {
|
||||||
|
kprintf(" >> PV fault!\n");
|
||||||
|
}
|
||||||
|
return PageFaultResponse::ShouldCrash;
|
||||||
|
}
|
||||||
|
|
||||||
|
RetainPtr<Zone> MemoryManager::createZone(size_t size)
|
||||||
|
{
|
||||||
|
auto pages = allocatePhysicalPages(ceilDiv(size, PAGE_SIZE));
|
||||||
|
if (pages.isEmpty()) {
|
||||||
|
kprintf("MM: createZone: no physical pages for size %u", size);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return adopt(*new Zone(move(pages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<PhysicalAddress> MemoryManager::allocatePhysicalPages(size_t count)
|
||||||
|
{
|
||||||
|
kprintf("MM: alloc %u pages from %u available\n", count, m_freePages.size());
|
||||||
|
if (count > m_freePages.size())
|
||||||
|
return { };
|
||||||
|
|
||||||
|
Vector<PhysicalAddress> pages;
|
||||||
|
pages.ensureCapacity(count);
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
pages.append(m_freePages.takeLast());
|
||||||
|
kprintf("MM: returning the pages (%u of them)\n", pages.size());
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte* MemoryManager::quickMapOnePage(PhysicalAddress physicalAddress)
|
||||||
|
{
|
||||||
|
auto pte = ensurePTE(LinearAddress(4 * MB));
|
||||||
|
kprintf("quickmap %x @ %x {pte @ %p}\n", physicalAddress.get(), 4*MB, pte.ptr());
|
||||||
|
pte.setPhysicalPageBase(physicalAddress.pageBase());
|
||||||
|
pte.setPresent(true);
|
||||||
|
pte.setWritable(true);
|
||||||
|
return (byte*)(4 * MB);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryManager::unmapZonesForTask(Task& task)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryManager::mapZonesForTask(Task& task)
|
||||||
|
{
|
||||||
|
for (auto& mappedZone : task.m_mappedZones) {
|
||||||
|
auto& zone = *mappedZone.zone;
|
||||||
|
for (size_t i = 0; i < zone.m_pages.size(); ++i) {
|
||||||
|
auto pte = ensurePTE(mappedZone.linearAddress.offset(i * PAGE_SIZE));
|
||||||
|
pte.setPhysicalPageBase(zone.m_pages[i].get());
|
||||||
|
pte.setPresent(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copyToZone(Zone& zone, const void* data, size_t size)
|
||||||
|
{
|
||||||
|
if (zone.size() < size) {
|
||||||
|
kprintf("copyToZone: can't fit %u bytes into zone with size %u\n", size, zone.size());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* dataptr = (const byte*)data;
|
||||||
|
size_t remaining = size;
|
||||||
|
for (size_t i = 0; i < zone.m_pages.size(); ++i) {
|
||||||
|
byte* dest = MemoryManager::the().quickMapOnePage(zone.m_pages[i]);
|
||||||
|
kprintf("memcpy(%p, %p, %u)\n", dest, dataptr, min(PAGE_SIZE, remaining));
|
||||||
|
memcpy(dest, dataptr, min(PAGE_SIZE, remaining));
|
||||||
|
dataptr += PAGE_SIZE;
|
||||||
|
remaining -= PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,39 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Types.h>
|
#include "types.h"
|
||||||
|
#include "i386.h"
|
||||||
|
#include <AK/Retainable.h>
|
||||||
|
#include <AK/RetainPtr.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
#include <AK/HashMap.h>
|
||||||
|
|
||||||
class PhysicalAddress {
|
class Task;
|
||||||
public:
|
|
||||||
PhysicalAddress() { }
|
|
||||||
explicit PhysicalAddress(dword address) : m_address(address) { }
|
|
||||||
|
|
||||||
dword get() const { return m_address; }
|
enum class PageFaultResponse {
|
||||||
void set(dword address) { m_address = address; }
|
ShouldCrash,
|
||||||
void mask(dword m) { m_address &= m; }
|
Continue,
|
||||||
|
|
||||||
private:
|
|
||||||
dword m_address { 0 };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LinearAddress {
|
struct Zone : public Retainable<Zone> {
|
||||||
public:
|
public:
|
||||||
LinearAddress() { }
|
~Zone() { }
|
||||||
explicit LinearAddress(dword address) : m_address(address) { }
|
size_t size() const { return m_pages.size() * PAGE_SIZE; }
|
||||||
|
|
||||||
LinearAddress offset(dword o) const { return LinearAddress(m_address + o); }
|
const Vector<PhysicalAddress>& pages() const { return m_pages; }
|
||||||
dword get() const { return m_address; }
|
|
||||||
void set(dword address) { m_address = address; }
|
|
||||||
void mask(dword m) { m_address &= m; }
|
|
||||||
|
|
||||||
bool operator==(const LinearAddress& other) const { return m_address == other.m_address; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
dword m_address { 0 };
|
friend class MemoryManager;
|
||||||
|
friend bool copyToZone(Zone&, const void* data, size_t);
|
||||||
|
explicit Zone(Vector<PhysicalAddress>&& pages)
|
||||||
|
: m_pages(move(pages))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<PhysicalAddress> m_pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool copyToZone(Zone&, const void* data, size_t);
|
||||||
|
|
||||||
class MemoryManager {
|
class MemoryManager {
|
||||||
public:
|
public:
|
||||||
static MemoryManager& the();
|
static MemoryManager& the();
|
||||||
|
@ -38,6 +41,17 @@ public:
|
||||||
PhysicalAddress pageDirectoryBase() const { return PhysicalAddress(reinterpret_cast<dword>(m_pageDirectory)); }
|
PhysicalAddress pageDirectoryBase() const { return PhysicalAddress(reinterpret_cast<dword>(m_pageDirectory)); }
|
||||||
|
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
|
PageFaultResponse handlePageFault(const PageFault&);
|
||||||
|
|
||||||
|
RetainPtr<Zone> createZone(size_t);
|
||||||
|
|
||||||
|
// HACK: don't use this jeez :(
|
||||||
|
byte* quickMapOnePage(PhysicalAddress);
|
||||||
|
|
||||||
|
bool mapZonesForTask(Task&);
|
||||||
|
bool unmapZonesForTask(Task&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryManager();
|
MemoryManager();
|
||||||
~MemoryManager();
|
~MemoryManager();
|
||||||
|
@ -46,6 +60,8 @@ private:
|
||||||
|
|
||||||
void identityMap(LinearAddress, size_t length);
|
void identityMap(LinearAddress, size_t length);
|
||||||
|
|
||||||
|
Vector<PhysicalAddress> allocatePhysicalPages(size_t count);
|
||||||
|
|
||||||
struct PageDirectoryEntry {
|
struct PageDirectoryEntry {
|
||||||
explicit PageDirectoryEntry(dword* pde) : m_pde(pde) { }
|
explicit PageDirectoryEntry(dword* pde) : m_pde(pde) { }
|
||||||
|
|
||||||
|
@ -128,4 +144,9 @@ private:
|
||||||
|
|
||||||
dword* m_pageDirectory;
|
dword* m_pageDirectory;
|
||||||
dword* m_pageTableZero;
|
dword* m_pageTableZero;
|
||||||
|
dword* m_pageTableOne;
|
||||||
|
|
||||||
|
HashMap<int, RetainPtr<Zone>> m_zones;
|
||||||
|
|
||||||
|
Vector<PhysicalAddress> m_freePages;
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,34 +45,6 @@ void initialize()
|
||||||
kprintf("syscall: int 0x80 handler installed\n");
|
kprintf("syscall: int 0x80 handler installed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD invoke(DWORD function)
|
|
||||||
{
|
|
||||||
DWORD result;
|
|
||||||
asm("int $0x80":"=a"(result):"a"(function));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD invoke(DWORD function, DWORD arg1)
|
|
||||||
{
|
|
||||||
DWORD result;
|
|
||||||
asm("int $0x80":"=a"(result):"a"(function),"d"(arg1));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD invoke(DWORD function, DWORD arg1, DWORD arg2)
|
|
||||||
{
|
|
||||||
DWORD result;
|
|
||||||
asm("int $0x80":"=a"(result):"a"(function),"d"(arg1),"c"(arg2));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD invoke(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
|
||||||
{
|
|
||||||
DWORD result;
|
|
||||||
asm volatile("int $0x80":"=a"(result):"a"(function),"d"(arg1),"c"(arg2),"b"(arg3));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
||||||
{
|
{
|
||||||
switch (function) {
|
switch (function) {
|
||||||
|
|
|
@ -19,9 +19,33 @@ enum Function {
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
DWORD invoke(DWORD function);
|
|
||||||
DWORD invoke(DWORD function, DWORD arg1);
|
inline DWORD invoke(DWORD function)
|
||||||
DWORD invoke(DWORD function, DWORD arg1, DWORD arg2);
|
{
|
||||||
DWORD invoke(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3);
|
DWORD result;
|
||||||
|
asm("int $0x80":"=a"(result):"a"(function));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DWORD invoke(DWORD function, DWORD arg1)
|
||||||
|
{
|
||||||
|
DWORD result;
|
||||||
|
asm("int $0x80":"=a"(result):"a"(function),"d"(arg1));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DWORD invoke(DWORD function, DWORD arg1, DWORD arg2)
|
||||||
|
{
|
||||||
|
DWORD result;
|
||||||
|
asm("int $0x80":"=a"(result):"a"(function),"d"(arg1),"c"(arg2));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DWORD invoke(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
||||||
|
{
|
||||||
|
DWORD result;
|
||||||
|
asm volatile("int $0x80":"=a"(result):"a"(function),"d"(arg1),"c"(arg2),"b"(arg3));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,14 @@ void Task::allocateLDT()
|
||||||
m_tss.ldt = newLDTSelector;
|
m_tss.ldt = newLDTSelector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Task::mapZone(LinearAddress address, RetainPtr<Zone>&& zone)
|
||||||
|
{
|
||||||
|
// FIXME: This needs sanity checks. What if this overlaps existing zones?
|
||||||
|
kprintf("mapped zone with size %u at %x\n", zone->size(), address.get());
|
||||||
|
m_mappedZones.append({ address, move(zone) });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||||
: m_name(n)
|
: m_name(n)
|
||||||
, m_entry(e)
|
, m_entry(e)
|
||||||
|
@ -100,6 +108,19 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||||
, m_state(Runnable)
|
, m_state(Runnable)
|
||||||
, m_ring(ring)
|
, m_ring(ring)
|
||||||
{
|
{
|
||||||
|
if (!isRing0()) {
|
||||||
|
auto zone = MemoryManager::the().createZone(PAGE_SIZE);
|
||||||
|
ASSERT(zone);
|
||||||
|
|
||||||
|
kprintf("New task zone: { size: %u }\n", zone->size());
|
||||||
|
|
||||||
|
bool success = mapZone(LinearAddress(0x300000), zone.copyRef());
|
||||||
|
ASSERT(success);
|
||||||
|
|
||||||
|
success = copyToZone(*zone, (void*)e, PAGE_SIZE);
|
||||||
|
ASSERT(success);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&m_tss, 0, sizeof(m_tss));
|
memset(&m_tss, 0, sizeof(m_tss));
|
||||||
memset(&m_ldtEntries, 0, sizeof(m_ldtEntries));
|
memset(&m_ldtEntries, 0, sizeof(m_ldtEntries));
|
||||||
|
|
||||||
|
@ -133,7 +154,13 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||||
|
|
||||||
m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get();
|
m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get();
|
||||||
|
|
||||||
m_tss.eip = (DWORD)m_entry;
|
if (isRing0()) {
|
||||||
|
m_tss.eip = (DWORD)m_entry;
|
||||||
|
} else {
|
||||||
|
m_tss.eip = m_mappedZones[0].linearAddress.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintf("basically ready\n");
|
||||||
|
|
||||||
// NOTE: Each task gets 4KB of stack.
|
// NOTE: Each task gets 4KB of stack.
|
||||||
// This memory is leaked ATM.
|
// This memory is leaked ATM.
|
||||||
|
@ -165,7 +192,7 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||||
|
|
||||||
system.nprocess++;
|
system.nprocess++;
|
||||||
|
|
||||||
kprintf("Task %u (%s) spawned @ %p\n", m_pid, m_name.characters(), m_entry);
|
kprintf("Task %u (%s) spawned @ %p\n", m_pid, m_name.characters(), m_tss.eip);
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::~Task()
|
Task::~Task()
|
||||||
|
@ -300,6 +327,11 @@ static bool contextSwitch(Task* t)
|
||||||
if (current->state() == Task::Running)
|
if (current->state() == Task::Running)
|
||||||
current->setState(Task::Runnable);
|
current->setState(Task::Runnable);
|
||||||
|
|
||||||
|
bool success = MemoryManager::the().unmapZonesForTask(*current);
|
||||||
|
ASSERT(success);
|
||||||
|
success = MemoryManager::the().mapZonesForTask(*t);
|
||||||
|
ASSERT(success);
|
||||||
|
|
||||||
current = t;
|
current = t;
|
||||||
t->setState(Task::Running);
|
t->setState(Task::Running);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
//#define TASK_SANITY_CHECKS
|
//#define TASK_SANITY_CHECKS
|
||||||
|
|
||||||
class FileHandle;
|
class FileHandle;
|
||||||
|
class Zone;
|
||||||
|
|
||||||
class Task : public InlineLinkedListNode<Task> {
|
class Task : public InlineLinkedListNode<Task> {
|
||||||
friend class InlineLinkedListNode<Task>;
|
friend class InlineLinkedListNode<Task>;
|
||||||
|
@ -97,6 +98,9 @@ public:
|
||||||
static void taskDidCrash(Task*);
|
static void taskDidCrash(Task*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class MemoryManager;
|
||||||
|
|
||||||
|
bool mapZone(LinearAddress, RetainPtr<Zone>&&);
|
||||||
FileHandle* openFile(String&&);
|
FileHandle* openFile(String&&);
|
||||||
|
|
||||||
void allocateLDT();
|
void allocateLDT();
|
||||||
|
@ -120,6 +124,13 @@ private:
|
||||||
Vector<OwnPtr<FileHandle>> m_fileHandles;
|
Vector<OwnPtr<FileHandle>> m_fileHandles;
|
||||||
RingLevel m_ring { Ring0 };
|
RingLevel m_ring { Ring0 };
|
||||||
int m_error { 0 };
|
int m_error { 0 };
|
||||||
|
|
||||||
|
struct MappedZone {
|
||||||
|
LinearAddress linearAddress;
|
||||||
|
RetainPtr<Zone> zone;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<MappedZone> m_mappedZones;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void task_init();
|
extern void task_init();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "i386.h"
|
#include "i386.h"
|
||||||
#include "Assertions.h"
|
#include "Assertions.h"
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
|
#include "MemoryManager.h"
|
||||||
|
|
||||||
struct DescriptorTablePointer {
|
struct DescriptorTablePointer {
|
||||||
WORD size;
|
WORD size;
|
||||||
|
@ -67,8 +68,8 @@ asm( \
|
||||||
" iret\n" \
|
" iret\n" \
|
||||||
);
|
);
|
||||||
|
|
||||||
EH_ENTRY(13)
|
// 13: General Protection Fault
|
||||||
|
EH_ENTRY(13);
|
||||||
void exception_13_handler()
|
void exception_13_handler()
|
||||||
{
|
{
|
||||||
auto& regs = *reinterpret_cast<RegisterDump*>(exception_state_dump);
|
auto& regs = *reinterpret_cast<RegisterDump*>(exception_state_dump);
|
||||||
|
@ -88,6 +89,42 @@ void exception_13_handler()
|
||||||
Task::taskDidCrash(current);
|
Task::taskDidCrash(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 14: Page Fault
|
||||||
|
EH_ENTRY(14);
|
||||||
|
void exception_14_handler()
|
||||||
|
{
|
||||||
|
dword faultAddress;
|
||||||
|
asm ("movl %%cr2, %%eax":"=a"(faultAddress));
|
||||||
|
|
||||||
|
auto& regs = *reinterpret_cast<RegisterDump*>(exception_state_dump);
|
||||||
|
kprintf("%s page fault: %u(%s), %s laddr=%p\n",
|
||||||
|
current->isRing0() ? "Kernel" : "User",
|
||||||
|
current->pid(),
|
||||||
|
current->name().characters(),
|
||||||
|
exception_code & 2 ? "write" : "read",
|
||||||
|
faultAddress);
|
||||||
|
|
||||||
|
kprintf("exception code: %w\n", exception_code);
|
||||||
|
kprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs);
|
||||||
|
kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx);
|
||||||
|
kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, regs.esp, regs.esi, regs.edi);
|
||||||
|
|
||||||
|
if (current->isRing0())
|
||||||
|
HANG;
|
||||||
|
|
||||||
|
auto response = MemoryManager::the().handlePageFault(PageFault(exception_code, LinearAddress(faultAddress)));
|
||||||
|
|
||||||
|
if (response == PageFaultResponse::ShouldCrash) {
|
||||||
|
kprintf("Crashing after unresolved page fault\n");
|
||||||
|
// NOTE: This will schedule a new task.
|
||||||
|
Task::taskDidCrash(current);
|
||||||
|
} else if (response == PageFaultResponse::Continue) {
|
||||||
|
kprintf("Continuing after resolved page fault\n");
|
||||||
|
} else {
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define EH(i, msg) \
|
#define EH(i, msg) \
|
||||||
static void _exception ## i () \
|
static void _exception ## i () \
|
||||||
{ \
|
{ \
|
||||||
|
@ -227,7 +264,7 @@ void idt_init()
|
||||||
registerInterruptHandler(0x0b, _exception11);
|
registerInterruptHandler(0x0b, _exception11);
|
||||||
registerInterruptHandler(0x0c, _exception12);
|
registerInterruptHandler(0x0c, _exception12);
|
||||||
registerInterruptHandler(0x0d, exception_13_entry);
|
registerInterruptHandler(0x0d, exception_13_entry);
|
||||||
registerInterruptHandler(0x0e, _exception14);
|
registerInterruptHandler(0x0e, exception_14_entry);
|
||||||
registerInterruptHandler(0x0f, _exception15);
|
registerInterruptHandler(0x0f, _exception15);
|
||||||
registerInterruptHandler(0x10, _exception16);
|
registerInterruptHandler(0x10, _exception16);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096u
|
||||||
|
|
||||||
union Descriptor {
|
union Descriptor {
|
||||||
struct {
|
struct {
|
||||||
WORD limit_lo;
|
WORD limit_lo;
|
||||||
|
@ -76,6 +78,42 @@ void writeGDTEntry(WORD selector, Descriptor&);
|
||||||
/* Map IRQ0-15 @ ISR 0x50-0x5F */
|
/* Map IRQ0-15 @ ISR 0x50-0x5F */
|
||||||
#define IRQ_VECTOR_BASE 0x50
|
#define IRQ_VECTOR_BASE 0x50
|
||||||
|
|
||||||
|
struct PageFaultFlags {
|
||||||
|
enum Flags {
|
||||||
|
NotPresent = 0x00,
|
||||||
|
ProtectionViolation = 0x01,
|
||||||
|
Read = 0x00,
|
||||||
|
Write = 0x02,
|
||||||
|
UserMode = 0x04,
|
||||||
|
SupervisorMode = 0x00,
|
||||||
|
InstructionFetch = 0x08,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class PageFault {
|
||||||
|
public:
|
||||||
|
PageFault(word code, LinearAddress address)
|
||||||
|
: m_code(code)
|
||||||
|
, m_address(address)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearAddress address() const { return m_address; }
|
||||||
|
word code() const { return m_code; }
|
||||||
|
|
||||||
|
bool isNotPresent() const { return (m_code & 1) == PageFaultFlags::NotPresent; }
|
||||||
|
bool isProtectionViolation() const { return (m_code & 1) == PageFaultFlags::ProtectionViolation; }
|
||||||
|
bool isRead() const { return (m_code & 2) == PageFaultFlags::Read; }
|
||||||
|
bool isWrite() const { return (m_code & 2) == PageFaultFlags::Write; }
|
||||||
|
bool isUser() const { return (m_code & 4) == PageFaultFlags::UserMode; }
|
||||||
|
bool isSupervisor() const { return (m_code & 4) == PageFaultFlags::SupervisorMode; }
|
||||||
|
bool isInstructionFetch() const { return (m_code & 8) == PageFaultFlags::InstructionFetch; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
word m_code;
|
||||||
|
LinearAddress m_address;
|
||||||
|
};
|
||||||
|
|
||||||
struct RegisterDump {
|
struct RegisterDump {
|
||||||
WORD gs;
|
WORD gs;
|
||||||
WORD fs;
|
WORD fs;
|
||||||
|
@ -95,3 +133,8 @@ struct RegisterDump {
|
||||||
DWORD eflags;
|
DWORD eflags;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
inline constexpr dword pageBaseOf(dword address)
|
||||||
|
{
|
||||||
|
return address & 0xfffff000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ static void user_main()
|
||||||
DO_SYSCALL_A3(0x3000, 2, 3, 4);
|
DO_SYSCALL_A3(0x3000, 2, 3, 4);
|
||||||
// Crash ourselves!
|
// Crash ourselves!
|
||||||
char* x = reinterpret_cast<char*>(0xbeefbabe);
|
char* x = reinterpret_cast<char*>(0xbeefbabe);
|
||||||
//*x = 1;
|
*x = 1;
|
||||||
HANG;
|
HANG;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// nothing?
|
// nothing?
|
||||||
|
@ -158,7 +158,7 @@ void init()
|
||||||
|
|
||||||
//vfs->listDirectory("/");
|
//vfs->listDirectory("/");
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
{
|
{
|
||||||
auto motdFile = vfs->open("/motd.txt");
|
auto motdFile = vfs->open("/motd.txt");
|
||||||
ASSERT(motdFile);
|
ASSERT(motdFile);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Types.h>
|
||||||
|
|
||||||
#define PACKED __attribute__ ((packed))
|
#define PACKED __attribute__ ((packed))
|
||||||
#define NORETURN __attribute__ ((noreturn))
|
#define NORETURN __attribute__ ((noreturn))
|
||||||
#define PURE __attribute__ ((pure))
|
#define PURE __attribute__ ((pure))
|
||||||
|
@ -26,3 +28,42 @@ struct FarPtr {
|
||||||
DWORD offset { 0 };
|
DWORD offset { 0 };
|
||||||
WORD selector { 0 };
|
WORD selector { 0 };
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
class PhysicalAddress {
|
||||||
|
public:
|
||||||
|
PhysicalAddress() { }
|
||||||
|
explicit PhysicalAddress(dword address) : m_address(address) { }
|
||||||
|
|
||||||
|
dword get() const { return m_address; }
|
||||||
|
void set(dword address) { m_address = address; }
|
||||||
|
void mask(dword m) { m_address &= m; }
|
||||||
|
|
||||||
|
byte* asPtr() { return reinterpret_cast<byte*>(m_address); }
|
||||||
|
const byte* asPtr() const { return reinterpret_cast<const byte*>(m_address); }
|
||||||
|
|
||||||
|
dword pageBase() const { return m_address & 0xfffff000; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
dword m_address { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
class LinearAddress {
|
||||||
|
public:
|
||||||
|
LinearAddress() { }
|
||||||
|
explicit LinearAddress(dword address) : m_address(address) { }
|
||||||
|
|
||||||
|
LinearAddress offset(dword o) const { return LinearAddress(m_address + o); }
|
||||||
|
dword get() const { return m_address; }
|
||||||
|
void set(dword address) { m_address = address; }
|
||||||
|
void mask(dword m) { m_address &= m; }
|
||||||
|
|
||||||
|
bool operator==(const LinearAddress& other) const { return m_address == other.m_address; }
|
||||||
|
|
||||||
|
byte* asPtr() { return reinterpret_cast<byte*>(m_address); }
|
||||||
|
const byte* asPtr() const { return reinterpret_cast<const byte*>(m_address); }
|
||||||
|
|
||||||
|
dword pageBase() const { return m_address & 0xfffff000; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
dword m_address { 0 };
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue