/*
* PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/ke/i386/v86vdm.c
- * PURPOSE: Manages the Kernel's support for Virtual-8086 Mode (V86)
- * used by Video Drivers to access ROM BIOS functions, as well
- * as the kernel architecture part of generic VDM support.
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ * PURPOSE: V8086 and VDM Trap Emulation
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ * Alex Ionescu (alex.ionescu@reactos.org)
*/
-/* INCLUDES ******************************************************************/
+/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
-/* GLOBALS *******************************************************************/
+#define KiVdmGetInstructionSize(x) ((x) & 0xFF)
+#define KiVdmGetPrefixFlags(x) ((x) & 0xFFFFFF00)
+
+/* GLOBALS ********************************************************************/
ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE;
ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
PVOID Ki386IopmSaveArea;
BOOLEAN KeI386VirtualIntExtensions = FALSE;
+const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT;
+
+/* UNHANDLED OPCODES **********************************************************/
+
+KiVdmUnhandledOpcode(F);
+KiVdmUnhandledOpcode(OUTSW);
+KiVdmUnhandledOpcode(OUTSB);
+KiVdmUnhandledOpcode(INSB);
+KiVdmUnhandledOpcode(INSW);
+KiVdmUnhandledOpcode(NPX);
+KiVdmUnhandledOpcode(INBimm);
+KiVdmUnhandledOpcode(INWimm);
+KiVdmUnhandledOpcode(OUTBimm);
+KiVdmUnhandledOpcode(OUTWimm);
+KiVdmUnhandledOpcode(INB);
+KiVdmUnhandledOpcode(INW);
+KiVdmUnhandledOpcode(OUTB);
+KiVdmUnhandledOpcode(OUTW);
+KiVdmUnhandledOpcode(HLT);
+KiVdmUnhandledOpcode(INTO);
+KiVdmUnhandledOpcode(INV);
+
+/* OPCODE HANDLERS ************************************************************/
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ ULONG Esp, V86EFlags, TrapEFlags;
+
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
+ /* Get current V8086 flags and mask out interrupt flag */
+ V86EFlags = *KiNtVdmState;
+ V86EFlags &= ~EFLAGS_INTERRUPT_MASK;
+
+ /* Get trap frame EFLags and leave only align, nested task and interrupt */
+ TrapEFlags = TrapFrame->EFlags;
+ V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
+
+ /* Add in those flags if they exist, and add in the IOPL flag */
+ V86EFlags |= TrapEFlags;
+ V86EFlags |= EFLAGS_IOPL;
+
+ /* Build flat ESP */
+ Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
+
+ /* Check for OPER32 */
+ if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32)
+ {
+ /* Save EFlags */
+ Esp -= 4;
+ *(PULONG)Esp = V86EFlags;
+ }
+ else
+ {
+ /* Save EFLags */
+ Esp -= 2;
+ *(PUSHORT)Esp = (USHORT)V86EFlags;
+ }
+
+ /* Set new ESP and EIP */
+ TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4);
+ TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
+
+ /* We're done */
+ return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ ULONG Esp, V86EFlags, EFlags, TrapEFlags;
+
+ /* Build flat ESP */
+ Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
+
+ /* Check for OPER32 */
+ if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32)
+ {
+ /* Read EFlags */
+ EFlags = *(PULONG)Esp;
+ Esp += 4;
+ }
+ else
+ {
+ /* Read EFlags */
+ EFlags = *(PUSHORT)Esp;
+ Esp += 2;
+ }
+
+ /* Set new ESP */
+ TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4);
+
+ /* Mask out IOPL from the flags */
+ EFlags &= ~EFLAGS_IOPL;
+
+ /* Save the V86 flags, but mask out the nested task flag */
+ V86EFlags = EFlags & ~EFLAGS_NESTED_TASK;
+
+ /* Now leave only alignment, nested task and interrupt flag */
+ EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
+
+ /* Get trap EFlags */
+ TrapEFlags = TrapFrame->EFlags;
+
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
+ /* Add V86 and Interrupt flag */
+ V86EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
+
+ /* Update EFlags in trap frame */
+ TrapFrame->EFlags = V86EFlags;
+
+ /* Check if ESP0 needs to be fixed up */
+ if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame);
+
+ /* Update the V8086 EFlags state */
+ KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
+ KiVdmSetVdmEFlags(EFlags);
+
+ /* FIXME: Check for VDM interrupts */
+
+ /* Update EIP */
+ TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
+
+ /* We're done */
+ return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ ULONG Esp, V86EFlags, TrapEFlags, Eip, Interrupt;
+
+ /* Read trap frame EFlags */
+ TrapEFlags = TrapFrame->EFlags;
+
+ /* Remove interrupt flag from V8086 EFlags */
+ V86EFlags = *KiNtVdmState;
+ KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
+
+ /* Keep only alignment and interrupt flag from the V8086 state */
+ V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK);
+
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
+ /* Mask in the relevant V86 EFlags into the trap flags */
+ V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK);
+
+ /* And mask out the VIF, nested task and TF flag from the trap flags */
+ TrapFrame->EFlags = TrapEFlags &~ (EFLAGS_VIF | EFLAGS_NESTED_TASK | EFLAGS_TF);
+
+ /* Add the IOPL flag to the local trap flags */
+ V86EFlags |= EFLAGS_IOPL;
+
+ /* Build flat ESP */
+ Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
+
+ /* Push EFlags */
+ Esp -= 2;
+ *(PUSHORT)(Esp) = (USHORT)V86EFlags;
+
+ /* Push CS */
+ Esp -= 2;
+ *(PUSHORT)(Esp) = (USHORT)TrapFrame->SegCs;
+
+ /* Push IP */
+ Esp -= 2;
+ *(PUSHORT)(Esp) = (USHORT)TrapFrame->Eip + KiVdmGetInstructionSize(Flags) + 1;
+
+ /* Update ESP */
+ TrapFrame->HardwareEsp = (USHORT)Esp;
+
+ /* Get flat EIP */
+ Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
+
+ /* Now get the *next* EIP address (current is original + the count - 1) */
+ Eip += KiVdmGetInstructionSize(Flags);
+
+ /* Now read the interrupt number */
+ Interrupt = *(PUCHAR)Eip;
+
+ /* Read the EIP from its IVT entry */
+ Interrupt = *(PULONG)(Interrupt * 4);
+ TrapFrame->Eip = (USHORT)Interrupt;
+
+ /* Now get the CS segment */
+ Interrupt = (USHORT)(Interrupt >> 16);
+
+ /* Check if the trap was not V8086 trap */
+ if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
+ {
+ /* Was it a kernel CS? */
+ Interrupt |= RPL_MASK;
+ if (TrapFrame->SegCs == KGDT_R0_CODE)
+ {
+ /* Add the RPL mask */
+ TrapFrame->SegCs = Interrupt;
+ }
+ else
+ {
+ /* Set user CS */
+ TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
+ }
+ }
+ else
+ {
+ /* Set IVT CS */
+ TrapFrame->SegCs = Interrupt;
+ }
+
+ /* We're done */
+ return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ ULONG Esp, V86EFlags, EFlags, TrapEFlags, Eip;
+
+ /* Build flat ESP */
+ Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
+
+ /* Check for OPER32 */
+ if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32)
+ {
+ /* Build segmented EIP */
+ TrapFrame->Eip = *(PULONG)Esp;
+ TrapFrame->SegCs = *(PUSHORT)(Esp + 4);
+
+ /* Set new ESP */
+ TrapFrame->HardwareEsp += 12;
+
+ /* Get EFLAGS */
+ EFlags = *(PULONG)(Esp + 8);
+ }
+ else
+ {
+ /* Build segmented EIP */
+ TrapFrame->Eip = *(PUSHORT)Esp;
+ TrapFrame->SegCs = *(PUSHORT)(Esp + 2);
+
+ /* Set new ESP */
+ TrapFrame->HardwareEsp += 6;
+
+ /* Get EFLAGS */
+ EFlags = *(PUSHORT)(Esp + 4);
+ }
+
+ /* Mask out EFlags */
+ EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP);
+ V86EFlags = EFlags;
+
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
+ /* Add V86 and Interrupt flag */
+ EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
+
+ /* Update EFlags in trap frame */
+ TrapEFlags = TrapFrame->EFlags;
+ TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | EFlags;
+
+ /* Check if ESP0 needs to be fixed up */
+ if (!(TrapEFlags & EFLAGS_V86_MASK)) Ki386AdjustEsp0(TrapFrame);
+
+ /* Update the V8086 EFlags state */
+ KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
+ KiVdmSetVdmEFlags(V86EFlags);
+
+ /* Build flat EIP and check if this is the BOP instruction */
+ Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
+ if (*(PUSHORT)Eip == 0xC4C4)
+ {
+ /* Dispatch the BOP */
+ VdmDispatchBop(TrapFrame);
+ }
+ else
+ {
+ /* FIXME: Check for VDM interrupts */
+ DPRINT("FIXME: Check for VDM interrupts\n");
+ }
+
+ /* We're done */
+ return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
+ /* Disable interrupts */
+ KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
+
+ /* Skip instruction */
+ TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
+
+ /* Done */
+ return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
+ /* Enable interrupts */
+ KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK);
+
+ /* Skip instruction */
+ TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
+
+ /* Done */
+ return TRUE;
+}
+
+/* MASTER OPCODE HANDLER ******************************************************/
+
+BOOLEAN
+FASTCALL
+KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ ULONG Eip;
+
+ /* Get flat EIP of the *current* instruction (not the original EIP) */
+ Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
+ Eip += KiVdmGetInstructionSize(Flags) - 1;
+
+ /* Read the opcode entry */
+ switch (*(PUCHAR)Eip)
+ {
+ case 0xF: return KiCallVdmHandler(F);
+ case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES);
+ case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS);
+ case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS);
+ case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS);
+ case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS);
+ case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS);
+ case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32);
+ case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32);
+ case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK);
+ case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE);
+ case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP);
+ case 0x6C: return KiCallVdmHandler(INSB);
+ case 0x6D: return KiCallVdmHandler(INSW);
+ case 0x6E: return KiCallVdmHandler(OUTSB);
+ case 0x6F: return KiCallVdmHandler(OUTSW);
+ case 0x98: return KiCallVdmHandler(NPX);
+ case 0xD8: return KiCallVdmHandler(NPX);
+ case 0xD9: return KiCallVdmHandler(NPX);
+ case 0xDA: return KiCallVdmHandler(NPX);
+ case 0xDB: return KiCallVdmHandler(NPX);
+ case 0xDC: return KiCallVdmHandler(NPX);
+ case 0xDD: return KiCallVdmHandler(NPX);
+ case 0xDE: return KiCallVdmHandler(NPX);
+ case 0xDF: return KiCallVdmHandler(NPX);
+ case 0x9C: return KiCallVdmHandler(PUSHF);
+ case 0x9D: return KiCallVdmHandler(POPF);
+ case 0xCD: return KiCallVdmHandler(INTnn);
+ case 0xCE: return KiCallVdmHandler(INTO);
+ case 0xCF: return KiCallVdmHandler(IRET);
+ case 0xE4: return KiCallVdmHandler(INBimm);
+ case 0xE5: return KiCallVdmHandler(INWimm);
+ case 0xE6: return KiCallVdmHandler(OUTBimm);
+ case 0xE7: return KiCallVdmHandler(OUTWimm);
+ case 0xEC: return KiCallVdmHandler(INB);
+ case 0xED: return KiCallVdmHandler(INW);
+ case 0xEE: return KiCallVdmHandler(OUTB);
+ case 0xEF: return KiCallVdmHandler(OUTW);
+ case 0xF4: return KiCallVdmHandler(HLT);
+ case 0xFA: return KiCallVdmHandler(CLI);
+ case 0xFB: return KiCallVdmHandler(STI);
+ default: return KiCallVdmHandler(INV);
+ }
+}
+
+/* PREFIX HANDLER *************************************************************/
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Flags)
+{
+ /* Increase instruction size */
+ Flags++;
+
+ /* Handle the next opcode */
+ return KiVdmHandleOpcode(TrapFrame, Flags);
+}
+
+/* TRAP HANDLER ***************************************************************/
+
+BOOLEAN
+FASTCALL
+Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame)
+{
+ /* Clean up */
+ TrapFrame->Eip &= 0xFFFF;
+ TrapFrame->HardwareEsp &= 0xFFFF;
-/* PRIVATE FUNCTIONS *********************************************************/
+ /* We start with only 1 byte per instruction */
+ return KiVdmHandleOpcode(TrapFrame, 1);
+}
+
+ULONG_PTR
+FASTCALL
+KiExitV86Mode(IN PKTRAP_FRAME TrapFrame)
+{
+ PKV8086_STACK_FRAME StackFrame;
+ PKGDTENTRY GdtEntry;
+ PKTHREAD Thread;
+ PKTRAP_FRAME PmTrapFrame;
+ PKV86_FRAME V86Frame;
+ PFX_SAVE_AREA NpxFrame;
+
+ /* Get the stack frame back */
+ StackFrame = CONTAINING_RECORD(TrapFrame->Esi, KV8086_STACK_FRAME, V86Frame);
+ PmTrapFrame = &StackFrame->TrapFrame;
+ V86Frame = &StackFrame->V86Frame;
+ NpxFrame = &StackFrame->NpxArea;
+
+ /* Copy the FPU frame back */
+ Thread = KeGetCurrentThread();
+ RtlCopyMemory(KiGetThreadNpxArea(Thread), NpxFrame, sizeof(FX_SAVE_AREA));
-/* PUBLIC FUNCTIONS **********************************************************/
+ /* Set initial stack back */
+ Thread->InitialStack = (PVOID)((ULONG_PTR)V86Frame->ThreadStack + sizeof(FX_SAVE_AREA));
+
+ /* Set ESP0 back in the KTSS */
+ KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&PmTrapFrame->V86Es;
+
+ /* Restore TEB addresses */
+ Thread->Teb = V86Frame->ThreadTeb;
+ KeGetPcr()->NtTib.Self = V86Frame->PcrTeb;
+
+ /* Setup real TEB descriptor */
+ GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
+ GdtEntry->BaseLow = (USHORT)((ULONG_PTR)Thread->Teb & 0xFFFF);
+ GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Thread->Teb >> 16);
+ GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Thread->Teb >> 24);
+
+ /* Enable interrupts and return a pointer to the trap frame */
+ _enable();
+ return (ULONG)PmTrapFrame;
+}
+
+VOID
+FASTCALL
+KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame)
+{
+ PKTHREAD Thread;
+ PKGDTENTRY GdtEntry;
+ PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame;
+ PKV86_FRAME V86Frame = &StackFrame->V86Frame;
+ PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea;
+
+ /* Build fake user-mode trap frame */
+ TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK;
+ TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0;
+ TrapFrame->ErrCode = 0;
+
+ /* Get the current thread's initial stack */
+ Thread = KeGetCurrentThread();
+ V86Frame->ThreadStack = KiGetThreadNpxArea(Thread);
+
+ /* Save TEB addresses */
+ V86Frame->ThreadTeb = Thread->Teb;
+ V86Frame->PcrTeb = KeGetPcr()->NtTib.Self;
+
+ /* Save return EIP */
+ TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress;
+
+ /* Save our stack (after the frames) */
+ TrapFrame->Esi = (ULONG_PTR)V86Frame;
+ TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4;
+
+ /* Sanitize EFlags and enable interrupts */
+ TrapFrame->EFlags = __readeflags() & 0x60DD7;
+ TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
+
+ /* Fill out the rest of the frame */
+ TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
+ TrapFrame->HardwareEsp = 0x11FFE;
+ TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
+ TrapFrame->Dr7 = 0;
+ //TrapFrame->DbgArgMark = 0xBADB0D00;
+ TrapFrame->PreviousPreviousMode = -1;
+
+ /* Disable interrupts */
+ _disable();
+
+ /* Copy the thread's NPX frame */
+ RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA));
+
+ /* Clear exception list */
+ KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
+
+ /* Set new ESP0 */
+ KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es;
+
+ /* Set new initial stack */
+ Thread->InitialStack = V86Frame;
+
+ /* Set VDM TEB */
+ Thread->Teb = (PTEB)TRAMPOLINE_TEB;
+ KeGetPcr()->NtTib.Self = (PVOID)TRAMPOLINE_TEB;
+
+ /* Setup VDM TEB descriptor */
+ GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
+ GdtEntry->BaseLow = (USHORT)((ULONG_PTR)TRAMPOLINE_TEB & 0xFFFF);
+ GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 16);
+ GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 24);
+
+ /* Enable interrupts */
+ _enable();
+
+ /* Start VDM execution */
+ NtVdmControl(VdmStartExecution, NULL);
+
+ /* Exit to V86 mode */
+ KiEoiHelper(TrapFrame);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
/* Allocate VDM structure */
VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool,
sizeof(VDM_PROCESS_OBJECTS),
- TAG('K', 'e', ' ', ' '));
+ ' eK');
if (!VdmProcessObjects) return STATUS_NO_MEMORY;
/* Set it up */
KeSetSystemAffinityThread(1);
/* Make sure there's space for two IOPMs, then copy & clear the current */
- //ASSERT(((PKGDTENTRY)&KeGetPcr()->GDT[KGDT_TSS / 8])->LimitLow >=
- // (0x2000 + IOPM_OFFSET - 1));
+ ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >=
+ (0x2000 + IOPM_OFFSET - 1));
RtlCopyMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
RtlZeroMemory(&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
return STATUS_SUCCESS;
}
-/* EOF */
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+Ke386IoSetAccessProcess(IN PKPROCESS Process,
+ IN ULONG MapNumber)
+{
+ USHORT MapOffset;
+ PKPRCB Prcb;
+ KAFFINITY TargetProcessors;
+
+ if(MapNumber > IOPM_COUNT)
+ return FALSE;
+
+ MapOffset = KiComputeIopmOffset(MapNumber);
+
+ Process->IopmOffset = MapOffset;
+
+ TargetProcessors = Process->ActiveProcessors;
+ Prcb = KeGetCurrentPrcb();
+ if (TargetProcessors & Prcb->SetMember)
+ KeGetPcr()->TSS->IoMapBase = MapOffset;
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+Ke386SetIoAccessMap(IN ULONG MapNumber,
+ IN PKIO_ACCESS_MAP IopmBuffer)
+{
+ PKPROCESS CurrentProcess;
+ PKPRCB Prcb;
+ PVOID pt;
+
+ if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE))
+ return FALSE;
+
+ Prcb = KeGetCurrentPrcb();
+
+ // Copy the IOP map and load the map for the current process.
+ pt = &(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap);
+ RtlMoveMemory(pt, (PVOID)IopmBuffer, IOPM_SIZE);
+ CurrentProcess = Prcb->CurrentThread->ApcState.Process;
+ KeGetPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset;
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+Ke386QueryIoAccessMap(IN ULONG MapNumber,
+ IN PKIO_ACCESS_MAP IopmBuffer)
+{
+ ULONG i;
+ PVOID Map;
+ PUCHAR p;
+
+ if (MapNumber > IOPM_COUNT)
+ return FALSE;
+
+ if (MapNumber == IO_ACCESS_MAP_NONE)
+ {
+ // no access, simply return a map of all 1s
+ p = (PUCHAR)IopmBuffer;
+ for (i = 0; i < IOPM_SIZE; i++) {
+ p[i] = (UCHAR)-1;
+ }
+ }
+ else
+ {
+ // copy the bits
+ Map = (PVOID)&(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap);
+ RtlMoveMemory((PVOID)IopmBuffer, Map, IOPM_SIZE);
+ }
+
+ return TRUE;
+}