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/processor/PageFaultHandler.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/Subsystem.h"
23 #include "pedigree/kernel/debugger/Debugger.h"
24 #include "pedigree/kernel/panic.h"
25 #include "pedigree/kernel/process/Process.h"
26 #include "pedigree/kernel/process/Scheduler.h"
27 #include "pedigree/kernel/process/Thread.h"
28 #include "pedigree/kernel/processor/InterruptManager.h"
29 #include "pedigree/kernel/processor/MemoryRegion.h"
30 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
31 #include "pedigree/kernel/processor/Processor.h"
32 #include "pedigree/kernel/processor/ProcessorInformation.h"
33 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
34 #include "pedigree/kernel/processor/state.h"
35 #include "pedigree/kernel/utilities/Iterator.h"
36 #include "pedigree/kernel/utilities/StaticString.h"
37 #include "pedigree/kernel/utilities/utility.h"
38 
40 
41 #define PAGE_FAULT_EXCEPTION 0x0E
42 #define PFE_PAGE_PRESENT 0x01
43 #define PFE_ATTEMPTED_WRITE 0x02
44 #define PFE_USER_MODE 0x04
45 #define PFE_RESERVED_BIT 0x08
46 #define PFE_INSTRUCTION_FETCH 0x10
47 
49 {
51 
52  return (IntManager.registerInterruptHandler(PAGE_FAULT_EXCEPTION, this));
53 }
54 
55 void PageFaultHandler::interrupt(size_t interruptNumber, InterruptState &state)
56 {
57  uintptr_t cr2, code;
58  asm volatile("mov %%cr2, %%rax" : "=a"(cr2));
59  code = state.m_Errorcode;
60 
61  uintptr_t page =
63 
64  // Check for copy-on-write.
65  VirtualAddressSpace &va = Processor::information().getVirtualAddressSpace();
66  if (va.isMapped(reinterpret_cast<void *>(page)))
67  {
68  physical_uintptr_t phys;
69  size_t flags;
70  va.getMapping(reinterpret_cast<void *>(page), phys, flags);
72  {
73 #ifdef SUPERDEBUG
74  NOTICE_NOLOCK(
76  .getCurrentThread()
77  ->getParent()
78  ->getId()
79  << " PageFaultHandler: copy-on-write for v=" << Hex << page);
80 #endif
81 
82  MemoryRegion tmpRegion("CoW Temporary Page");
83  if (!PhysicalMemoryManager::instance().allocateRegion(
84  tmpRegion, 1,
89  {
90  FATAL(
91  "PageFaultHandler: CoW temporary map() failed @" << Hex
92  << page);
93  return;
94  }
95 
96  // Remap faulting page
97  va.unmap(reinterpret_cast<void *>(page));
98  physical_uintptr_t p =
100  if (!p)
101  {
102  FATAL("PageFaultHandler: CoW OOM'd!");
103  return;
104  }
105 
107  flags &= ~VirtualAddressSpace::CopyOnWrite;
108  if (!va.map(p, reinterpret_cast<void *>(page), flags))
109  {
110  FATAL("PageFaultHandler: CoW new map() failed.");
111  return;
112  }
113 
114  // Perform the actual copy.
115  MemoryCopy(
116  reinterpret_cast<uint8_t *>(page),
117  reinterpret_cast<uint8_t *>(tmpRegion.virtualAddress()),
119 
120  // Done with the memory region now - ready to release any additional
121  // references too
122  tmpRegion.free();
123 
124  // Clean up old reference to memory (may free the page, if we were
125  // the last one to reference the CoW page)
127  return;
128  }
129  }
130 
133  if (!va.memIsInKernelHeap(reinterpret_cast<void *>(page)))
134  {
135  // Check our handler list.
136  for (List<MemoryTrapHandler *>::Iterator it = m_Handlers.begin();
137  it != m_Handlers.end(); it++)
138  {
139  if ((*it)->trap(state, cr2, code & PFE_ATTEMPTED_WRITE))
140  {
141  return;
142  }
143  }
144  }
145 
146  Thread *pThread = Processor::information().getCurrentThread();
147 
148  // Get PFE location and error code
149  static LargeStaticString sError;
150  sError.clear();
151  sError.append("Page Fault Exception at 0x");
152  sError.append(cr2, 16, 16, '0');
153  sError.append(", EIP 0x");
154  sError.append(state.getInstructionPointer(), 16, 16, '0');
155  sError.append(", error code 0x");
156  sError.append(code, 16, 8, '0');
157 
158  // Extract error code information
159  static LargeStaticString sCode;
160  sCode.clear();
161  sCode.append("Details: CPU=");
162  sCode.append(Processor::id());
163  if (pThread)
164  {
165  Process *pParent = pThread->getParent();
166  if (pParent)
167  {
168  sCode.append(" PID=");
169  sCode.append(pParent->getId());
170  }
171  sCode.append(" TID=");
172  sCode.append(pThread->getId());
173  }
174  sCode.append(" ");
175 
176  if (!(code & PFE_PAGE_PRESENT))
177  sCode.append("NOT ");
178  sCode.append("PRESENT | ");
179 
180  if (code & PFE_ATTEMPTED_WRITE)
181  sCode.append("WRITE | ");
182  else
183  sCode.append("READ | ");
184 
185  if (code & PFE_USER_MODE)
186  sCode.append("USER ");
187  else
188  sCode.append("KERNEL ");
189  sCode.append("MODE | ");
190 
191  if (code & PFE_RESERVED_BIT)
192  sCode.append("RESERVED BIT SET | ");
193  if (code & PFE_INSTRUCTION_FETCH)
194  sCode.append("FETCH |");
195 
196  // Ensure the log spinlock isn't going to die on us...
197  // Log::instance().m_Lock.release();
198 
199  ERROR(static_cast<const char *>(sError));
200  ERROR(static_cast<const char *>(sCode));
201 
202 // static LargeStaticString eCode;
203 #ifdef DEBUGGER
204  // Page faults in usermode are usually useless to debug in the debugger
205  // (some exceptions exist)
206  if (!(code & PFE_USER_MODE))
207  Debugger::instance().start(state, sError);
208 #endif
209 
210  Scheduler &scheduler = Scheduler::instance();
211  if (UNLIKELY(scheduler.getNumProcesses() == 0) || (pThread == nullptr))
212  {
213  // We are in the early stages of the boot process (no processes started)
214  panic(sError);
215  }
216  else
217  {
218  // Unrecoverable PFE in a process - Kill the process and yield
219  // Processor::information().getCurrentThread()->getParent()->kill();
220  Process *pProcess = pThread->getParent();
221  Subsystem *pSubsystem = pProcess->getSubsystem();
222  if (pSubsystem && !state.kernelMode())
223  pSubsystem->threadException(pThread, Subsystem::PageFault);
224  else
225  {
226  pProcess->kill();
227  }
228  }
229 }
230 
231 PageFaultHandler::PageFaultHandler() : m_Handlers()
232 {
233 }
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
virtual void unmap(void *virtualAddress)=0
This class manages how processes and threads are scheduled across processors.
Definition: Scheduler.h:44
static PhysicalMemoryManager & instance()
virtual void getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
size_t getId()
Definition: Process.h:108
static Debugger & instance()
Definition: Debugger.h:48
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
virtual bool isMapped(void *virtualAddress)=0
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
Handles interrupts and interrupt registrations from kernel components.
virtual void threadException(Thread *pThread, ExceptionType eType)
Definition: Subsystem.cc:35
static ProcessorInformation & information()
Definition: Processor.cc:45
virtual void interrupt(size_t interruptNumber, InterruptState &state)
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
Definition: List.h:64
virtual bool memIsInKernelHeap(void *pMem)=0
Special memory entity in the kernel&#39;s virtual address space.
Definition: MemoryRegion.h:35
Definition: Log.h:136
size_t getNumProcesses()
Definition: Scheduler.cc:140
Iterator begin()
Definition: List.h:123
static Scheduler & instance()
Definition: Scheduler.h:48
Process * getParent() const
Definition: Thread.h:181
static ProcessorId id()
Definition: Processor.cc:40
Definition: Thread.h:54
PageFaultHandler() INITIALISATION_ONLY
#define ERROR(text)
Definition: Log.h:82
virtual void freePage(physical_uintptr_t page)=0
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
size_t getId()
Definition: Thread.h:210
void kill() NORETURN
Definition: Process.cc:239
#define FATAL(text)
Definition: Log.h:89
static InterruptManager & instance()
Iterator end()
Definition: List.h:135
static EXPORTED_PUBLIC PageFaultHandler m_Instance