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);