ReactOS  0.4.14-dev-49-gfb4591c
pgflt.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1998-2001 Klaus P. Gerlicher
4 
5 Module Name:
6 
7  pgflt.c
8 
9 Abstract:
10 
11  page fault handling on x86
12 
13 Environment:
14 
15  Kernel mode only
16 
17 Author:
18 
19  Klaus P. Gerlicher
20 
21 Revision History:
22 
23  25-Nov-1999: created
24  15-Nov-2000: general cleanup of source files
25 
26 Copyright notice:
27 
28  This file may be distributed under the terms of the GNU Public License.
29 
30 --*/
31 
33 // INCLUDES
35 #include "remods.h"
36 
37 #include "precomp.h"
38 
40 // GLOBALS
42 
43 char tempPageFault[1024];
44 extern void NewInt31Handler(void);
45 
49 static ULONG PCR_SEL = PCR_SELECTOR;
50 static ULONG OLD_PCR;
51 
53 // FUNCTIONS
55 
56 //*************************************************************************
57 // HandleInDebuggerFault()
58 //
59 //*************************************************************************
61 {
62  PEPROCESS tsk;
63 
64  ENTER_FUNC();
65 
66  DPRINT((0,"HandleInDebuggerFault(): ###### page fault @ %.8X while inside debugger, eip: %x\n",address, ptr->eip));
67 
68  // fault in this page fault handler
70  {
71  DPRINT((0,"HandleInDebuggerFault(): ###### page fault @ %.8X while in page fault handler\n",address));
72 
73  DPRINT((0,"!!! machine is halted !!!\n"));
74  __asm__ __volatile__ ("hlt");
75 
76  LEAVE_FUNC();
77  return 0;
78  }
79 
81 
82  // when we come here from DebuggerShell() we live on a different stack
83  // so the current task is different as well
84  tsk = IoGetCurrentProcess();
85 
86  DPRINT((0,"%.8X (%.4X:%.8X %.8X %s %s %s task=%.8X )\n",
87  address,
88  ptr->cs,
89  ptr->eip,
90  ptr->eflags,
91  (ptr->error_code&1)?"PLP":"NP",
92  (ptr->error_code&2)?"WRITE":"READ",
93  (ptr->error_code&4)?"USER-MODE":"KERNEL-MODE",
94  (ULONG)tsk));
95 
96  if(!bInPrintk)
97  {
98  DPRINT((0,"HandleInDebuggerFault(): unexpected pagefault in command handler!\n",address));
99  }
100  else
101  {
102  DPRINT((0,"HandleInDebuggerFault(): unexpected pagefault in command handler while in PrintkCallback()!\n",address));
103  }
104 
105  if(tsk)
106  {
107  PULONG pPGD;
108  PULONG pPTE;
109 
110  pPGD = ADDR_TO_PDE(address);
111 
112  DPRINT((0,"PGD for %.8X @ %.8X = %.8X\n",address,(ULONG)pPGD,(ULONG)(*pPGD) ));
113 
114  if(pPGD && (*pPGD)&_PAGE_PRESENT)
115  {
116  // not large page
117  if(!((*pPGD)&_PAGE_4M))
118  {
119  pPTE = ADDR_TO_PTE(address);
120  if(pPTE)
121  {
122  DPRINT((0,"PTE for %.8X @ %.8X = %.8X\n",address,(ULONG)pPTE,(ULONG)(*pPTE) ));
123  }
124  }
125  }
126  }
127 
129 
130  DPRINT((0,"!!! machine is halted !!!\n"));
131  __asm__ __volatile__ ("hlt");
132 
133  LEAVE_FUNC();
134 
135  return 2;
136 }
137 
138 //*************************************************************************
139 // HandlePageFault()
140 //
141 // returns:
142 // 0 = let the system handle it
143 // 1 = call DebuggerShell()
144 // 2 = FATAL error inside debugger
145 //*************************************************************************
147 {
148  PVOID address;
149  PEPROCESS tsk, tsk1;
150  PMADDRESS_SPACE vma;
151  PLIST_ENTRY current_entry;
153  ULONG value;
154  PKTHREAD CurrentThread;
155  PETHREAD CurrentEThread;
156 
157  // get linear address of page fault
158  __asm__ __volatile__("movl %%cr2,%0"
159  :"=r" (address));
160 
161  DPRINT((0,"\nPageFault: bInDebShell: %d, error: %d, addr: %x\n", bInDebuggerShell, ptr->error_code, address));
162 
163  // there's something terribly wrong if we get a fault in our command handler
164  if(bInDebuggerShell)
165  {
166  DPRINT((0,"return handleindebuggerfault\n"));
168  }
169 
171  // remember error code so we can push it back on the stack
172  error_code = ptr->error_code;
173 
174  //ei Check IRQL here!!!
175 /*
176  if(in_interrupt())
177  {
178  Print(OUTPUT_WINDOW,"pICE: system is currently processing an interrupt!\n");
179  return 1;
180  }
181 */
182  // current process
183  tsk = IoGetCurrentProcess();
184  DPRINT((0,"tsk: %x\t", tsk));
185  if( !tsk || !(IsAddressValid((ULONG)tsk))){
186  DPRINT((0,"tsk address not valid: tsk: %x\n", tsk));
187  return 0;
188  }
189 
190  // lookup VMA for this address
191  if( (ULONG)address > KERNEL_BASE )
192  vma = my_init_mm; // use kernel mem area for kernel addresses
193  else vma = &(tsk->AddressSpace); // otherwise, use user memory area
194 
195  if( !vma ){
196  DPRINT((0,"vma not valid: vma: %x\n", vma));
197  return 0;
198  }
199 
200  current_entry = vma->MAreaListHead.Flink;
201  ASSERT(current_entry);
202  DPRINT((0,"vma: %x, current_entry: %x, kernel arena: %x\n", vma, current_entry, my_init_mm));
203  while(current_entry != &vma->MAreaListHead)
204  {
205  ASSERT(current_entry);
206  ASSERT(IsAddressValid((ULONG)current_entry));
207  current = CONTAINING_RECORD(current_entry,
208  MEMORY_AREA,
209  Entry);
210 
211 
212  if( (address >= current->BaseAddress) && (address <= current->BaseAddress + current->Length ))
213  {
214  DPRINT((0,"address: %x %x - %x Attrib: %x, Type: %x\n", address, current->BaseAddress, current->BaseAddress + current->Length, current->Attributes, current->Type));
215  //page not present
216  if( !(error_code & 1) ){
217  //check it is in pageable area
218  if( current->Type == MEMORY_AREA_SECTION_VIEW ||
219  current->Type == MEMORY_AREA_VIRTUAL_MEMORY ||
220  current->Type == MEMORY_AREA_PAGED_POOL ||
221  current->Type == MEMORY_AREA_SHARED_DATA
222  ){
223  //ei too much output Print(OUTPUT_WINDOW,"pICE: VMA Pageable Section.\n");
224  //ei DPRINT((0,"return 0 1\n"));
225  return 0; //let the system handle this
226  }
227  Print(OUTPUT_WINDOW,"pICE: VMA Page not present in non-pageable Section!\n");
228  //ei DPRINT((0,"Type: currenttype: %x return 1 2\n", current->Type));
229  return 0;
230  }
231  else{ //access violation
232 
233  if( error_code & 4 )
234  { //user mode
235  if( (ULONG)address >= KERNEL_BASE )
236  {
237  Print(OUTPUT_WINDOW,"pICE: User mode program trying to access kernel memory!\n");
238  //DPRINT((0,"return 0 3\n"));
239  return 1;
240  }
241  //DPRINT((0,"return 0 4\n"));
242  return 0;
243  }
244  /*
245  if(error_code & 2)
246  {
247  //on write
248  if(!(current->Attributes & PAGE_READONLY))
249  {
250  Print(OUTPUT_WINDOW,"pICE: virtual memory arena is not writeable!\n");
251  return 1;
252  }
253  }
254  // READ ACCESS
255  else
256  {
257  // test EXT bit in error code
258  if (error_code & 1)
259  {
260  Print(OUTPUT_WINDOW,"pICE: page-level protection fault!\n");
261  return 1;
262  }
263  //
264  */
265  /*
266  if (!(current->Attributes & PAGE_EXECUTE_READ))
267  {
268  Print(OUTPUT_WINDOW,"pICE: VMA is not readable!\n");
269  return 1;
270  }
271  */
272 
273  // let the system handle it
274  //DPRINT((0,"return 0 5\n"));
275  return 0;
276  }
277  }
278  current_entry = current_entry->Flink;
279  }
280 
281  Print(OUTPUT_WINDOW,"pICE: no virtual memory arena at this address!\n");
282  DPRINT((0,"return 0 6\n"));
283  return 1;
284 
285  // let the system handle it
286 // return 0;
287 }
288 
289 //*************************************************************************
290 // NewIntEHandler()
291 //
292 //*************************************************************************
293 __asm__ ("\n\t \
294 NewIntEHandler:\n\t \
295  pushfl\n\t \
296  cli\n\t \
297  cld\n\t \
298  pushal\n\t \
299  pushl %ds\n\t \
300 \n\t \
301  // setup default data selectors\n\t \
302  movw %ss,%ax\n\t \
303  movw %ax,%ds\n\t \
304 \n\t \
305  /*\n\t \
306  * Load the PCR selector.\n\t \
307  */\n\t \
308  movl %fs, %eax\n\t \
309  movl %eax, _OLD_PCR\n\t \
310  movl _PCR_SEL, %eax\n\t \
311  movl %eax, %fs\n\t \
312 \n\t \
313  // get frame ptr\n\t \
314  lea 40(%esp),%eax\n\t \
315  pushl %eax\n\t \
316  call _HandlePageFault\n\t \
317  addl $4,%esp\n\t \
318 \n\t \
319  pushl %eax\n\t \
320  movl _OLD_PCR, %eax\n\t \
321  movl %eax, %fs\n\t \
322  popl %eax\n\t \
323 \n\t \
324  cmpl $0,%eax\n\t \
325  je call_old_inte_handler\n\t \
326 \n\t \
327  cmpl $2,%eax\n\t \
328  je call_handler_unknown_reason\n\t \
329 \n\t \
330  popl %ds\n\t \
331  popal\n\t \
332  popfl\n\t \
333  // remove error code. will be restored later when we call\n\t \
334  // original handler again.\n\t \
335  addl $4,%esp\n\t \
336  // call debugger loop\n\t \
337  pushl $" STR(REASON_PAGEFAULT) "\n\t \
338  jmp NewInt31Handler\n\t \
339 \n\t \
340 call_old_inte_handler:\n\t \
341  popl %ds\n\t \
342  popal\n\t \
343  popfl\n\t \
344  // chain to old handler\n\t \
345  .byte 0x2e\n\t \
346  jmp *_OldIntEHandler\n\t \
347 \n\t \
348 call_handler_unknown_reason:\n\t \
349  popl %ds\n\t \
350  popal\n\t \
351  popfl\n\t \
352  // remove error code. will be restored later when we call\n\t \
353  // original handler again.\n\t \
354  addl $4,%esp\n\t \
355  // call debugger loop\n\t \
356  pushl $" STR(REASON_INTERNAL_ERROR) "\n\t \
357  jmp NewInt31Handler\n\t \
358  ");
359 
360 
361 //*************************************************************************
362 // InstallIntEHook()
363 //
364 //*************************************************************************
365 void InstallIntEHook(void)
366 {
367  ULONG LocalIntEHandler;
368 
369  ENTER_FUNC();
370 
371  MaskIrqs();
372  if(!OldIntEHandler)
373  {
374  __asm__ __volatile__("mov $NewIntEHandler,%0"
375  :"=r" (LocalIntEHandler)
376  :
377  :"eax");
378  OldIntEHandler=SetGlobalInt(0x0E,(ULONG)LocalIntEHandler);
379  }
380  UnmaskIrqs();
381  DPRINT((0,"OldIntE @ %x\n", OldIntEHandler));
382  LEAVE_FUNC();
383 }
384 
385 //*************************************************************************
386 // DeInstallIntEHook()
387 //
388 //*************************************************************************
390 {
391  ENTER_FUNC();
392 
393  MaskIrqs();
394  if(OldIntEHandler)
395  {
397  OldIntEHandler=0;
398  }
399  UnmaskIrqs();
400 
401  LEAVE_FUNC();
402 }
ULONG error_code
Definition: pgflt.c:47
volatile BOOLEAN bInDebuggerShell
Definition: shell.c:79
#define TRUE
Definition: types.h:120
#define _PAGE_4M
Definition: utils.h:268
ULONG ulRealStackPtr
Definition: shell.c:82
BOOLEAN bInPrintk
Definition: output.c:54
ULONG OldIntEHandler
Definition: pgflt.c:46
ULONG SetGlobalInt(ULONG dwInt, ULONG NewIntHandler)
Definition: hooks.c:95
#define LEAVE_FUNC()
Definition: debug.h:43
void Print(USHORT Window, LPSTR p)
Definition: hardware.c:797
#define STR(x)
Definition: utils.h:34
char tempPageFault[1024]
Definition: pgflt.c:43
#define REASON_INTERNAL_ERROR
Definition: shell.h:79
PMADDRESS_SPACE my_init_mm
Definition: utils.h:300
#define ADDR_TO_PTE(v)
Definition: parse.h:181
static PVOID ptr
Definition: dispmode.c:27
unsigned char BOOLEAN
void DPRINT(...)
Definition: polytest.cpp:61
void MaskIrqs(void)
Definition: hooks.c:68
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:71
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
#define _PAGE_PRESENT
Definition: compat.h:67
void IntelStackWalk(ULONG pc, ULONG ebp, ULONG esp)
Definition: utils.c:1530
PEPROCESS NTAPI IoGetCurrentProcess(VOID)
Definition: util.c:139
BOOLEAN bInPageFaultHandler
Definition: pgflt.c:48
GLuint address
Definition: glext.h:9393
void NewInt31Handler(void)
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
static ULONG PCR_SEL
Definition: pgflt.c:49
Definition: typedefs.h:117
void InstallIntEHook(void)
Definition: pgflt.c:365
GLsizei const GLfloat * value
Definition: glext.h:6069
#define ADDR_TO_PDE(v)
Definition: parse.h:179
ULONG HandleInDebuggerFault(FRAME *ptr, ULONG address)
Definition: pgflt.c:60
ULONG CurrentEBP
Definition: shell.c:115
unsigned int * PULONG
Definition: retypes.h:1
ULONG HandlePageFault(FRAME *ptr)
Definition: pgflt.c:146
static ULONG OLD_PCR
Definition: pgflt.c:50
unsigned int ULONG
Definition: retypes.h:1
#define ENTER_FUNC()
Definition: debug.h:42
void DeInstallIntEHook(void)
Definition: pgflt.c:389
__asm__("\n\t \ NewIntEHandler:\n\t \ pushfl\n\t \ cli\n\t \ cld\n\t \ pushal\n\t \ pushl %ds\n\t \ \n\t \ // setup default data selectors\n\t \ movw %ss,%ax\n\t \ movw %ax,%ds\n\t \ \n\t \ /*\n\t \ * Load the PCR selector.\n\t \ */\n\t \ movl %fs, %eax\n\t \ movl %eax, _OLD_PCR\n\t \ movl _PCR_SEL, %eax\n\t \ movl %eax, %fs\n\t \ \n\t \ // get frame ptr\n\t \ lea 40(%esp),%eax\n\t \ pushl %eax\n\t \ call _HandlePageFault\n\t \ addl $4,%esp\n\t \ \n\t \ pushl %eax\n\t \ movl _OLD_PCR, %eax\n\t \ movl %eax, %fs\n\t \ popl %eax\n\t \ \n\t \ cmpl $0,%eax\n\t \ je call_old_inte_handler\n\t \ \n\t \ cmpl $2,%eax\n\t \ je call_handler_unknown_reason\n\t \ \n\t \ popl %ds\n\t \ popal\n\t \ popfl\n\t \ // remove error code. will be restored later when we call\n\t \ // original handler again.\n\t \ addl $4,%esp\n\t \ // call debugger loop\n\t \ pushl $" STR(REASON_PAGEFAULT) "\n\t \ jmp NewInt31Handler\n\t \ \n\t \ call_old_inte_handler:\n\t \ popl %ds\n\t \ popal\n\t \ popfl\n\t \ // chain to old handler\n\t \ .byte 0x2e\n\t \ jmp *_OldIntEHandler\n\t \ \n\t \ call_handler_unknown_reason:\n\t \ popl %ds\n\t \ popal\n\t \ popfl\n\t \ // remove error code. will be restored later when we call\n\t \ // original handler again.\n\t \ addl $4,%esp\n\t \ // call debugger loop\n\t \ pushl $" STR(REASON_INTERNAL_ERROR) "\n\t \ jmp NewInt31Handler\n\t \ ")
base of all file and directory entries
Definition: entries.h:82
Definition: i386bug.c:6
BOOLEAN IsAddressValid(ULONG address)
Definition: utils.c:611
struct task_struct * current
Definition: linux.c:32
void UnmaskIrqs(void)
Definition: hooks.c:82
#define REASON_PAGEFAULT
Definition: shell.h:74