3 Copyright (c) 1998-2001 Klaus P. Gerlicher
11 page fault handling on x86
24 15-Nov-2000: general cleanup of source files
28 This file may be distributed under the terms of the GNU Public License.
32 ////////////////////////////////////////////////////
39 ////////////////////////////////////////////////////
43 char tempPageFault
[1024];
44 extern void NewInt31Handler(void);
46 ULONG OldIntEHandler
=0;
48 BOOLEAN bInPageFaultHandler
= FALSE
;
49 static ULONG PCR_SEL
= PCR_SELECTOR
;
52 ////////////////////////////////////////////////////
56 //*************************************************************************
57 // HandleInDebuggerFault()
59 //*************************************************************************
60 ULONG
HandleInDebuggerFault(FRAME
* ptr
,ULONG address
)
66 DPRINT((0,"HandleInDebuggerFault(): ###### page fault @ %.8X while inside debugger, eip: %x\n",address
, ptr
->eip
));
68 // fault in this page fault handler
69 if(bInPageFaultHandler
)
71 DPRINT((0,"HandleInDebuggerFault(): ###### page fault @ %.8X while in page fault handler\n",address
));
73 DPRINT((0,"!!! machine is halted !!!\n"));
74 __asm__
__volatile__ ("hlt");
80 bInPageFaultHandler
= TRUE
;
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();
86 DPRINT((0,"%.8X (%.4X:%.8X %.8X %s %s %s task=%.8X )\n",
91 (ptr
->error_code
&1)?"PLP":"NP",
92 (ptr
->error_code
&2)?"WRITE":"READ",
93 (ptr
->error_code
&4)?"USER-MODE":"KERNEL-MODE",
98 DPRINT((0,"HandleInDebuggerFault(): unexpected pagefault in command handler!\n",address
));
102 DPRINT((0,"HandleInDebuggerFault(): unexpected pagefault in command handler while in PrintkCallback()!\n",address
));
110 pPGD
= ADDR_TO_PDE(address
);
112 DPRINT((0,"PGD for %.8X @ %.8X = %.8X\n",address
,(ULONG
)pPGD
,(ULONG
)(*pPGD
) ));
114 if(pPGD
&& (*pPGD
)&_PAGE_PRESENT
)
117 if(!((*pPGD
)&_PAGE_4M
))
119 pPTE
= ADDR_TO_PTE(address
);
122 DPRINT((0,"PTE for %.8X @ %.8X = %.8X\n",address
,(ULONG
)pPTE
,(ULONG
)(*pPTE
) ));
128 IntelStackWalk(ptr
->eip
,CurrentEBP
,ulRealStackPtr
);
130 DPRINT((0,"!!! machine is halted !!!\n"));
131 __asm__
__volatile__ ("hlt");
138 //*************************************************************************
142 // 0 = let the system handle it
143 // 1 = call DebuggerShell()
144 // 2 = FATAL error inside debugger
145 //*************************************************************************
146 ULONG
HandlePageFault(FRAME
* ptr
)
151 PLIST_ENTRY current_entry
;
152 MEMORY_AREA
* current
;
154 PKTHREAD CurrentThread
;
155 PETHREAD CurrentEThread
;
157 // get linear address of page fault
158 __asm__
__volatile__("movl %%cr2,%0"
161 DPRINT((0,"\nPageFault: bInDebShell: %d, error: %d, addr: %x\n", bInDebuggerShell
, ptr
->error_code
, address
));
163 // there's something terribly wrong if we get a fault in our command handler
166 DPRINT((0,"return handleindebuggerfault\n"));
167 return HandleInDebuggerFault(ptr
,(ULONG
)address
);
170 ASSERT(IsAddressValid((ULONG
)ptr
));
171 // remember error code so we can push it back on the stack
172 error_code
= ptr
->error_code
;
174 //ei Check IRQL here!!!
178 Print(OUTPUT_WINDOW,"pICE: system is currently processing an interrupt!\n");
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
));
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
196 DPRINT((0,"vma not valid: vma: %x\n", vma
));
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
)
205 ASSERT(current_entry
);
206 ASSERT(IsAddressValid((ULONG
)current_entry
));
207 current
= CONTAINING_RECORD(current_entry
,
212 if( (address
>= current
->BaseAddress
) && (address
<= current
->BaseAddress
+ current
->Length
))
214 DPRINT((0,"address: %x %x - %x Attrib: %x, Type: %x\n", address
, current
->BaseAddress
, current
->BaseAddress
+ current
->Length
, current
->Attributes
, current
->Type
));
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
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
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));
231 else{ //access violation
235 if( (ULONG
)address
>= KERNEL_BASE
)
237 Print(OUTPUT_WINDOW
,"pICE: User mode program trying to access kernel memory!\n");
238 //DPRINT((0,"return 0 3\n"));
241 //DPRINT((0,"return 0 4\n"));
248 if(!(current->Attributes & PAGE_READONLY))
250 Print(OUTPUT_WINDOW,"pICE: virtual memory arena is not writeable!\n");
257 // test EXT bit in error code
260 Print(OUTPUT_WINDOW,"pICE: page-level protection fault!\n");
266 if (!(current->Attributes & PAGE_EXECUTE_READ))
268 Print(OUTPUT_WINDOW,"pICE: VMA is not readable!\n");
273 // let the system handle it
274 //DPRINT((0,"return 0 5\n"));
278 current_entry
= current_entry
->Flink
;
281 Print(OUTPUT_WINDOW
,"pICE: no virtual memory arena at this address!\n");
282 DPRINT((0,"return 0 6\n"));
285 // let the system handle it
289 //*************************************************************************
292 //*************************************************************************
294 NewIntEHandler:\n\t \
301 // setup default data selectors\n\t \
306 * Load the PCR selector.\n\t \
309 movl %eax, _OLD_PCR\n\t \
310 movl _PCR_SEL, %eax\n\t \
313 // get frame ptr\n\t \
314 lea 40(%esp),%eax\n\t \
316 call _HandlePageFault\n\t \
320 movl _OLD_PCR, %eax\n\t \
325 je call_old_inte_handler\n\t \
328 je call_handler_unknown_reason\n\t \
333 // remove error code. will be restored later when we call\n\t \
334 // original handler again.\n\t \
336 // call debugger loop\n\t \
337 pushl $" STR(REASON_PAGEFAULT
) "\n\t \
338 jmp NewInt31Handler\n\t \
340 call_old_inte_handler:\n\t \
344 // chain to old handler\n\t \
346 jmp *_OldIntEHandler\n\t \
348 call_handler_unknown_reason:\n\t \
352 // remove error code. will be restored later when we call\n\t \
353 // original handler again.\n\t \
355 // call debugger loop\n\t \
356 pushl $" STR(REASON_INTERNAL_ERROR
) "\n\t \
357 jmp NewInt31Handler\n\t \
361 //*************************************************************************
364 //*************************************************************************
365 void InstallIntEHook(void)
367 ULONG LocalIntEHandler
;
374 __asm__
__volatile__("mov $NewIntEHandler,%0"
375 :"=r" (LocalIntEHandler
)
378 OldIntEHandler
=SetGlobalInt(0x0E,(ULONG
)LocalIntEHandler
);
381 DPRINT((0,"OldIntE @ %x\n", OldIntEHandler
));
385 //*************************************************************************
386 // DeInstallIntEHook()
388 //*************************************************************************
389 void DeInstallIntEHook(void)
396 SetGlobalInt(0x0E,(ULONG
)OldIntEHandler
);