/*++ Copyright (c) 1991 Microsoft Corporation Module Name: vdmuserrefs.c Abstract: This module contains routines that probe and fetch from the instruction stream to make the vdm bop support solid. Author: Neill Clift (NeillC) 27-Jun-2001 Revision History: --*/ #include "vdmp.h" #pragma alloc_text (PAGE, VdmFetchBop1) #pragma alloc_text (PAGE, VdmFetchBop4) #pragma alloc_text (PAGE, VdmDispatchOpcodeV86_try) #pragma alloc_text (PAGE, VdmTibPass1) #pragma alloc_text (PAGE, VdmDispatchBop) #pragma alloc_text (PAGE, VdmFetchULONG) VOID NTFastDOSIO ( PKTRAP_FRAME TrapFrame, ULONG IoType ); ULONG VdmFetchBop4 ( IN PVOID Pc ) /*++ Routine Description: This routine reads up to 4 bytes of bop instruction data Arguments: Pc - Program counter fetched from the faulting instruction's trap frame. Return Value: ULONG - Up to 4 bytes of instruction stream. Unfetchable bytes are zeroed. --*/ { ULONG Value; ULONG i; BOOLEAN DidProbe; DidProbe = FALSE; try { ProbeForReadSmallStructure (Pc, sizeof (UCHAR), sizeof (UCHAR)); DidProbe = TRUE; return *(PULONG)Pc; } except (EXCEPTION_EXECUTE_HANDLER) { if (DidProbe == FALSE) { return 0; } } Value = 0; try { for (i = 0; i < sizeof (ULONG); i++) { Value += (((PUCHAR)Pc)[i])<<(i*8); } } except (EXCEPTION_EXECUTE_HANDLER) { } return Value; } ULONG VdmFetchULONG ( IN PVOID Pc ) /*++ Routine Description: This routine reads 4 bytes from the user address space Arguments: Pc - Program counter fetched from the faulting instruction's trap frame. Return Value: ULONG - 4 bytes of user mode data --*/ { try { ProbeForReadSmallStructure (Pc, sizeof (ULONG), sizeof (UCHAR)); return *(PULONG)Pc; } except (EXCEPTION_EXECUTE_HANDLER) { return 0; } } ULONG VdmFetchBop1 ( IN PVOID Pc ) /*++ Routine Description: This routine reads a single byte of bop instruction data. Arguments: Pc - Program counter fetched from the faulting instruction's trap frame Return Value: ULONG - 1 byte of instruction stream or zero if unreadable --*/ { try { ProbeForReadSmallStructure (Pc, sizeof (UCHAR), sizeof (UCHAR)); return *(PUCHAR)Pc; } except (EXCEPTION_EXECUTE_HANDLER) { return 0; } } ULONG VdmDispatchOpcodeV86_try ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This routine is just a shell around trap.asm code to handle faulting instruction stream references. This routines is called at APC_LEVEL to prevent NtSetContextThread from changing the EIP after its been probed earlier. Arguments: Pc - Program counter fetched from the faulting instructions trap frame Return Value: ULONG - 1 byte of instruction stream or zero if unreadable --*/ { try { return Ki386DispatchOpcodeV86 (TrapFrame); } except (EXCEPTION_EXECUTE_HANDLER) { return 0; } } PVOID VdmTibPass1 ( IN ULONG Cs, IN ULONG Eip, IN ULONG Ebx ) { PVDM_TIB VdmTib; // // Copy the specified registers to the VDM Tib communication area, // using proper probing and exception handling. // try { VdmTib = NtCurrentTeb()->Vdm; ProbeForWrite (VdmTib, sizeof(VDM_TIB), sizeof(UCHAR)); VdmTib->VdmContext.Ebx = Ebx; VdmTib->VdmContext.Eip = Eip; VdmTib->VdmContext.SegCs = Cs; } except (EXCEPTION_EXECUTE_HANDLER) { return NULL; } return VdmTib; } #define BOP_INSTRUCTION 0xC4C4 #define SVC_DEMFASTREAD 0x42 #define SVC_DEMFASTWRITE 0x43 #define DOS_BOP 0x50 extern ULONG VdmBopCount; LOGICAL VdmDispatchBop ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This routine attempts to decode and execute the user instruction. If this cannot be done, FALSE is returned and the ntvdm monitor must handle it. Arguments: TrapFrame - Supplies a pointer to register trapframe. Return Value: TRUE if the opcode was handled here. FALSE if not (ie: the caller must reflect this instruction to ntvdm to handle on behalf of the 16-bit app). Environment: Kernel mode, APC_LEVEL. --*/ { LOGICAL RetVal; BOOLEAN GotSelector; PVDM_TIB VdmTib; ULONG SegCs; ULONG LinearEIP; ULONG Flags; ULONG Base; ULONG Limit; ULONG IoType; LOGICAL DoFastIo; if (TrapFrame->EFlags & EFLAGS_V86_MASK) { SegCs = TrapFrame->SegCs & 0xFFFF; LinearEIP = (SegCs << 4) + (TrapFrame->Eip & 0xffff); } else { GotSelector = Ki386GetSelectorParameters ((USHORT) TrapFrame->SegCs, &Flags, &Base, &Limit); if (GotSelector == FALSE) { return TRUE; } LinearEIP = Base + TrapFrame->Eip; } DoFastIo = FALSE; RetVal = TRUE; try { ProbeForReadSmallStructure (LinearEIP, sizeof (UCHAR), sizeof (UCHAR)); if (*(PUSHORT)LinearEIP != BOP_INSTRUCTION) { RetVal = FALSE; leave; } // // Check the BOP number. // if (*(PUCHAR)(LinearEIP + 2) == DOS_BOP) { if ((*(PUCHAR)(LinearEIP + 3) == SVC_DEMFASTREAD) || (*(PUCHAR)(LinearEIP + 3) == SVC_DEMFASTWRITE)) { // // Take the fast I/O path. // IoType = (ULONG)(*(PUCHAR)(LinearEIP + 3)); DoFastIo = TRUE; leave; } } VdmBopCount += 1; VdmTib = NtCurrentTeb()->Vdm; ProbeForWrite (VdmTib, sizeof(VDM_TIB), sizeof(UCHAR)); VdmTib->EventInfo.Event = VdmBop; VdmTib->EventInfo.BopNumber = *(PUCHAR)(LinearEIP + 2); VdmTib->EventInfo.InstructionSize = 3; VdmEndExecution (TrapFrame, VdmTib); } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = FALSE; NOTHING; // Fall through } if (DoFastIo) { NTFastDOSIO (TrapFrame, IoType); } return RetVal; }