The Pedigree Project  0.1
x86/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 
29 
30 #define PAGE_FAULT_EXCEPTION 0x0E
31 #define PFE_PAGE_PRESENT 0x01
32 #define PFE_ATTEMPTED_WRITE 0x02
33 #define PFE_USER_MODE 0x04
34 #define PFE_RESERVED_BIT 0x08
35 #define PFE_INSTRUCTION_FETCH 0x10
36 
38 {
40 
41  return (IntManager.registerInterruptHandler(PAGE_FAULT_EXCEPTION, this));
42 }
43 
44 void PageFaultHandler::interrupt(size_t interruptNumber, InterruptState &state)
45 {
46  uint32_t cr2, code;
47  asm volatile("mov %%cr2, %%eax" : "=a"(cr2));
48  code = state.m_Errorcode;
49 
50  uintptr_t page =
52 
53  // Check for copy-on-write.
54  VirtualAddressSpace &va = Processor::information().getVirtualAddressSpace();
55  if (va.isMapped(reinterpret_cast<void *>(page)))
56  {
57  physical_uintptr_t phys;
58  size_t flags;
59  va.getMapping(reinterpret_cast<void *>(page), phys, flags);
61  {
62 #ifdef SUPERDEBUG
63  NOTICE_NOLOCK(
65  .getCurrentThread()
66  ->getParent()
67  ->getId()
68  << " PageFaultHandler: copy-on-write for v=" << page);
69 #endif
70 
71  // Save current page content
72  static uint8_t buffer
73  [0x1000]; // PhysicalMemoryManager::instance().getPageSize()];
74  MemoryCopy(
75  buffer, reinterpret_cast<uint8_t *>(page),
76  PhysicalMemoryManager::instance().getPageSize());
77 
78  // Now that we've saved the page content, we can make a new physical
79  // page and map it.
80  physical_uintptr_t p =
82  if (!p)
83  {
84  FATAL("PageFaultHandler: Out of memory!");
85  return;
86  }
87 
88  // Remove the old mapping and map in the new page, with similar
89  // flags.
90  va.unmap(reinterpret_cast<void *>(page));
91 
93  flags &= ~VirtualAddressSpace::CopyOnWrite;
94  if (!va.map(p, reinterpret_cast<void *>(page), flags))
95  {
96  FATAL("PageFaultHandler: map() failed.");
97  return;
98  }
99 
100  // Restore the contents of the page to the new mapping.
101  MemoryCopy(
102  reinterpret_cast<uint8_t *>(page), buffer,
103  PhysicalMemoryManager::instance().getPageSize());
104 
105  // Clean up old reference to memory (may free the page, if we were
106  // the last one to reference the CoW page)
108  return;
109  }
110  }
111 
112  if (cr2 < reinterpret_cast<uintptr_t>(KERNEL_SPACE_START))
113  {
114  // Check our handler list.
115  for (List<MemoryTrapHandler *>::Iterator it = m_Handlers.begin();
116  it != m_Handlers.end(); it++)
117  {
118  if ((*it)->trap(cr2, code & PFE_ATTEMPTED_WRITE))
119  {
120  return;
121  }
122  }
123  }
124 
125  // Get PFE location and error code
126  static LargeStaticString sError;
127  sError.clear();
128  sError.append("Page Fault Exception at 0x");
129  sError.append(cr2, 16, 8, '0');
130  sError.append(", error code 0x");
131  sError.append(code, 16, 8, '0');
132  sError.append(", EIP 0x");
133  sError.append(state.getInstructionPointer(), 16, 8, '0');
134 
135  // Extract error code information
136  static LargeStaticString sCode;
137  sCode.clear();
138  sCode.append("Details: PID=");
139  sCode.append(
140  Processor::information().getCurrentThread()->getParent()->getId());
141  sCode.append(" ");
142 
143  if (!(code & PFE_PAGE_PRESENT))
144  sCode.append("NOT ");
145  sCode.append("PRESENT | ");
146 
147  if (code & PFE_ATTEMPTED_WRITE)
148  sCode.append("WRITE | ");
149  else
150  sCode.append("READ | ");
151 
152  if (code & PFE_USER_MODE)
153  sCode.append("USER ");
154  else
155  sCode.append("KERNEL ");
156  sCode.append("MODE | ");
157 
158  if (code & PFE_RESERVED_BIT)
159  sCode.append("RESERVED BIT SET | ");
160  if (code & PFE_INSTRUCTION_FETCH)
161  sCode.append("FETCH |");
162 
163  // Ensure the log spinlock isn't going to die on us...
164  // Log::instance().m_Lock.release();
165 
166  ERROR_NOLOCK(static_cast<const char *>(sError));
167  ERROR_NOLOCK(static_cast<const char *>(sCode));
168 
169 // static LargeStaticString eCode;
170 #ifdef DEBUGGER
171  uintptr_t physAddr = 0, flags = 0;
172  if (va.isMapped(reinterpret_cast<void *>(state.getInstructionPointer())))
173  va.getMapping(
174  reinterpret_cast<void *>(state.getInstructionPointer()), physAddr,
175  flags);
176 
177  // Page faults in usermode are usually useless to debug in the debugger
178  // (some exceptions exist)
179  if (!(code & PFE_USER_MODE))
180  Debugger::instance().start(state, sError);
181 #endif
182 
183  Scheduler &scheduler = Scheduler::instance();
184  if (UNLIKELY(scheduler.getNumProcesses() == 0))
185  {
186  // We are in the early stages of the boot process (no processes
187  // started)
188  panic(sError);
189  }
190  else
191  {
192  // Unrecoverable PFE in a process - Kill the process and yield
193  // Processor::information().getCurrentThread()->getParent()->kill();
194  Thread *pThread = Processor::information().getCurrentThread();
195  Process *pProcess = pThread->getParent();
196  Subsystem *pSubsystem = pProcess->getSubsystem();
197  if (pSubsystem)
198  pSubsystem->threadException(pThread, Subsystem::PageFault);
199  else
200  pProcess->kill();
201 
202  // kill member function also calls yield(), so shouldn't get here.
203  for (;;)
204  ;
205  }
206 
207  // Currently, no code paths return from a PFE.
208 }
209 
210 PageFaultHandler::PageFaultHandler() : m_Handlers()
211 {
212 }
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
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
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
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()
Iterator end()
Definition: List.h:135
static EXPORTED_PUBLIC PageFaultHandler m_Instance