The Pedigree Project  0.1
hosted/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 "VirtualAddressSpace.h"
22 #include "pedigree/kernel/Log.h"
23 #include "pedigree/kernel/debugger/Debugger.h"
24 #include "pedigree/kernel/panic.h"
25 #include "pedigree/kernel/process/Scheduler.h"
26 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
27 
28 namespace __pedigree_hosted
29 {
30 };
31 using namespace __pedigree_hosted;
32 
33 #include <signal.h>
34 #include <ucontext.h>
35 
36 #define SUPERDEBUG
37 
39 
41 {
43  bool r1 = IntManager.registerInterruptHandler(SIGSEGV, this);
44  bool r2 = IntManager.registerInterruptHandler(SIGBUS, this);
45 
46  return r1 && r2;
47 }
48 
49 void PageFaultHandler::interrupt(size_t interruptNumber, InterruptState &state)
50 {
51  siginfo_t *info = reinterpret_cast<siginfo_t *>(state.getRegister(1));
52 
53  uintptr_t page = reinterpret_cast<uintptr_t>(page_align(info->si_addr));
54  uintptr_t unaligned_page = reinterpret_cast<uintptr_t>(info->si_addr);
55  uintptr_t code = info->si_code;
56 
57  VirtualAddressSpace &va = Processor::information().getVirtualAddressSpace();
58  if (va.isMapped(reinterpret_cast<void *>(page)))
59  {
60  physical_uintptr_t phys;
61  size_t flags;
62  va.getMapping(reinterpret_cast<void *>(page), phys, flags);
64  {
65 #ifdef SUPERDEBUG
66  NOTICE_NOLOCK(
68  .getCurrentThread()
69  ->getParent()
70  ->getId()
71  << " PageFaultHandler: copy-on-write for v=" << page);
72 #endif
73 
74  Process *pProcess =
75  Processor::information().getCurrentThread()->getParent();
76  size_t pageSz = PhysicalMemoryManager::instance().getPageSize();
77 
78  // Get a temporary page in which we can store the current mapping
79  // for copy.
80  uintptr_t tempAddr = 0;
81  pProcess->getSpaceAllocator().allocate(pageSz, tempAddr);
82 
83  // Map temporary page to the old page.
84  if (!va.map(
85  phys, reinterpret_cast<void *>(tempAddr),
87  {
88  FATAL("PageFaultHandler: CoW temporary map() failed");
89  return;
90  }
91 
92  // OK, we can now unmap the old page - we hold a valid temporary
93  // mapping.
94  va.unmap(reinterpret_cast<void *>(page));
95 
96  // Allocate new page for the new memory region.
97  physical_uintptr_t p =
99  if (!p)
100  {
101  FATAL("PageFaultHandler: CoW OOM'd!");
102  return;
103  }
104 
105  // Map in the new page, making sure to mark it not CoW.
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 *>(tempAddr), pageSz);
118 
119  // Release temporary page.
120  va.unmap(reinterpret_cast<void *>(tempAddr));
121  pProcess->getSpaceAllocator().free(tempAddr, pageSz);
122 
123  // Clean up old reference to memory (may free the page, if we were
124  // the last one to reference the CoW page)
126  return;
127  }
128  }
129 
130  if (page < reinterpret_cast<uintptr_t>(KERNEL_SPACE_START))
131  {
132  // Check our handler list.
133  for (List<MemoryTrapHandler *>::Iterator it = m_Handlers.begin();
134  it != m_Handlers.end(); it++)
135  {
136  if ((*it)->trap(page, code == SEGV_ACCERR))
137  {
138  return;
139  }
140  }
141  }
142 
143  // Extra information comes from the ucontext_t structure passed to the
144  // signal handler (SIGSEGV).
145  uintptr_t ucontext_loc = state.getRegister(2);
146  ucontext_t *ctx = reinterpret_cast<ucontext_t *>(ucontext_loc);
147  state.setInstructionPointer(ctx->uc_mcontext.gregs[REG_RIP]);
148  state.setStackPointer(ctx->uc_mcontext.gregs[REG_RSP]);
149  state.setBasePointer(ctx->uc_mcontext.gregs[REG_RBP]);
150 
151  // Get PFE location and error code
152  static LargeStaticString sError;
153  sError.clear();
154  sError.append("Page Fault Exception at 0x");
155  sError.append(unaligned_page, 16, 8, '0');
156  sError.append(", error code 0x");
157  sError.append(code, 16, 8, '0');
158  sError.append(", EIP 0x");
159  sError.append(state.getInstructionPointer(), 16, 8, '0');
160 
161  // Extract error code information
162  static LargeStaticString sCode;
163  sCode.clear();
164  sCode.append("Details: PID=");
165  sCode.append(
166  Processor::information().getCurrentThread()->getParent()->getId());
167  sCode.append(" ");
168 
169  if (code == SEGV_MAPERR)
170  sCode.append("NOT ");
171  sCode.append("PRESENT | ");
172 
173  ERROR(static_cast<const char *>(sError));
174  ERROR(static_cast<const char *>(sCode));
175 
176 #ifdef DEBUGGER
177  if (state.kernelMode())
178  Debugger::instance().start(state, sError);
179 #endif
180 
181  Scheduler &scheduler = Scheduler::instance();
182  if (UNLIKELY(scheduler.getNumProcesses() == 0))
183  {
184  // We are in the early stages of the boot process (no processes
185  // started)
186  panic(sError);
187  }
188  else
189  {
190  // Unrecoverable PFE in a process - Kill the process and yield
191  // Processor::information().getCurrentThread()->getParent()->kill();
192  Thread *pThread = Processor::information().getCurrentThread();
193  Process *pProcess = pThread->getParent();
194  Subsystem *pSubsystem = pProcess->getSubsystem();
195  if (pSubsystem)
196  pSubsystem->threadException(pThread, Subsystem::PageFault);
197  else
198  {
199  pProcess->kill();
200 
201  // kill member function also calls yield(), so shouldn't get here.
202  for (;;)
203  ;
204  }
205  }
206 }
207 
208 PageFaultHandler::PageFaultHandler() : m_Handlers()
209 {
210 }
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
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
void free(T address, T length, bool merge=true)
Definition: RangeList.h:163
static ProcessorInformation & information()
Definition: Processor.cc:45
bool allocate(T length, T &address)
Definition: RangeList.h:222
virtual void interrupt(size_t interruptNumber, InterruptState &state)
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
Definition: List.h:64
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
Definition: Thread.h:54
PageFaultHandler() INITIALISATION_ONLY
EXPORTED_PUBLIC void * page_align(void *p) PURE
Definition: utility.cc:28
#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
void kill() NORETURN
Definition: Process.cc:239
#define FATAL(text)
Definition: Log.h:89
static InterruptManager & instance()
MemoryAllocator & getSpaceAllocator()
Definition: Process.h:178
static EXPORTED_PUBLIC PageFaultHandler m_Instance