3 * Copyright (C) 2000, 2001 ReactOS Team
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.
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.
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.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/v86m.c
22 * PURPOSE: Support for v86 mode
23 * PROGRAMMER: David Welch (welch@cwcom.net)
26 /* INCLUDES *****************************************************************/
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>
37 #include <internal/debug.h>
39 /* GLOBALS *******************************************************************/
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)
46 #define VALID_FLAGS (0xDFF)
48 /* FUNCTIONS *****************************************************************/
51 KeV86GPF(PKV86M_TRAP_FRAME VTf, PKTRAP_FRAME Tf)
56 BOOL BigDataPrefix = FALSE;
57 BOOL BigAddressPrefix = FALSE;
58 BOOL RepPrefix = FALSE;
62 ip = (PUCHAR)((Tf->Cs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
63 sp = (PUSHORT)((Tf->Ss & 0xFFFF) * 16 + (Tf->Esp & 0xFFFF));
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);
73 /* 32-bit data prefix */
80 /* 32-bit address prefix */
82 BigAddressPrefix = TRUE;
96 if (BigDataPrefix || BigAddressPrefix || RepPrefix)
98 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
101 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
112 if (BigDataPrefix || BigAddressPrefix || RepPrefix)
114 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
117 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
130 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
133 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
136 if (!BigAddressPrefix)
138 Tf->Esp = Tf->Esp - 2;
140 sp[0] = Tf->Eflags & 0xFFFF;
141 if (VTf->regs->Vif == 1)
143 sp[0] = sp[0] | INTERRUPT_FLAG;
147 sp[0] = sp[0] & (~INTERRUPT_FLAG);
152 Tf->Esp = Tf->Esp - 4;
155 dsp[0] = dsp[0] & VALID_FLAGS;
156 if (VTf->regs->Vif == 1)
158 dsp[0] = dsp[0] | INTERRUPT_FLAG;
162 dsp[0] = dsp[0] & (~INTERRUPT_FLAG);
174 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
177 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
180 if (!BigAddressPrefix)
182 Tf->Eflags = Tf->Eflags & (~0xFFFF);
183 Tf->Eflags = Tf->Eflags | (sp[0] & VALID_FLAGS);
184 if (Tf->Eflags & INTERRUPT_FLAG)
192 Tf->Eflags = Tf->Eflags | INTERRUPT_FLAG;
193 Tf->Esp = Tf->Esp + 2;
197 Tf->Eflags = Tf->Eflags | (dsp[0] & VALID_FLAGS);
198 if (dsp[0] & INTERRUPT_FLAG)
206 Tf->Eflags = Tf->Eflags | INTERRUPT_FLAG;
207 Tf->Esp = Tf->Esp + 2;
218 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
221 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
225 Tf->Eflags = Tf->Eflags & (~0xFFFF);
226 Tf->Eflags = Tf->Eflags | sp[2];
227 if (Tf->Eflags & INTERRUPT_FLAG)
235 Tf->Eflags = Tf->Eflags & (~INTERRUPT_FLAG);
236 Tf->Esp = Tf->Esp + 6;
246 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
249 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
251 DPRINT("outb %d, %x\n", (ULONG)ip[i + 1], Tf->Eax & 0xFF);
252 WRITE_PORT_UCHAR((PUCHAR)(ULONG)ip[i + 1],
254 Tf->Eip = Tf->Eip + 2;
264 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
267 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
271 DPRINT("outw %d, %x\n", (ULONG)ip[i + 1], Tf->Eax & 0xFFFF);
272 WRITE_PORT_USHORT((PUSHORT)(ULONG)ip[1], Tf->Eax & 0xFFFF);
276 DPRINT("outl %d, %x\n", (ULONG)ip[i + 1], Tf->Eax);
277 WRITE_PORT_ULONG((PULONG)(ULONG)ip[1], Tf->Eax);
279 Tf->Eip = Tf->Eip + 2;
289 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
292 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
306 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
309 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
313 DPRINT("outw %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax & 0xFFFF);
314 WRITE_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF),
319 DPRINT("outl %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax);
320 WRITE_PORT_ULONG((PULONG)(Tf->Edx & 0xFFFF),
323 Tf->Eip = Tf->Eip + 1;
333 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
336 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
354 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
357 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
370 v = READ_PORT_USHORT((PUSHORT)(ULONG)ip[1]);
371 DPRINT("inl %d\t%X\n", (ULONG)ip[1], v);
374 Tf->Eip = Tf->Eip + 2;
384 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
387 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
405 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
408 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
423 v = READ_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF));
424 DPRINT("inl %d\t%X\n", Tf->Edx & 0xFFFF, v);
427 Tf->Eip = Tf->Eip + 1;
435 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
446 if (!BigAddressPrefix)
448 Count = Count & 0xFFFF;
452 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
454 if (!BigAddressPrefix)
456 Offset = Offset & 0xFFFF;
458 Buffer = (PUCHAR)((Tf->Es * 16) + Offset);
459 for (; Count > 0; Count--)
461 WRITE_PORT_UCHAR(Port, *Buffer);
462 if (Tf->Eflags & DIRECTION_FLAG)
479 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
483 PUSHORT BufferS = NULL;
484 PULONG BufferL = NULL;
491 if (!BigAddressPrefix)
493 Count = Count & 0xFFFF;
497 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
499 if (!BigAddressPrefix)
501 Offset = Offset & 0xFFFF;
505 BufferL = (PULONG)((Tf->Es * 16) + Offset);
509 BufferS = (PUSHORT)((Tf->Es * 16) + Offset);
511 for (; Count > 0; Count--)
515 WRITE_PORT_ULONG((PULONG)Port, *BufferL);
519 WRITE_PORT_USHORT((PUSHORT)Port, *BufferS);
521 if (Tf->Eflags & DIRECTION_FLAG)
552 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
563 if (!BigAddressPrefix)
565 Count = Count & 0xFFFF;
569 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
571 if (!BigAddressPrefix)
573 Offset = Offset & 0xFFFF;
575 Buffer = (PUCHAR)((Tf->Es * 16) + Offset);
576 for (; Count > 0; Count--)
578 *Buffer = READ_PORT_UCHAR(Port);
579 if (Tf->Eflags & DIRECTION_FLAG)
596 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
600 PUSHORT BufferS = NULL;
601 PULONG BufferL = NULL;
608 if (!BigAddressPrefix)
610 Count = Count & 0xFFFF;
614 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
616 if (!BigAddressPrefix)
618 Offset = Offset & 0xFFFF;
622 BufferL = (PULONG)((Tf->Es * 16) + Offset);
626 BufferS = (PUSHORT)((Tf->Es * 16) + Offset);
628 for (; Count > 0; Count--)
632 *BufferL = READ_PORT_ULONG((PULONG)Port);
636 *BufferS = READ_PORT_USHORT((PUSHORT)Port);
638 if (Tf->Eflags & DIRECTION_FLAG)
674 entry = ((unsigned int *)0)[inum];
676 Tf->Esp = Tf->Esp - 6;
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)
684 sp[2] = sp[2] | INTERRUPT_FLAG;
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);
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 */
700 DPRINT1("V86GPF unhandled (was %x)\n", ip[i]);
701 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
706 KeV86Exception(ULONG ExceptionNr, PKTRAP_FRAME Tf, ULONG address)
709 PKV86M_TRAP_FRAME VTf;
711 VTf = (PKV86M_TRAP_FRAME)Tf;
713 if(KeGetCurrentProcess()->NtVdmFlag)
715 VTf->regs->PStatus = (PNTSTATUS) ExceptionNr;
716 if(ExceptionNr != 14) return 1;
720 * Check if we have reached the recovery instruction
722 Ip = (PUCHAR)((Tf->Cs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
723 if (ExceptionNr != 14)
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,
728 DPRINT("VTf %x VTf->regs %x\n", VTf, VTf->regs);
730 if (ExceptionNr == 6 &&
731 memcmp(Ip, VTf->regs->RecoveryInstruction, 4) == 0 &&
732 (Tf->Cs * 16 + Tf->Eip) == VTf->regs->RecoveryAddress)
734 *VTf->regs->PStatus = STATUS_SUCCESS;
739 * Handle the exceptions
745 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
750 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
755 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
760 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
765 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
768 /* Array bounds check */
770 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
775 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
778 /* Device not available */
780 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
785 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
790 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
795 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
798 /* Segment not present */
800 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;;
805 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
808 /* General protection fault */
810 return(KeV86GPF(VTf, Tf));
817 Status = MmPageFault(USER_CS,
822 if (!NT_SUCCESS(Status))
824 if(KeGetCurrentProcess()->NtVdmFlag)
826 VTf->regs->PStatus = (PNTSTATUS) STATUS_NONCONTINUABLE_EXCEPTION;
830 DPRINT("V86Exception, halting due to page fault\n");
831 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
840 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
843 /* Alignment check */
845 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
849 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;