3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/i386/v86m.c
6 * PURPOSE: Support for v86 mode
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 #define IOPL_FLAG ((1 << 12) | (1 << 13))
20 #define INTERRUPT_FLAG (1 << 9)
21 #define TRAP_FLAG (1 << 8)
22 #define DIRECTION_FLAG (1 << 10)
24 #define VALID_FLAGS (0xDFF)
26 /* FUNCTIONS *****************************************************************/
29 KeV86GPF(PKV86M_TRAP_FRAME VTf
, PKTRAP_FRAME Tf
)
34 BOOL BigDataPrefix
= FALSE
;
35 BOOL BigAddressPrefix
= FALSE
;
36 BOOL RepPrefix
= FALSE
;
40 ip
= (PUCHAR
)((Tf
->SegCs
& 0xFFFF) * 16 + (Tf
->Eip
& 0xFFFF));
41 sp
= (PUSHORT
)((Tf
->HardwareSegSs
& 0xFFFF) * 16 + (Tf
->HardwareEsp
& 0xFFFF));
44 DPRINT("KeV86GPF handling %x at %x:%x ss:sp %x:%x Flags %x\n",
45 ip
[0], Tf
->SegCs
, Tf
->Eip
, Tf
->Ss
, Tf
->HardwareEsp
, VTf
->regs
->Flags
);
51 /* 32-bit data prefix */
58 /* 32-bit address prefix */
60 BigAddressPrefix
= TRUE
;
74 if (BigDataPrefix
|| BigAddressPrefix
|| RepPrefix
)
76 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
79 if (VTf
->regs
->Flags
& KV86M_EMULATE_CLI_STI
)
90 if (BigDataPrefix
|| BigAddressPrefix
|| RepPrefix
)
92 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
95 if (VTf
->regs
->Flags
& KV86M_EMULATE_CLI_STI
)
108 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
111 if (VTf
->regs
->Flags
& KV86M_EMULATE_CLI_STI
)
114 if (!BigAddressPrefix
)
116 Tf
->HardwareEsp
= Tf
->HardwareEsp
- 2;
118 sp
[0] = (USHORT
)(Tf
->EFlags
& 0xFFFF);
119 if (VTf
->regs
->Vif
== 1)
121 sp
[0] = (USHORT
)(sp
[0] | INTERRUPT_FLAG
);
125 sp
[0] = (USHORT
)(sp
[0] & (~INTERRUPT_FLAG
));
130 Tf
->HardwareEsp
= Tf
->HardwareEsp
- 4;
133 dsp
[0] = dsp
[0] & VALID_FLAGS
;
134 if (VTf
->regs
->Vif
== 1)
136 dsp
[0] = dsp
[0] | INTERRUPT_FLAG
;
140 dsp
[0] = dsp
[0] & (~INTERRUPT_FLAG
);
152 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
155 if (VTf
->regs
->Flags
& KV86M_EMULATE_CLI_STI
)
158 if (!BigAddressPrefix
)
160 Tf
->EFlags
= Tf
->EFlags
& (~0xFFFF);
161 Tf
->EFlags
= Tf
->EFlags
| (sp
[0] & VALID_FLAGS
);
162 if (Tf
->EFlags
& INTERRUPT_FLAG
)
170 Tf
->EFlags
= Tf
->EFlags
| INTERRUPT_FLAG
;
171 Tf
->HardwareEsp
= Tf
->HardwareEsp
+ 2;
175 Tf
->EFlags
= Tf
->EFlags
| (dsp
[0] & VALID_FLAGS
);
176 if (dsp
[0] & INTERRUPT_FLAG
)
184 Tf
->EFlags
= Tf
->EFlags
| INTERRUPT_FLAG
;
185 Tf
->HardwareEsp
= Tf
->HardwareEsp
+ 2;
196 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
199 if (VTf
->regs
->Flags
& KV86M_EMULATE_CLI_STI
)
203 Tf
->EFlags
= Tf
->EFlags
& (~0xFFFF);
204 Tf
->EFlags
= Tf
->EFlags
| sp
[2];
205 if (Tf
->EFlags
& INTERRUPT_FLAG
)
213 Tf
->EFlags
= Tf
->EFlags
& (~INTERRUPT_FLAG
);
214 Tf
->HardwareEsp
= Tf
->HardwareEsp
+ 6;
224 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
227 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
229 DPRINT("outb %d, %x\n", (ULONG
)ip
[i
+ 1], Tf
->Eax
& 0xFF);
230 WRITE_PORT_UCHAR((PUCHAR
)(ULONG
)ip
[i
+ 1],
231 (UCHAR
)(Tf
->Eax
& 0xFF));
232 Tf
->Eip
= Tf
->Eip
+ 2;
242 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
245 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
249 DPRINT("outw %d, %x\n", (ULONG
)ip
[i
+ 1], Tf
->Eax
& 0xFFFF);
250 WRITE_PORT_USHORT((PUSHORT
)(ULONG
)ip
[1], (USHORT
)(Tf
->Eax
& 0xFFFF));
254 DPRINT("outl %d, %x\n", (ULONG
)ip
[i
+ 1], Tf
->Eax
);
255 WRITE_PORT_ULONG((PULONG
)(ULONG
)ip
[1], Tf
->Eax
);
257 Tf
->Eip
= Tf
->Eip
+ 2;
267 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
270 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
272 DPRINT("outb %d, %x\n", Tf
->Edx
& 0xFFFF, Tf
->Eax
& 0xFF);
273 WRITE_PORT_UCHAR((PUCHAR
)(Tf
->Edx
& 0xFFFF), (UCHAR
)(Tf
->Eax
& 0xFF));
274 Tf
->Eip
= Tf
->Eip
+ 1;
284 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
287 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
291 DPRINT("outw %d, %x\n", Tf
->Edx
& 0xFFFF, Tf
->Eax
& 0xFFFF);
292 WRITE_PORT_USHORT((PUSHORT
)(Tf
->Edx
& 0xFFFF),
293 (USHORT
)(Tf
->Eax
& 0xFFFF));
297 DPRINT("outl %d, %x\n", Tf
->Edx
& 0xFFFF, Tf
->Eax
);
298 WRITE_PORT_ULONG((PULONG
)(Tf
->Edx
& 0xFFFF),
301 Tf
->Eip
= Tf
->Eip
+ 1;
311 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
314 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
318 v
= READ_PORT_UCHAR((PUCHAR
)(ULONG
)ip
[1]);
319 DPRINT("inb %d\t%X\n", (ULONG
)ip
[1], v
);
320 Tf
->Eax
= Tf
->Eax
& (~0xFF);
321 Tf
->Eax
= Tf
->Eax
| v
;
322 Tf
->Eip
= Tf
->Eip
+ 2;
332 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
335 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
340 v
= READ_PORT_USHORT((PUSHORT
)(ULONG
)ip
[1]);
341 DPRINT("inw %d\t%X\n", (ULONG
)ip
[1], v
);
342 Tf
->Eax
= Tf
->Eax
& (~0xFFFF);
343 Tf
->Eax
= Tf
->Eax
| v
;
348 v
= READ_PORT_ULONG((PULONG
)(ULONG
)ip
[1]);
349 DPRINT("inl %d\t%X\n", (ULONG
)ip
[1], v
);
352 Tf
->Eip
= Tf
->Eip
+ 2;
362 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
365 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
369 v
= READ_PORT_UCHAR((PUCHAR
)(Tf
->Edx
& 0xFFFF));
370 DPRINT("inb %d\t%X\n", Tf
->Edx
& 0xFFFF, v
);
371 Tf
->Eax
= Tf
->Eax
& (~0xFF);
372 Tf
->Eax
= Tf
->Eax
| v
;
373 Tf
->Eip
= Tf
->Eip
+ 1;
383 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
386 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
392 v
= READ_PORT_USHORT((PUSHORT
)(Tf
->Edx
& 0xFFFF));
393 DPRINT("inw %d\t%X\n", Tf
->Edx
& 0xFFFF, v
);
394 Tf
->Eax
= Tf
->Eax
& (~0xFFFF);
395 Tf
->Eax
= Tf
->Eax
| v
;
401 v
= READ_PORT_ULONG((PULONG
)(Tf
->Edx
& 0xFFFF));
402 DPRINT("inl %d\t%X\n", Tf
->Edx
& 0xFFFF, v
);
405 Tf
->Eip
= Tf
->Eip
+ 1;
413 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
424 if (!BigAddressPrefix
)
426 Count
= Count
& 0xFFFF;
430 Port
= (PUCHAR
)(Tf
->Edx
& 0xFFFF);
432 if (!BigAddressPrefix
)
434 Offset
= Offset
& 0xFFFF;
436 Buffer
= (PUCHAR
)((Tf
->SegEs
* 16) + Offset
);
437 for (; Count
> 0; Count
--)
439 WRITE_PORT_UCHAR(Port
, *Buffer
);
440 if (Tf
->EFlags
& DIRECTION_FLAG
)
457 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
461 PUSHORT BufferS
= NULL
;
462 PULONG BufferL
= NULL
;
469 if (!BigAddressPrefix
)
471 Count
= Count
& 0xFFFF;
475 Port
= (PUCHAR
)(Tf
->Edx
& 0xFFFF);
477 if (!BigAddressPrefix
)
479 Offset
= Offset
& 0xFFFF;
483 BufferL
= (PULONG
)((Tf
->SegEs
* 16) + Offset
);
487 BufferS
= (PUSHORT
)((Tf
->SegEs
* 16) + Offset
);
489 for (; Count
> 0; Count
--)
493 WRITE_PORT_ULONG((PULONG
)Port
, *BufferL
);
497 WRITE_PORT_USHORT((PUSHORT
)Port
, *BufferS
);
499 if (Tf
->EFlags
& DIRECTION_FLAG
)
530 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
541 if (!BigAddressPrefix
)
543 Count
= Count
& 0xFFFF;
547 Port
= (PUCHAR
)(Tf
->Edx
& 0xFFFF);
549 if (!BigAddressPrefix
)
551 Offset
= Offset
& 0xFFFF;
553 Buffer
= (PUCHAR
)((Tf
->SegEs
* 16) + Offset
);
554 for (; Count
> 0; Count
--)
556 *Buffer
= READ_PORT_UCHAR(Port
);
557 if (Tf
->EFlags
& DIRECTION_FLAG
)
574 if (VTf
->regs
->Flags
& KV86M_ALLOW_IO_PORT_ACCESS
)
578 PUSHORT BufferS
= NULL
;
579 PULONG BufferL
= NULL
;
586 if (!BigAddressPrefix
)
588 Count
= Count
& 0xFFFF;
592 Port
= (PUCHAR
)(Tf
->Edx
& 0xFFFF);
594 if (!BigAddressPrefix
)
596 Offset
= Offset
& 0xFFFF;
600 BufferL
= (PULONG
)((Tf
->SegEs
* 16) + Offset
);
604 BufferS
= (PUSHORT
)((Tf
->SegEs
* 16) + Offset
);
606 for (; Count
> 0; Count
--)
610 *BufferL
= READ_PORT_ULONG((PULONG
)Port
);
614 *BufferS
= READ_PORT_USHORT((PUSHORT
)Port
);
616 if (Tf
->EFlags
& DIRECTION_FLAG
)
652 entry
= ((unsigned int *)0)[inum
];
654 Tf
->HardwareEsp
= Tf
->HardwareEsp
- 6;
657 sp
[0] = (USHORT
)((Tf
->Eip
& 0xFFFF) + 2);
658 sp
[1] = (USHORT
)(Tf
->SegCs
& 0xFFFF);
659 sp
[2] = (USHORT
)(Tf
->EFlags
& 0xFFFF);
660 if (VTf
->regs
->Vif
== 1)
662 sp
[2] = (USHORT
)(sp
[2] | INTERRUPT_FLAG
);
664 DPRINT("sp[0] %x sp[1] %x sp[2] %x\n", sp
[0], sp
[1], sp
[2]);
665 Tf
->Eip
= entry
& 0xFFFF;
666 Tf
->SegCs
= entry
>> 16;
667 Tf
->EFlags
= Tf
->EFlags
& (~TRAP_FLAG
);
673 /* FIXME: Also emulate ins and outs */
674 /* FIXME: Handle opcode prefixes */
675 /* FIXME: Don't allow the BIOS to write to sensitive I/O ports */
678 DPRINT1("V86GPF unhandled (was %x)\n", ip
[i
]);
679 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
685 KeV86Exception(ULONG ExceptionNr
, PKTRAP_FRAME Tf
, ULONG address
)
688 PKV86M_TRAP_FRAME VTf
;
690 ASSERT (ExceptionNr
!= 14);
692 VTf
= (PKV86M_TRAP_FRAME
)Tf
;
694 /* FIXME: This should use ->VdmObjects */
695 if(KeGetCurrentProcess()->Unused
)
697 VTf
->regs
->PStatus
= (PNTSTATUS
) ExceptionNr
;
702 * Check if we have reached the recovery instruction
704 Ip
= (PUCHAR
)((Tf
->SegCs
& 0xFFFF) * 16 + (Tf
->Eip
& 0xFFFF));
706 DPRINT("ExceptionNr %d Ip[0] %x Ip[1] %x Ip[2] %x Ip[3] %x Tf->SegCs %x "
707 "Tf->Eip %x\n", ExceptionNr
, Ip
[0], Ip
[1], Ip
[2], Ip
[3], Tf
->SegCs
,
709 DPRINT("VTf %x VTf->regs %x\n", VTf
, VTf
->regs
);
711 if (ExceptionNr
== 6 &&
712 memcmp(Ip
, VTf
->regs
->RecoveryInstruction
, 4) == 0 &&
713 (Tf
->SegCs
* 16 + Tf
->Eip
) == VTf
->regs
->RecoveryAddress
)
715 *VTf
->regs
->PStatus
= STATUS_SUCCESS
;
720 * Handle the exceptions
726 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
731 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
736 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
741 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
746 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
749 /* Array bounds check */
751 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
756 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
759 /* Device not available */
761 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
766 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
771 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
776 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
779 /* Segment not present */
781 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
786 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
789 /* General protection fault */
791 return(KeV86GPF(VTf
, Tf
));
796 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
799 /* Alignment check */
801 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;
805 *VTf
->regs
->PStatus
= STATUS_NONCONTINUABLE_EXCEPTION
;