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