:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / ke / i386 / v86m.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2000, 2001  ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * PROJECT:         ReactOS kernel
21  * FILE:            ntoskrnl/ke/i386/v86m.c
22  * PURPOSE:         Support for v86 mode
23  * PROGRAMMER:      David Welch (welch@cwcom.net)
24  */
25
26 /* INCLUDES *****************************************************************/
27
28 #include <ddk/ntddk.h>
29 #include <internal/v86m.h>
30 #include <internal/trap.h>
31 #include <internal/mm.h>
32 #include <internal/i386/segment.h>
33 #include <string.h>
34
35 #define NDEBUG
36 #include <internal/debug.h>
37
38 /* GLOBALS *******************************************************************/
39
40 #define IOPL_FLAG          ((1 << 12) | (1 << 13))
41 #define INTERRUPT_FLAG     (1 << 9)
42 #define TRAP_FLAG          (1 << 8)
43 #define DIRECTION_FLAG     (1 << 10)
44
45 #define VALID_FLAGS         (0xDFF)
46
47 /* FUNCTIONS *****************************************************************/
48
49 ULONG
50 KeV86GPF(PKV86M_TRAP_FRAME VTf, PKTRAP_FRAME Tf)
51 {
52   PUCHAR ip;
53   PUSHORT sp; 
54   PULONG dsp;
55   BOOL BigDataPrefix = FALSE;
56   BOOL BigAddressPrefix = FALSE;
57   BOOL RepPrefix = FALSE;
58   ULONG i = 0;
59   BOOL Exit = FALSE;
60
61   ip = (PUCHAR)((Tf->Cs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
62   sp = (PUSHORT)((Tf->Ss & 0xFFFF) * 16 + (Tf->Esp & 0xFFFF));
63   dsp = (PULONG)sp;
64
65   DPRINT("KeV86GPF handling %x at %x:%x ss:sp %x:%x Flags %x\n",
66          ip[0], Tf->Cs, Tf->Eip, Tf->Ss, Tf->Esp, VTf->regs->Flags);
67  
68   while (!Exit)
69     {
70       switch (ip[i])
71         {
72           /* 32-bit data prefix */
73         case 0x66:
74           BigDataPrefix = TRUE;
75           i++;
76           Tf->Eip++;
77           break;
78
79           /* 32-bit address prefix */
80         case 0x67:
81           BigAddressPrefix = TRUE;
82           i++;
83           Tf->Eip++;
84           break;
85
86           /* rep prefix */
87         case 0xFC:
88           RepPrefix = TRUE;
89           i++;
90           Tf->Eip++;
91           break;
92
93           /* sti */
94         case 0xFB:
95           if (BigDataPrefix || BigAddressPrefix || RepPrefix)
96             {
97               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
98               return(1);
99             }
100           if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
101             {
102               Tf->Eip++;
103               VTf->regs->Vif = 1;
104               return(0);
105             }
106           Exit = TRUE;
107           break;
108           
109           /* cli */
110         case 0xFA:
111           if (BigDataPrefix || BigAddressPrefix || RepPrefix)
112             {
113               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
114               return(1);
115             }
116           if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
117             {
118               Tf->Eip++;
119               VTf->regs->Vif = 0;
120               return(0);
121             }
122           Exit = TRUE;
123           break;
124           
125           /* pushf */
126         case 0x9C:
127           if (RepPrefix)
128             {
129               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
130               return(1);
131             }
132           if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
133             {
134               Tf->Eip++;
135               if (!BigAddressPrefix)
136                 {
137                   Tf->Esp = Tf->Esp - 2;
138                   sp = sp - 1;
139                   sp[0] = Tf->Eflags & 0xFFFF;
140                   if (VTf->regs->Vif == 1)
141                     {
142                       sp[0] = sp[0] | INTERRUPT_FLAG;
143                     }
144                   else
145                     {
146                       sp[0] = sp[0] & (~INTERRUPT_FLAG);
147                     }
148                 }
149               else
150                 {
151                   Tf->Esp = Tf->Esp - 4;
152                   dsp = dsp - 1;
153                   dsp[0] = Tf->Eflags;
154                   dsp[0] = dsp[0] & VALID_FLAGS;
155                   if (VTf->regs->Vif == 1)
156                     {
157                       dsp[0] = dsp[0] | INTERRUPT_FLAG;
158                     }
159                   else
160                     {
161                       dsp[0] = dsp[0] & (~INTERRUPT_FLAG);
162                     }
163                 }
164               return(0);
165             }
166           Exit = TRUE;
167           break;
168           
169           /* popf */
170         case 0x9D:
171           if (RepPrefix)
172             {
173               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
174               return(1);
175             }
176           if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
177             {
178               Tf->Eip++;
179               if (!BigAddressPrefix)
180                 {
181                   Tf->Eflags = Tf->Eflags & (~0xFFFF);
182                   Tf->Eflags = Tf->Eflags | (sp[0] & VALID_FLAGS);
183                   if (Tf->Eflags & INTERRUPT_FLAG)
184                     {
185                       VTf->regs->Vif = 1;
186                     }
187                   else
188                     {
189                       VTf->regs->Vif = 0;
190                     }             
191                   Tf->Eflags = Tf->Eflags | INTERRUPT_FLAG;
192                   Tf->Esp = Tf->Esp + 2;
193                 }
194               else
195                 {
196                   Tf->Eflags = Tf->Eflags | (dsp[0] & VALID_FLAGS);
197                   if (dsp[0] & INTERRUPT_FLAG)
198                     {
199                       VTf->regs->Vif = 1;
200                     }
201                   else
202                     {
203                       VTf->regs->Vif = 0;
204                     }
205                   Tf->Eflags = Tf->Eflags | INTERRUPT_FLAG;
206                   Tf->Esp = Tf->Esp + 2;
207                 }
208               return(0);
209             }
210           Exit = TRUE;
211           break;
212
213       /* iret */
214         case 0xCF:
215           if (RepPrefix)
216             {
217               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
218               return(1);
219             }
220           if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
221             {
222               Tf->Eip = sp[0];
223               Tf->Cs = sp[1];
224               Tf->Eflags = Tf->Eflags & (~0xFFFF);
225               Tf->Eflags = Tf->Eflags | sp[2];
226               if (Tf->Eflags & INTERRUPT_FLAG)
227                 {
228                   VTf->regs->Vif = 1;
229                 }
230               else
231                 {
232                   VTf->regs->Vif = 0;
233                 }
234               Tf->Eflags = Tf->Eflags & (~INTERRUPT_FLAG);
235               Tf->Esp = Tf->Esp + 6;
236               return(0);
237             }
238           Exit = TRUE;
239           break;
240
241           /* out imm8, al */
242         case 0xE6:
243           if (RepPrefix)
244             {
245               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
246               return(1);
247             }
248           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
249             {
250               WRITE_PORT_UCHAR((PUCHAR)(ULONG)ip[i + 1], 
251                                Tf->Eax & 0xFF);
252               Tf->Eip = Tf->Eip + 2;
253               return(0);
254             }
255           Exit = TRUE;
256           break;
257           
258           /* out imm8, ax */
259         case 0xE7:
260           if (RepPrefix)
261             {
262               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
263               return(1);
264             }
265           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
266             {
267               if (!BigDataPrefix)
268                 {
269                   WRITE_PORT_USHORT((PUSHORT)(ULONG)ip[1], Tf->Eax & 0xFFFF);
270                 }
271               else
272                 {
273                   WRITE_PORT_ULONG((PULONG)(ULONG)ip[1], Tf->Eax);
274                 }
275               Tf->Eip = Tf->Eip + 2;
276               return(0);
277             }
278           Exit = TRUE;
279           break;
280
281           /* out dx, al */
282         case 0xEE:
283           if (RepPrefix)
284             {
285               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
286               return(1);
287             }
288           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
289             {
290               WRITE_PORT_UCHAR((PUCHAR)(Tf->Edx & 0xFFFF), Tf->Eax & 0xFF);
291               Tf->Eip = Tf->Eip + 1;
292               return(0);
293             }
294           Exit = TRUE;
295           break;
296           
297           /* out dx, ax */
298         case 0xEF:
299           if (RepPrefix)
300             {
301               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
302               return(1);
303             }
304           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
305             {
306               if (!BigDataPrefix)
307                 {
308                   WRITE_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF), 
309                                     Tf->Eax & 0xFFFF);
310                 }
311               else
312                 {
313                   WRITE_PORT_ULONG((PULONG)(Tf->Edx & 0xFFFF), 
314                                    Tf->Eax);
315                 }
316               Tf->Eip = Tf->Eip + 1;
317               return(0);
318             }
319           Exit = TRUE;
320           break;
321           
322           /* in al, imm8 */
323         case 0xE4:
324           if (RepPrefix)
325             {
326               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
327               return(1);
328             }
329           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
330             {
331               UCHAR v;
332               
333               v = READ_PORT_UCHAR((PUCHAR)(ULONG)ip[1]);
334               Tf->Eax = Tf->Eax & (~0xFF);
335               Tf->Eax = Tf->Eax | v;
336               Tf->Eip = Tf->Eip + 2;
337               return(0);
338             }
339           Exit = TRUE;
340           break;
341           
342           /* in ax, imm8 */
343         case 0xE5:
344           if (RepPrefix)
345             {
346               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
347               return(1);
348             }
349           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
350             {
351               USHORT v;
352               
353               v = READ_PORT_USHORT((PUSHORT)(ULONG)ip[1]);
354               Tf->Eax = Tf->Eax & (~0xFFFF);
355               Tf->Eax = Tf->Eax | v;
356               Tf->Eip = Tf->Eip + 2;
357               return(0);
358             }
359           Exit = TRUE;
360           break;
361
362           /* in al, dx */
363         case 0xEC:
364           if (RepPrefix)
365             {
366               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
367               return(1);
368             }
369           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
370             {
371               UCHAR v;
372
373               v = READ_PORT_UCHAR((PUCHAR)(Tf->Edx & 0xFFFF));
374               Tf->Eax = Tf->Eax & (~0xFF);
375               Tf->Eax = Tf->Eax | v;
376               Tf->Eip = Tf->Eip + 1;
377               return(0);
378             }
379           Exit = TRUE;
380           break;
381           
382           /* in ax, dx */
383         case 0xED:
384           if (RepPrefix)
385             {
386               *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
387               return(1);
388             }
389           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
390             {
391               USHORT v;
392
393               v = READ_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF));
394               Tf->Eax = Tf->Eax & (~0xFFFF);
395               Tf->Eax = Tf->Eax | v;
396               Tf->Eip = Tf->Eip + 1;
397               return(0);
398             }
399           Exit = TRUE;
400           break;
401
402       /* outsb */
403         case 0x6E:
404           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
405             {
406               ULONG Count;
407               PUCHAR Port;
408               PUCHAR Buffer;
409               ULONG Offset;
410               
411               Count = 1;
412               if (RepPrefix)
413                 {
414                   Count = Tf->Ecx;
415                   if (!BigAddressPrefix)
416                     {
417                       Count = Count & 0xFFFF;
418                     }
419                 }
420
421               Port = (PUCHAR)(Tf->Edx & 0xFFFF);
422               Offset = Tf->Edi;
423               if (!BigAddressPrefix)
424                 {
425                   Offset = Offset & 0xFFFF;
426                 }
427               Buffer = (PUCHAR)((Tf->Es * 16) + Offset);
428               for (; Count > 0; Count--)
429                 {
430                   WRITE_PORT_UCHAR(Port, *Buffer);
431                   if (Tf->Eflags & DIRECTION_FLAG)
432                     {
433                       Buffer++;
434                     }
435                   else
436                     {
437                       Buffer--;
438                     }
439                 }                               
440               Tf->Eip++;
441               return(0);
442             }
443           Exit = TRUE;
444           break;
445
446           /* insw/insd */
447         case 0x6F:
448           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
449             {
450               ULONG Count;
451               PUCHAR Port;
452               PUSHORT BufferS = NULL;
453               PULONG BufferL = NULL;
454               ULONG Offset;
455               
456               Count = 1;
457               if (RepPrefix)
458                 {
459                   Count = Tf->Ecx;
460                   if (!BigAddressPrefix)
461                     {
462                       Count = Count & 0xFFFF;
463                     }
464                 }
465
466               Port = (PUCHAR)(Tf->Edx & 0xFFFF);
467               Offset = Tf->Edi;
468               if (!BigAddressPrefix)
469                 {
470                   Offset = Offset & 0xFFFF;
471                 }
472               if (BigDataPrefix)
473                 {
474                   BufferL = (PULONG)((Tf->Es * 16) + Offset);
475                 }
476               else
477                 {
478                   BufferS = (PUSHORT)((Tf->Es * 16) + Offset);
479                 }
480               for (; Count > 0; Count--)
481                 {
482                   if (BigDataPrefix)
483                     {
484                       WRITE_PORT_ULONG((PULONG)Port, *BufferL);
485                     }
486                   else
487                     {
488                       WRITE_PORT_USHORT((PUSHORT)Port, *BufferS);
489                     }
490                   if (Tf->Eflags & DIRECTION_FLAG)
491                     {
492                       if (BigDataPrefix)
493                         {
494                           BufferL++;
495                         }
496                       else
497                         {
498                           BufferS++;
499                         }
500                     }
501                   else
502                     {
503                       if (BigDataPrefix)
504                         {
505                           BufferL--;
506                         }
507                       else
508                         {
509                           BufferS--;
510                         }
511                     }
512                 }                               
513               Tf->Eip++;
514               return(0);
515             }
516           Exit = TRUE;
517           break;
518       
519       /* insb */
520         case 0x6C:
521           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
522             {
523               ULONG Count;
524               PUCHAR Port;
525               PUCHAR Buffer;
526               ULONG Offset;
527               
528               Count = 1;
529               if (RepPrefix)
530                 {
531                   Count = Tf->Ecx;
532                   if (!BigAddressPrefix)
533                     {
534                       Count = Count & 0xFFFF;
535                     }
536                 }
537
538               Port = (PUCHAR)(Tf->Edx & 0xFFFF);
539               Offset = Tf->Edi;
540               if (!BigAddressPrefix)
541                 {
542                   Offset = Offset & 0xFFFF;
543                 }
544               Buffer = (PUCHAR)((Tf->Es * 16) + Offset);
545               for (; Count > 0; Count--)
546                 {
547                   *Buffer = READ_PORT_UCHAR(Port);
548                   if (Tf->Eflags & DIRECTION_FLAG)
549                     {
550                       Buffer++;
551                     }
552                   else
553                     {
554                       Buffer--;
555                     }
556                 }                               
557               Tf->Eip++;
558               return(0);
559             }
560           Exit = TRUE;
561           break;
562
563           /* insw/insd */
564         case 0x6D:
565           if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
566             {
567               ULONG Count;
568               PUCHAR Port;
569               PUSHORT BufferS = NULL;
570               PULONG BufferL = NULL;
571               ULONG Offset;
572               
573               Count = 1;
574               if (RepPrefix)
575                 {
576                   Count = Tf->Ecx;
577                   if (!BigAddressPrefix)
578                     {
579                       Count = Count & 0xFFFF;
580                     }
581                 }
582
583               Port = (PUCHAR)(Tf->Edx & 0xFFFF);
584               Offset = Tf->Edi;
585               if (!BigAddressPrefix)
586                 {
587                   Offset = Offset & 0xFFFF;
588                 }
589               if (BigDataPrefix)
590                 {
591                   BufferL = (PULONG)((Tf->Es * 16) + Offset);
592                 }
593               else
594                 {
595                   BufferS = (PUSHORT)((Tf->Es * 16) + Offset);
596                 }
597               for (; Count > 0; Count--)
598                 {
599                   if (BigDataPrefix)
600                     {
601                       *BufferL = READ_PORT_ULONG((PULONG)Port);
602                     }
603                   else
604                     {
605                       *BufferS = READ_PORT_USHORT((PUSHORT)Port);
606                     }
607                   if (Tf->Eflags & DIRECTION_FLAG)
608                     {
609                       if (BigDataPrefix)
610                         {
611                           BufferL++;
612                         }
613                       else
614                         {
615                           BufferS++;
616                         }
617                     }
618                   else
619                     {
620                       if (BigDataPrefix)
621                         {
622                           BufferL--;
623                         }
624                       else
625                         {
626                           BufferS--;
627                         }
628                     }
629                 }                               
630               Tf->Eip++;
631               return(0);
632             }
633           Exit = TRUE;
634           break;
635
636           /* Int nn */
637         case 0xCD:
638           {
639             unsigned int inum;
640             unsigned int entry;
641             
642             inum = ip[1];
643             entry = ((unsigned int *)0)[inum];
644             
645             Tf->Esp = Tf->Esp - 6;
646             sp = sp - 3;
647             
648             sp[0] = (Tf->Eip & 0xFFFF) + 2;
649             sp[1] = Tf->Cs & 0xFFFF;
650             sp[2] = Tf->Eflags & 0xFFFF;
651             if (VTf->regs->Vif == 1)
652               {
653                 sp[2] = sp[2] | INTERRUPT_FLAG;
654               }
655             DPRINT("sp[0] %x sp[1] %x sp[2] %x\n", sp[0], sp[1], sp[2]);
656             Tf->Eip = entry & 0xFFFF;
657             Tf->Cs = entry >> 16;
658             Tf->Eflags = Tf->Eflags & (~TRAP_FLAG);
659             
660             return(0);
661           }
662         }
663           
664       /* FIXME: Also emulate ins and outs */
665       /* FIXME: Handle opcode prefixes */
666       /* FIXME: Don't allow the BIOS to write to sensitive I/O ports */
667     }
668    
669   DPRINT1("V86GPF unhandled (was %x)\n", ip[i]);
670   *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
671   return(1);
672 }
673
674 ULONG
675 KeV86Exception(ULONG ExceptionNr, PKTRAP_FRAME Tf, ULONG address)
676 {
677   PUCHAR Ip;
678   PKV86M_TRAP_FRAME VTf;
679
680   VTf = (PKV86M_TRAP_FRAME)Tf;
681
682   /*
683    * Check if we have reached the recovery instruction
684    */
685   Ip = (PUCHAR)((Tf->Cs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
686   if (ExceptionNr != 14)
687     {
688       DPRINT("ExceptionNr %d Ip[0] %x Ip[1] %x Ip[2] %x Ip[3] %x Tf->Cs %x "
689              "Tf->Eip %x\n", ExceptionNr, Ip[0], Ip[1], Ip[2], Ip[3], Tf->Cs,
690              Tf->Eip);
691       DPRINT("VTf %x VTf->regs %x\n", VTf, VTf->regs);
692     }
693   if (ExceptionNr == 6 &&
694       memcmp(Ip, VTf->regs->RecoveryInstruction, 4) == 0 &&
695       (Tf->Cs * 16 + Tf->Eip) == VTf->regs->RecoveryAddress)
696     {
697       *VTf->regs->PStatus = STATUS_SUCCESS;
698       return(1);
699     }
700
701   /*
702    * Handle the exceptions
703    */
704   switch (ExceptionNr)
705     {
706       /* Divide error */
707     case 0:
708       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
709       return(1);
710
711       /* Single step */
712     case 1:
713       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
714       return(1);
715
716       /* NMI */
717     case 2:
718       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
719       return(1);
720
721       /* Breakpoint */
722     case 3:
723       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
724       return(1);
725
726       /* Overflow */
727     case 4:
728       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
729       return(1);
730
731       /* Array bounds check */
732     case 5:
733       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
734       return(1);
735
736       /* Invalid opcode */
737     case 6:
738       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
739       return(1);
740
741       /* Device not available */
742     case 7:
743       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
744       return(1);
745
746       /* Double fault */
747     case 8:
748       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
749       return(1);
750
751       /* Intel reserved */
752     case 9:
753       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
754       return(1);
755
756       /* Invalid TSS */
757     case 10:
758       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
759       return(1);
760
761       /* Segment not present */
762     case 11:
763       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;;
764       return(1);
765
766       /* Stack fault */
767     case 12:
768       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
769       return(1);
770
771       /* General protection fault */
772     case 13:
773       return(KeV86GPF(VTf, Tf));
774
775       /* Page fault */
776     case 14:
777       {
778         NTSTATUS Status;
779
780         Status = MmPageFault(USER_CS,
781                              &Tf->Eip,
782                              NULL,
783                              address,
784                              Tf->ErrorCode);
785         if (!NT_SUCCESS(Status))
786           {
787             DPRINT("V86Exception, halting due to page fault\n");
788             *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
789             return(1);
790           }
791         return(0);
792       }
793
794       /* Intel reserved */
795     case 15:
796     case 16:
797       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
798       return(1);
799       
800       /* Alignment check */
801     case 17:
802       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
803       return(1);
804
805     default:
806       *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
807       return(1);
808     }
809 }
810
811
812