:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / apps / utils / pice / module / pgflt.c
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
32 ////////////////////////////////////////////////////
33 // INCLUDES
34 ////
35 #include "remods.h"
36
37 #include "precomp.h"
38
39 ////////////////////////////////////////////////////
40 // GLOBALS
41 ////
42
43 char tempPageFault[1024];
44 extern void NewInt31Handler(void);
45
46 ULONG OldIntEHandler=0;
47 ULONG error_code;
48 BOOLEAN bInPageFaultHandler = FALSE;
49 static ULONG PCR_SEL = PCR_SELECTOR;
50 static ULONG OLD_PCR;
51
52 ////////////////////////////////////////////////////
53 // FUNCTIONS
54 ////
55
56 //*************************************************************************
57 // HandleInDebuggerFault()
58 //
59 //*************************************************************************
60 ULONG HandleInDebuggerFault(FRAME* ptr,ULONG address)
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
69         if(bInPageFaultHandler)
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
80         bInPageFaultHandler = TRUE;
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
128     IntelStackWalk(ptr->eip,CurrentEBP,ulRealStackPtr);
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 //*************************************************************************
146 ULONG HandlePageFault(FRAME* ptr)
147 {
148     PVOID address;
149         PEPROCESS tsk, tsk1;
150         PMADDRESS_SPACE vma;
151     PLIST_ENTRY current_entry;
152         MEMORY_AREA* current;
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"));
167                 return HandleInDebuggerFault(ptr,(ULONG)address);
168     }
169
170         ASSERT(IsAddressValid((ULONG)ptr));
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 //*************************************************************************
389 void DeInstallIntEHook(void)
390 {
391         ENTER_FUNC();
392
393         MaskIrqs();
394         if(OldIntEHandler)
395         {
396                 SetGlobalInt(0x0E,(ULONG)OldIntEHandler);
397         OldIntEHandler=0;
398         }
399         UnmaskIrqs();
400
401     LEAVE_FUNC();
402 }