The Pedigree Project 0.1
x64/PageFaultHandler.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/Subsystem.h"
22#include "pedigree/kernel/debugger/Debugger.h"
23#include "pedigree/kernel/panic.h"
24#include "pedigree/kernel/process/Process.h"
25#include "pedigree/kernel/process/Scheduler.h"
26#include "pedigree/kernel/process/Thread.h"
27#include "pedigree/kernel/processor/InterruptManager.h"
28#include "pedigree/kernel/processor/PageFaultHandler.h"
29#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
30#include "pedigree/kernel/processor/Processor.h"
31#include "pedigree/kernel/processor/ProcessorInformation.h"
32#include "pedigree/kernel/processor/VirtualAddressSpace.h"
33#include "pedigree/kernel/processor/state.h"
34#include "pedigree/kernel/utilities/Iterator.h"
35#include "pedigree/kernel/utilities/StaticString.h"
36#include "pedigree/kernel/utilities/utility.h"
37
39
40#define PAGE_FAULT_EXCEPTION 0x0E
41#define PFE_PAGE_PRESENT 0x01
42#define PFE_ATTEMPTED_WRITE 0x02
43#define PFE_USER_MODE 0x04
44#define PFE_RESERVED_BIT 0x08
45#define PFE_INSTRUCTION_FETCH 0x10
46#define PFE_PROTECTION_KEY 0x20
47#define PFE_SHADOW_STACK 0x40
48
51
52 return (IntManager.registerInterruptHandler(PAGE_FAULT_EXCEPTION, this));
53}
54
55void PageFaultHandler::interrupt(size_t interruptNumber, InterruptState& state) {
56 uintptr_t cr2, code;
57 asm volatile("mov %%cr2, %%rax" : "=a"(cr2));
58 code = state.m_Errorcode;
59
60 uintptr_t page = cr2 & ~(PhysicalMemoryManager::instance().getPageSize() - 1);
61
62 VirtualAddressSpace& va = Processor::information().getVirtualAddressSpace();
63 const bool copyOnWriteFault =
64 (code & (PFE_PAGE_PRESENT | PFE_ATTEMPTED_WRITE)) ==
65 (PFE_PAGE_PRESENT | PFE_ATTEMPTED_WRITE) &&
66 !(code & (PFE_RESERVED_BIT | PFE_INSTRUCTION_FETCH | PFE_PROTECTION_KEY | PFE_SHADOW_STACK));
67 if (copyOnWriteFault &&
68 va.handleCopyOnWriteFault(reinterpret_cast<void*>(page), (code & PFE_USER_MODE) != 0)) {
69 return;
70 }
71
74 if (!va.memIsInKernelHeap(reinterpret_cast<void*>(page))) {
75 if (dispatchHandlers(state, cr2, code & PFE_ATTEMPTED_WRITE, code & PFE_PAGE_PRESENT)) {
76 return;
77 }
78 }
79
80 Thread* pThread = Processor::information().getCurrentThread();
81
82 if (pThread && !state.kernelMode()) {
83 Process* process = pThread->getParent();
84 if (process && process->getSubsystem()) {
85 pThread->deferSubsystemException(static_cast<size_t>(Subsystem::PageFault), cr2, code);
86 return;
87 }
88 }
89
90 // Get PFE location and error code
91 static LargeStaticString sError;
92 sError.clear();
93 sError.append("Page Fault Exception at 0x");
94 sError.append(cr2, 16, 16, '0');
95 sError.append(", EIP 0x");
96 sError.append(state.getInstructionPointer(), 16, 16, '0');
97 sError.append(", error code 0x");
98 sError.append(code, 16, 8, '0');
99
100 // Extract error code information
101 static LargeStaticString sCode;
102 sCode.clear();
103 sCode.append("Details: CPU=");
104 sCode.append(Processor::id());
105 if (pThread) {
106 Process* pParent = pThread->getParent();
107 if (pParent) {
108 sCode.append(" PID=");
109 sCode.append(pParent->getId());
110 }
111 sCode.append(" TID=");
112 sCode.append(pThread->getId());
113 }
114 sCode.append(" ");
115
116 if (!(code & PFE_PAGE_PRESENT))
117 sCode.append("NOT ");
118 sCode.append("PRESENT | ");
119
120 if (code & PFE_ATTEMPTED_WRITE)
121 sCode.append("WRITE | ");
122 else
123 sCode.append("READ | ");
124
125 if (code & PFE_USER_MODE)
126 sCode.append("USER ");
127 else
128 sCode.append("KERNEL ");
129 sCode.append("MODE | ");
130
131 if (code & PFE_RESERVED_BIT)
132 sCode.append("RESERVED BIT SET | ");
133 if (code & PFE_INSTRUCTION_FETCH)
134 sCode.append("FETCH |");
135
136 // Ensure the log spinlock isn't going to die on us...
137 // Log::instance().m_Lock.release();
138
139 ERROR(static_cast<const char*>(sError));
140 ERROR(static_cast<const char*>(sCode));
141
142// static LargeStaticString eCode;
143#if DEBUGGER
144 // Page faults in usermode are usually useless to debug in the debugger
145 // (some exceptions exist)
146 if (!(code & PFE_USER_MODE))
147 Debugger::instance().start(state, sError);
148#endif
149
150 Scheduler& scheduler = Scheduler::instance();
151 if (UNLIKELY(scheduler.getNumProcesses() == 0) || (pThread == nullptr)) {
152 // We are in the early stages of the boot process (no processes started)
153 panic(sError);
154 } else {
155 // Unrecoverable PFE in a process - Kill the process and yield
156 // Processor::information().getCurrentThread()->getParent()->kill();
157 Process* pProcess = pThread->getParent();
158 Subsystem* pSubsystem = pProcess->getSubsystem();
159 if (!pSubsystem || state.kernelMode()) {
160 pProcess->kill();
161 }
162 }
163}
void start(InterruptState &state, LargeStaticString &description)
Definition Debugger.cc:118
static Debugger & instance()
Definition Debugger.h:47
Handles interrupts and interrupt registrations from kernel components.
static EXPORTED_PUBLIC InterruptManager & instance()
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
static EXPORTED_PUBLIC PageFaultHandler m_Instance
virtual void interrupt(size_t interruptNumber, InterruptState &state)
static PhysicalMemoryManager & instance()
size_t getId()
Definition Process.h:462
void kill() NORETURN
Definition Process.cc:1860
static ProcessorId id()
static ProcessorInformation & information()
This class manages how processes and threads are scheduled across processors.
Definition Scheduler.h:50
static Scheduler & instance()
Definition Scheduler.h:96
size_t getNumProcesses()
Definition Scheduler.cc:266
bool deferSubsystemException(size_t type, uintptr_t faultAddress, uintptr_t errorCode)
Definition Thread.cc:3597
Process * getParent() const
Definition Thread.h:325
size_t getId()
Definition Thread.h:450
virtual bool handleCopyOnWriteFault(void *virtualAddress, bool userMode)=0
virtual bool memIsInKernelHeap(void *pMem)=0
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:117