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/i386/segment.h>
36 #include <internal/debug.h>
38 /* GLOBALS *******************************************************************/
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)
45 #define VALID_FLAGS (0xDFF)
47 /* FUNCTIONS *****************************************************************/
50 KeV86GPF(PKV86M_TRAP_FRAME VTf, PKTRAP_FRAME Tf)
55 BOOL BigDataPrefix = FALSE;
56 BOOL BigAddressPrefix = FALSE;
57 BOOL RepPrefix = FALSE;
61 ip = (PUCHAR)((Tf->Cs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
62 sp = (PUSHORT)((Tf->Ss & 0xFFFF) * 16 + (Tf->Esp & 0xFFFF));
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);
72 /* 32-bit data prefix */
79 /* 32-bit address prefix */
81 BigAddressPrefix = TRUE;
95 if (BigDataPrefix || BigAddressPrefix || RepPrefix)
97 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
100 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
111 if (BigDataPrefix || BigAddressPrefix || RepPrefix)
113 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
116 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
129 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
132 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
135 if (!BigAddressPrefix)
137 Tf->Esp = Tf->Esp - 2;
139 sp[0] = Tf->Eflags & 0xFFFF;
140 if (VTf->regs->Vif == 1)
142 sp[0] = sp[0] | INTERRUPT_FLAG;
146 sp[0] = sp[0] & (~INTERRUPT_FLAG);
151 Tf->Esp = Tf->Esp - 4;
154 dsp[0] = dsp[0] & VALID_FLAGS;
155 if (VTf->regs->Vif == 1)
157 dsp[0] = dsp[0] | INTERRUPT_FLAG;
161 dsp[0] = dsp[0] & (~INTERRUPT_FLAG);
173 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
176 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
179 if (!BigAddressPrefix)
181 Tf->Eflags = Tf->Eflags & (~0xFFFF);
182 Tf->Eflags = Tf->Eflags | (sp[0] & VALID_FLAGS);
183 if (Tf->Eflags & INTERRUPT_FLAG)
191 Tf->Eflags = Tf->Eflags | INTERRUPT_FLAG;
192 Tf->Esp = Tf->Esp + 2;
196 Tf->Eflags = Tf->Eflags | (dsp[0] & VALID_FLAGS);
197 if (dsp[0] & INTERRUPT_FLAG)
205 Tf->Eflags = Tf->Eflags | INTERRUPT_FLAG;
206 Tf->Esp = Tf->Esp + 2;
217 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
220 if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
224 Tf->Eflags = Tf->Eflags & (~0xFFFF);
225 Tf->Eflags = Tf->Eflags | sp[2];
226 if (Tf->Eflags & INTERRUPT_FLAG)
234 Tf->Eflags = Tf->Eflags & (~INTERRUPT_FLAG);
235 Tf->Esp = Tf->Esp + 6;
245 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
248 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
250 WRITE_PORT_UCHAR((PUCHAR)(ULONG)ip[i + 1],
252 Tf->Eip = Tf->Eip + 2;
262 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
265 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
269 WRITE_PORT_USHORT((PUSHORT)(ULONG)ip[1], Tf->Eax & 0xFFFF);
273 WRITE_PORT_ULONG((PULONG)(ULONG)ip[1], Tf->Eax);
275 Tf->Eip = Tf->Eip + 2;
285 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
288 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
290 WRITE_PORT_UCHAR((PUCHAR)(Tf->Edx & 0xFFFF), Tf->Eax & 0xFF);
291 Tf->Eip = Tf->Eip + 1;
301 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
304 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
308 WRITE_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF),
313 WRITE_PORT_ULONG((PULONG)(Tf->Edx & 0xFFFF),
316 Tf->Eip = Tf->Eip + 1;
326 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
329 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
346 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
349 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
366 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
369 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
386 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
389 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
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;
404 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
415 if (!BigAddressPrefix)
417 Count = Count & 0xFFFF;
421 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
423 if (!BigAddressPrefix)
425 Offset = Offset & 0xFFFF;
427 Buffer = (PUCHAR)((Tf->Es * 16) + Offset);
428 for (; Count > 0; Count--)
430 WRITE_PORT_UCHAR(Port, *Buffer);
431 if (Tf->Eflags & DIRECTION_FLAG)
448 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
452 PUSHORT BufferS = NULL;
453 PULONG BufferL = NULL;
460 if (!BigAddressPrefix)
462 Count = Count & 0xFFFF;
466 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
468 if (!BigAddressPrefix)
470 Offset = Offset & 0xFFFF;
474 BufferL = (PULONG)((Tf->Es * 16) + Offset);
478 BufferS = (PUSHORT)((Tf->Es * 16) + Offset);
480 for (; Count > 0; Count--)
484 WRITE_PORT_ULONG((PULONG)Port, *BufferL);
488 WRITE_PORT_USHORT((PUSHORT)Port, *BufferS);
490 if (Tf->Eflags & DIRECTION_FLAG)
521 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
532 if (!BigAddressPrefix)
534 Count = Count & 0xFFFF;
538 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
540 if (!BigAddressPrefix)
542 Offset = Offset & 0xFFFF;
544 Buffer = (PUCHAR)((Tf->Es * 16) + Offset);
545 for (; Count > 0; Count--)
547 *Buffer = READ_PORT_UCHAR(Port);
548 if (Tf->Eflags & DIRECTION_FLAG)
565 if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
569 PUSHORT BufferS = NULL;
570 PULONG BufferL = NULL;
577 if (!BigAddressPrefix)
579 Count = Count & 0xFFFF;
583 Port = (PUCHAR)(Tf->Edx & 0xFFFF);
585 if (!BigAddressPrefix)
587 Offset = Offset & 0xFFFF;
591 BufferL = (PULONG)((Tf->Es * 16) + Offset);
595 BufferS = (PUSHORT)((Tf->Es * 16) + Offset);
597 for (; Count > 0; Count--)
601 *BufferL = READ_PORT_ULONG((PULONG)Port);
605 *BufferS = READ_PORT_USHORT((PUSHORT)Port);
607 if (Tf->Eflags & DIRECTION_FLAG)
643 entry = ((unsigned int *)0)[inum];
645 Tf->Esp = Tf->Esp - 6;
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)
653 sp[2] = sp[2] | INTERRUPT_FLAG;
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);
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 */
669 DPRINT1("V86GPF unhandled (was %x)\n", ip[i]);
670 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
675 KeV86Exception(ULONG ExceptionNr, PKTRAP_FRAME Tf, ULONG address)
678 PKV86M_TRAP_FRAME VTf;
680 VTf = (PKV86M_TRAP_FRAME)Tf;
683 * Check if we have reached the recovery instruction
685 Ip = (PUCHAR)((Tf->Cs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
686 if (ExceptionNr != 14)
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,
691 DPRINT("VTf %x VTf->regs %x\n", VTf, VTf->regs);
693 if (ExceptionNr == 6 &&
694 memcmp(Ip, VTf->regs->RecoveryInstruction, 4) == 0 &&
695 (Tf->Cs * 16 + Tf->Eip) == VTf->regs->RecoveryAddress)
697 *VTf->regs->PStatus = STATUS_SUCCESS;
702 * Handle the exceptions
708 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
713 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
718 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
723 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
728 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
731 /* Array bounds check */
733 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
738 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
741 /* Device not available */
743 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
748 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
753 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
758 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
761 /* Segment not present */
763 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;;
768 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
771 /* General protection fault */
773 return(KeV86GPF(VTf, Tf));
780 Status = MmPageFault(USER_CS,
785 if (!NT_SUCCESS(Status))
787 DPRINT("V86Exception, halting due to page fault\n");
788 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
797 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
800 /* Alignment check */
802 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
806 *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;