v86m.c

来自「一个类似windows」· C语言 代码 · 共 812 行 · 第 1/2 页

C
812
字号
/* $Id: v86m.c 21252 2006-03-08 20:03:59Z audit $
 *
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS kernel
 * FILE:            ntoskrnl/ke/i386/v86m.c
 * PURPOSE:         Support for v86 mode
 *
 * PROGRAMMERS:     David Welch (welch@cwcom.net)
 */

/* INCLUDES *****************************************************************/

#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>

/* GLOBALS *******************************************************************/

#define IOPL_FLAG          ((1 << 12) | (1 << 13))
#define INTERRUPT_FLAG     (1 << 9)
#define TRAP_FLAG          (1 << 8)
#define DIRECTION_FLAG     (1 << 10)

#define VALID_FLAGS         (0xDFF)

/* FUNCTIONS *****************************************************************/

ULONG
KeV86GPF(PKV86M_TRAP_FRAME VTf, PKTRAP_FRAME Tf)
{
  PUCHAR ip;
  PUSHORT sp;
  PULONG dsp;
  BOOL BigDataPrefix = FALSE;
  BOOL BigAddressPrefix = FALSE;
  BOOL RepPrefix = FALSE;
  ULONG i = 0;
  BOOL Exit = FALSE;

  ip = (PUCHAR)((Tf->SegCs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
  sp = (PUSHORT)((Tf->HardwareSegSs & 0xFFFF) * 16 + (Tf->HardwareEsp & 0xFFFF));
  dsp = (PULONG)sp;

  DPRINT("KeV86GPF handling %x at %x:%x ss:sp %x:%x Flags %x\n",
	 ip[0], Tf->SegCs, Tf->Eip, Tf->Ss, Tf->HardwareEsp, VTf->regs->Flags);

  while (!Exit)
    {
      switch (ip[i])
	{
	  /* 32-bit data prefix */
	case 0x66:
	  BigDataPrefix = TRUE;
    	  i++;
	  Tf->Eip++;
	  break;

	  /* 32-bit address prefix */
	case 0x67:
	  BigAddressPrefix = TRUE;
	  i++;
	  Tf->Eip++;
	  break;

	  /* rep prefix */
	case 0xFC:
	  RepPrefix = TRUE;
	  i++;
	  Tf->Eip++;
	  break;

	  /* sti */
	case 0xFB:
	  if (BigDataPrefix || BigAddressPrefix || RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
	    {
	      Tf->Eip++;
	      VTf->regs->Vif = 1;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* cli */
	case 0xFA:
	  if (BigDataPrefix || BigAddressPrefix || RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
	    {
	      Tf->Eip++;
	      VTf->regs->Vif = 0;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* pushf */
	case 0x9C:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
	    {
	      Tf->Eip++;
	      if (!BigAddressPrefix)
		{
		  Tf->HardwareEsp = Tf->HardwareEsp - 2;
		  sp = sp - 1;
		  sp[0] = (USHORT)(Tf->EFlags & 0xFFFF);
		  if (VTf->regs->Vif == 1)
		    {
		      sp[0] = (USHORT)(sp[0] | INTERRUPT_FLAG);
		    }
		  else
		    {
		      sp[0] = (USHORT)(sp[0] & (~INTERRUPT_FLAG));
		    }
		}
	      else
		{
		  Tf->HardwareEsp = Tf->HardwareEsp - 4;
		  dsp = dsp - 1;
		  dsp[0] = Tf->EFlags;
		  dsp[0] = dsp[0] & VALID_FLAGS;
		  if (VTf->regs->Vif == 1)
		    {
		      dsp[0] = dsp[0] | INTERRUPT_FLAG;
		    }
		  else
		    {
		      dsp[0] = dsp[0] & (~INTERRUPT_FLAG);
		    }
		}
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* popf */
	case 0x9D:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
	    {
	      Tf->Eip++;
	      if (!BigAddressPrefix)
		{
		  Tf->EFlags = Tf->EFlags & (~0xFFFF);
		  Tf->EFlags = Tf->EFlags | (sp[0] & VALID_FLAGS);
		  if (Tf->EFlags & INTERRUPT_FLAG)
		    {
		      VTf->regs->Vif = 1;
		    }
		  else
		    {
		      VTf->regs->Vif = 0;
		    }
		  Tf->EFlags = Tf->EFlags | INTERRUPT_FLAG;
		  Tf->HardwareEsp = Tf->HardwareEsp + 2;
		}
	      else
		{
		  Tf->EFlags = Tf->EFlags | (dsp[0] & VALID_FLAGS);
		  if (dsp[0] & INTERRUPT_FLAG)
		    {
		      VTf->regs->Vif = 1;
		    }
		  else
		    {
		      VTf->regs->Vif = 0;
		    }
		  Tf->EFlags = Tf->EFlags | INTERRUPT_FLAG;
		  Tf->HardwareEsp = Tf->HardwareEsp + 2;
		}
	      return(0);
	    }
	  Exit = TRUE;
	  break;

      /* iret */
	case 0xCF:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
	    {
	      Tf->Eip = sp[0];
	      Tf->SegCs = sp[1];
	      Tf->EFlags = Tf->EFlags & (~0xFFFF);
	      Tf->EFlags = Tf->EFlags | sp[2];
	      if (Tf->EFlags & INTERRUPT_FLAG)
		{
		  VTf->regs->Vif = 1;
		}
	      else
		{
		  VTf->regs->Vif = 0;
		}
	      Tf->EFlags = Tf->EFlags & (~INTERRUPT_FLAG);
	      Tf->HardwareEsp = Tf->HardwareEsp + 6;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* out imm8, al */
	case 0xE6:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      DPRINT("outb %d, %x\n", (ULONG)ip[i + 1], Tf->Eax & 0xFF);
	      WRITE_PORT_UCHAR((PUCHAR)(ULONG)ip[i + 1],
			       (UCHAR)(Tf->Eax & 0xFF));
	      Tf->Eip = Tf->Eip + 2;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* out imm8, ax */
	case 0xE7:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      if (!BigDataPrefix)
		{
		  DPRINT("outw %d, %x\n", (ULONG)ip[i + 1], Tf->Eax & 0xFFFF);
		  WRITE_PORT_USHORT((PUSHORT)(ULONG)ip[1], (USHORT)(Tf->Eax & 0xFFFF));
		}
	      else
		{
		  DPRINT("outl %d, %x\n", (ULONG)ip[i + 1], Tf->Eax);
		  WRITE_PORT_ULONG((PULONG)(ULONG)ip[1], Tf->Eax);
		}
	      Tf->Eip = Tf->Eip + 2;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* out dx, al */
	case 0xEE:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      DPRINT("outb %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax & 0xFF);
	      WRITE_PORT_UCHAR((PUCHAR)(Tf->Edx & 0xFFFF), (UCHAR)(Tf->Eax & 0xFF));
	      Tf->Eip = Tf->Eip + 1;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* out dx, ax */
	case 0xEF:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      if (!BigDataPrefix)
		{
		  DPRINT("outw %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax & 0xFFFF);
		  WRITE_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF),
				    (USHORT)(Tf->Eax & 0xFFFF));
		}
	      else
		{
		  DPRINT("outl %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax);
		  WRITE_PORT_ULONG((PULONG)(Tf->Edx & 0xFFFF),
				   Tf->Eax);
		}
	      Tf->Eip = Tf->Eip + 1;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* in al, imm8 */
	case 0xE4:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      UCHAR v;

	      v = READ_PORT_UCHAR((PUCHAR)(ULONG)ip[1]);
	      DPRINT("inb %d\t%X\n", (ULONG)ip[1], v);
	      Tf->Eax = Tf->Eax & (~0xFF);
	      Tf->Eax = Tf->Eax | v;
	      Tf->Eip = Tf->Eip + 2;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* in ax, imm8 */
	case 0xE5:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      if (!BigDataPrefix)
		{
		  USHORT v;
		  v = READ_PORT_USHORT((PUSHORT)(ULONG)ip[1]);
		  DPRINT("inw %d\t%X\n", (ULONG)ip[1], v);
		  Tf->Eax = Tf->Eax & (~0xFFFF);
		  Tf->Eax = Tf->Eax | v;
		}
	      else
		{
		  ULONG v;
		  v = READ_PORT_ULONG((PULONG)(ULONG)ip[1]);
		  DPRINT("inl %d\t%X\n", (ULONG)ip[1], v);
		  Tf->Eax = v;
		}
	      Tf->Eip = Tf->Eip + 2;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* in al, dx */
	case 0xEC:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      UCHAR v;

	      v = READ_PORT_UCHAR((PUCHAR)(Tf->Edx & 0xFFFF));
	      DPRINT("inb %d\t%X\n", Tf->Edx & 0xFFFF, v);
	      Tf->Eax = Tf->Eax & (~0xFF);
	      Tf->Eax = Tf->Eax | v;
	      Tf->Eip = Tf->Eip + 1;
	      return(0);
	    }
	  Exit = TRUE;
	  break;

	  /* in ax, dx */
	case 0xED:
	  if (RepPrefix)
	    {
	      *VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
	      return(1);
	    }
	  if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
	    {
	      if (!BigDataPrefix)
		{
		  USHORT v;

		  v = READ_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF));
		  DPRINT("inw %d\t%X\n", Tf->Edx & 0xFFFF, v);
		  Tf->Eax = Tf->Eax & (~0xFFFF);
		  Tf->Eax = Tf->Eax | v;
		}
	      else
		{
		  ULONG v;

		  v = READ_PORT_ULONG((PULONG)(Tf->Edx & 0xFFFF));
		  DPRINT("inl %d\t%X\n", Tf->Edx & 0xFFFF, v);
		  Tf->Eax = v;
		}
	      Tf->Eip = Tf->Eip + 1;
	      return(0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?