test: vdm.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# vdm.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1990  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     VDM.C
    00008
    00009 Abstract:
    00010
    00011     This module contains support routines for the x86 monitor for
    00012     running Dos applications in V86 mode.
    00013
    00014 Author:
    00015
    00016     Dave Hastings (daveh) 20 Mar 1991
    00017
    00018 Environment:
    00019
    00020     The code in this module is all x86 and EM specific.
    00021
    00022 Notes:
    00023
    00024     In its current implementation, this code is less robust than it needs
    00025     to be.  This will be fixed.  Specifically, parameter verification needs
    00026     to be done. (daveh 7/15/91)
    00027
    00028     Support for 32 bit segements (2/2/92)
    00029 Revision History:
    00030
    00031     20-Mar-1991 daveh
    00032         created
    00033     Charles Spirakis (intel) 23 Jun 1996 - Starting to move the necessary
    00034     code from the i386 environment to the EM environment. This code was
    00035         shamelessly stolen from ../i386/vdm.c
    00036 --*/
    00037 #include "ki.h"
    00038 #include "ia32def.h"
    00039 #include "vdmntos.h"
    00040
    00041 // The beginnings of the real VDM code for the EM port
    00042
    00043 ULONG KeIA32EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE;
    00044 ULONG KeIA32EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
    00045 BOOLEAN KeIA32VdmIoplAllowed = FALSE;
    00046 ULONG KeIA32VirtualIntExtensions = 0;
    00047
    00048 KMUTEX VdmStringIoMutex;
    00049 PULONG VdmFixedStateLinear;
    00050
    00051
    00052 #if !defined(WX86)
    00053
    00054 NTSTATUS
    00055 NtInitializeVDM(
    00056     VOID
    00057     )
    00058 {
    00059     return STATUS_SUCCESS;
    00060 }
    00061
    00062 NTSTATUS
    00063 NtVdmStartExecution (
    00064     )
    00065
    00066 /*++
    00067
    00068 Routine Description:
    00069
    00070     This routine returns STATUS_NOT_IMPLEMENTED
    00071
    00072 Arguments:
    00073
    00074 Return Value:
    00075
    00076     STATUS_NOT_IMPLEMENTED
    00077 --*/
    00078 {
    00079
    00080     return STATUS_NOT_IMPLEMENTED;
    00081
    00082 }
    00083
    00084 #else    // WX86
    00085
    00086 #pragma hdrstop
    00087
    00088 #define VDM_IO_TEST 0
    00089
    00090 #if VDM_IO_TEST
    00091 VOID
    00092 TestIoHandlerStuff(
    00093     VOID
    00094     );
    00095 #endif
    00096
    00097 #if DBG
    00098 VOID
    00099 PspPrintDescriptor(
    00100     IN PLDT_ENTRY Descriptor
    00101     );
    00102
    00103 extern ULONG fShowLdt;
    00104 #endif
    00105
    00106
    00107 BOOLEAN
    00108 KiIA32VdmDispatchIo(
    00109     IN ULONG PortNumber,
    00110     IN ULONG Size,
    00111     IN BOOLEAN Read,
    00112     IN UCHAR InstructionSize,
    00113     IN PKIA32_FRAME TrapFrame
    00114     );
    00115
    00116 BOOLEAN
    00117 KiIA32VdmDispatchStringIo(
    00118     IN ULONG PortNumber,
    00119     IN ULONG Size,
    00120     IN BOOLEAN Rep,
    00121     IN BOOLEAN Read,
    00122     IN ULONG Count,
    00123     IN ULONG Address,
    00124     IN UCHAR InstructionSize,
    00125     IN PKIA32_FRAME TrapFrame
    00126     );
    00127
    00128
    00129 BOOLEAN
    00130 VdmDispatchIoToHandler(
    00131     IN PVDM_IO_HANDLER VdmIoHandler,
    00132     IN ULONG Context,
    00133     IN ULONG PortNumber,
    00134     IN ULONG Size,
    00135     IN BOOLEAN Read,
    00136     IN OUT PULONG Data
    00137     );
    00138
    00139 BOOLEAN
    00140 VdmDispatchUnalignedIoToHandler(
    00141     IN PVDM_IO_HANDLER VdmIoHandler,
    00142     IN ULONG Context,
    00143     IN ULONG PortNumber,
    00144     IN ULONG Size,
    00145     IN BOOLEAN Read,
    00146     IN OUT PULONG Data
    00147     );
    00148
    00149 BOOLEAN
    00150 VdmDispatchStringIoToHandler(
    00151     IN PVDM_IO_HANDLER VdmIoHandler,
    00152     IN ULONG Context,
    00153     IN ULONG PortNumber,
    00154     IN ULONG Size,
    00155     IN ULONG Count,
    00156     IN BOOLEAN Read,
    00157     IN ULONG Data
    00158     );
    00159
    00160 BOOLEAN
    00161 VdmCallStringIoHandler(
    00162     IN PVDM_IO_HANDLER VdmIoHandler,
    00163     IN PVOID StringIoRoutine,
    00164     IN ULONG Context,
    00165     IN ULONG PortNumber,
    00166     IN ULONG Size,
    00167     IN ULONG Count,
    00168     IN BOOLEAN Read,
    00169     IN ULONG Data
    00170     );
    00171
    00172 BOOLEAN
    00173 VdmConvertToLinearAddress(
    00174     IN ULONG SegmentedAddress,
    00175     IN PVOID *LinearAddress
    00176     );
    00177
    00178 VOID
    00179 KeIA32VdmInitialize(
    00180     VOID
    00181     );
    00182
    00183 ULONG
    00184 KiIA32VdmEnablePentiumExtentions(
    00185     ULONG
    00186     );
    00187
    00188 #ifdef ALLOC_PRAGMA
    00189 #pragma alloc_text(PAGE, KiIA32VdmDispatchIo)
    00190 #pragma alloc_text(PAGE, KiIA32VdmDispatchStringIo)
    00191 #pragma alloc_text(PAGE, VdmDispatchIoToHandler)
    00192 #pragma alloc_text(PAGE, VdmDispatchUnalignedIoToHandler)
    00193 #pragma alloc_text(PAGE, VdmDispatchStringIoToHandler)
    00194 #pragma alloc_text(PAGE, VdmCallStringIoHandler)
    00195 #pragma alloc_text(PAGE, VdmConvertToLinearAddress)
    00196 #pragma alloc_text(INIT, KeIA32VdmInitialize)
    00197 #endif
    00198
    00199
    00200 BOOLEAN
    00201 KiIA32VdmDispatchIo(
    00202     IN ULONG PortNumber,
    00203     IN ULONG Size,
    00204     IN BOOLEAN Read,
    00205     IN UCHAR InstructionSize,
    00206     IN PKIA32_FRAME TrapFrame
    00207     )
    00208 /*++
    00209
    00210 Routine Description:
    00211
    00212     This routine sets up the Event info for an IO event, and causes the
    00213     event to be reflected to the Monitor.
    00214
    00215     It is assumed that interrupts are enabled upon entry, and Irql is
    00216     at APC level.
    00217
    00218 Arguments:
    00219
    00220     PortNumber -- Supplies the port number the IO was done to
    00221     Size -- Supplies the size of the IO operation.
    00222     Read -- Indicates whether the IO operation was a read or a write.
    00223     InstructionSize -- Supplies the size of the IO instruction in bytes.
    00224
    00225 Return Value:
    00226
    00227     True if the io instruction will be reflected to User mode.
    00228
    00229 --*/
    00230 {
    00231     PVDM_TIB VdmTib;
    00232     EXCEPTION_RECORD ExceptionRecord;
    00233     VDM_IO_HANDLER VdmIoHandler;
    00234     ULONG Result;
    00235     BOOLEAN Success = FALSE;
    00236     ULONG Context;
    00237
    00238     Success = PsIA32GetVdmIoHandler(
    00239         PsGetCurrentProcess(),
    00240         PortNumber & ~0x3,
    00241         &VdmIoHandler,
    00242         &Context
    00243         );
    00244
    00245     if (Success) {
    00246         Result = TrapFrame->Eax;
    00247         // if port is not aligned, perform unaligned IO
    00248         // else do the io the easy way
    00249         if (PortNumber % Size) {
    00250             Success = VdmDispatchUnalignedIoToHandler(
    00251                 &VdmIoHandler,
    00252                 Context,
    00253                 PortNumber,
    00254                 Size,
    00255                 Read,
    00256                 &Result
    00257                 );
    00258         } else {
    00259             Success = VdmDispatchIoToHandler(
    00260                 &VdmIoHandler,
    00261                 Context,
    00262                 PortNumber,
    00263                 Size,
    00264                 Read,
    00265                 &Result
    00266                 );
    00267         }
    00268     }
    00269
    00270     if (Success) {
    00271         if (Read) {
    00272             switch (Size) {
    00273             case 4:
    00274                 TrapFrame->Eax = Result;
    00275                 break;
    00276             case 2:
    00277                 *(PUSHORT)(&TrapFrame->Eax) = (USHORT)Result;
    00278                 break;
    00279             case 1:
    00280                 *(PUCHAR)(&TrapFrame->Eax) = (UCHAR)Result;
    00281                 break;
    00282             }
    00283         }
    00284         TrapFrame->Eip += (ULONG) InstructionSize;
    00285         return TRUE;
    00286     } else {
    00287         try {
    00288             VdmTib = NtCurrentTeb()->Vdm;
    00289             VdmTib->EventInfo.InstructionSize = (ULONG) InstructionSize;
    00290             VdmTib->EventInfo.Event = VdmIO;
    00291             VdmTib->EventInfo.IoInfo.PortNumber = (USHORT)PortNumber;
    00292             VdmTib->EventInfo.IoInfo.Size = (USHORT)Size;
    00293             VdmTib->EventInfo.IoInfo.Read = Read;
    00294         } except(EXCEPTION_EXECUTE_HANDLER) {
    00295             ExceptionRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
    00296             ExceptionRecord.ExceptionFlags = 0;
    00297             ExceptionRecord.NumberParameters = 0;
    00298             ExRaiseException(&ExceptionRecord);
    00299             return FALSE;
    00300         }
    00301     }
    00302
    00303     VdmEndExecution(TrapFrame, VdmTib);
    00304
    00305     return TRUE;
    00306 }
    00307
    00308
    00309 BOOLEAN
    00310 KiIA32VdmDispatchStringIo(
    00311     IN ULONG PortNumber,
    00312     IN ULONG Size,
    00313     IN BOOLEAN Rep,
    00314     IN BOOLEAN Read,
    00315     IN ULONG Count,
    00316     IN ULONG Address,
    00317     IN UCHAR InstructionSize,
    00318     IN PKIA32_FRAME TrapFrame
    00319     )
    00320 /*++
    00321
    00322 Routine Description:
    00323
    00324     This routine sets up the Event info for a string IO event, and causes the
    00325     event to be reflected to the Monitor.
    00326
    00327     It is assumed that interrupts are enabled upon entry, and Irql is
    00328     at APC level.
    00329
    00330 Arguments:
    00331
    00332     PortNumber -- Supplies the port number the IO was done to
    00333     Size -- Supplies the size of the IO operation.
    00334     Read -- Indicates whether the IO operation was a read or a write.
    00335     Count -- indicates the number of IO operations of Size size
    00336     Address -- Indicates address for string io
    00337     InstructionSize -- Supplies the size of the IO instruction in bytes.
    00338
    00339
    00340 Return Value:
    00341
    00342     True if the io instruction will be reflected to User mode.
    00343 --*/
    00344 {
    00345     PVDM_TIB VdmTib;
    00346     EXCEPTION_RECORD ExceptionRecord;
    00347     BOOLEAN Success = FALSE;
    00348     VDM_IO_HANDLER VdmIoHandler;
    00349     ULONG Context;
    00350
    00351     Success = PsIA32GetVdmIoHandler(
    00352         PsGetCurrentProcess(),
    00353         PortNumber & ~0x3,
    00354         &VdmIoHandler,
    00355         &Context
    00356         );
    00357
    00358
    00359     if (Success) {
    00360         Success = VdmDispatchStringIoToHandler(
    00361             &VdmIoHandler,
    00362             Context,
    00363             PortNumber,
    00364             Size,
    00365             Count,
    00366             Read,
    00367             Address
    00368             );
    00369     }
    00370
    00371     if (Success) {
    00372         PUSHORT pIndexRegister;
    00373         USHORT Index;
    00374
    00375         // WARNING no 32 bit address support
    00376
    00377         pIndexRegister = Read ? (PUSHORT)&TrapFrame->Edi
    00378                               : (PUSHORT)&TrapFrame->Esi;
    00379
    00380         if (TrapFrame->EFlags & EFLAGS_DF_MASK) {
    00381             Index = *pIndexRegister - (USHORT)(Count * Size);
    00382             }
    00383         else {
    00384             Index = *pIndexRegister + (USHORT)(Count * Size);
    00385             }
    00386
    00387         *pIndexRegister = Index;
    00388
    00389         if (Rep) {
    00390             (USHORT)TrapFrame->Ecx = 0;
    00391             }
    00392
    00393         TrapFrame->Eip += (ULONG) InstructionSize;
    00394         return TRUE;
    00395     }
    00396
    00397     try {
    00398         VdmTib = NtCurrentTeb()->Vdm;
    00399         VdmTib->EventInfo.InstructionSize = (ULONG) InstructionSize;
    00400         VdmTib->EventInfo.Event = VdmStringIO;
    00401         VdmTib->EventInfo.StringIoInfo.PortNumber = (USHORT)PortNumber;
    00402         VdmTib->EventInfo.StringIoInfo.Size = (USHORT)Size;
    00403         VdmTib->EventInfo.StringIoInfo.Rep = Rep;
    00404         VdmTib->EventInfo.StringIoInfo.Read = Read;
    00405         VdmTib->EventInfo.StringIoInfo.Count = Count;
    00406         VdmTib->EventInfo.StringIoInfo.Address = Address;
    00407     } except(EXCEPTION_EXECUTE_HANDLER) {
    00408         ExceptionRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
    00409         ExceptionRecord.ExceptionFlags = 0;
    00410         ExceptionRecord.NumberParameters = 0;
    00411         ExRaiseException(&ExceptionRecord);
    00412         return FALSE;
    00413     }
    00414
    00415
    00416     VdmEndExecution(TrapFrame, VdmTib);
    00417
    00418     return TRUE;
    00419 }
    00420
    00421
    00422 BOOLEAN
    00423 VdmDispatchIoToHandler(
    00424     IN PVDM_IO_HANDLER VdmIoHandler,
    00425     IN ULONG Context,
    00426     IN ULONG PortNumber,
    00427     IN ULONG Size,
    00428     IN BOOLEAN Read,
    00429     IN OUT PULONG Data
    00430     )
    00431 /*++
    00432
    00433 Routine Description:
    00434
    00435      This routine calls the handler for the IO.  If there is not a handler
    00436      of the proper size, it will call this function for 2 io's to the next
    00437      smaller size.  If the size was a byte, and there was no handler, FALSE
    00438      is returned.
    00439
    00440 Arguments:
    00441
    00442     VdmIoHandler -- Supplies a pointer to the handler table
    00443     Context -- Supplies 32 bits of data set when the port was trapped
    00444     PortNumber -- Supplies the port number the IO was done to
    00445     Size -- Supplies the size of the IO operation.
    00446     Read -- Indicates whether the IO operation was a read or a write.
    00447     Result -- Supplies a pointer to the location to put the result
    00448
    00449 Return Value:
    00450
    00451     True if one or more handlers were called to take care of the IO.
    00452     False if no handler was called to take care of the IO.
    00453
    00454 --*/
    00455 {
    00456     NTSTATUS Status;
    00457     BOOLEAN Success1, Success2;
    00458     USHORT FnIndex;
    00459     UCHAR AccessType;
    00460
    00461     // Insure that Io is aligned
    00462     ASSERT((!(PortNumber % Size)));
    00463
    00464     if (Read) {
    00465         FnIndex = 0;
    00466         AccessType = EMULATOR_READ_ACCESS;
    00467     } else {
    00468         FnIndex = 1;
    00469         AccessType = EMULATOR_WRITE_ACCESS;
    00470     }
    00471
    00472     switch (Size) {
    00473     case 1:
    00474         if (VdmIoHandler->IoFunctions[FnIndex].UcharIo[PortNumber % 4]) {
    00475             Status = (*(VdmIoHandler->IoFunctions[FnIndex].UcharIo[PortNumber % 4]))(
    00476                 Context,
    00477                 PortNumber,
    00478                 AccessType,
    00479                 (PUCHAR)Data
    00480                 );
    00481             if (NT_SUCCESS(Status)) {
    00482                 return TRUE;
    00483             }
    00484         }
    00485         // No handler for this port
    00486         return FALSE;
    00487
    00488     case 2:
    00489         if (VdmIoHandler->IoFunctions[FnIndex].UshortIo[PortNumber % 2]) {
    00490             Status = (*(VdmIoHandler->IoFunctions[FnIndex].UshortIo[PortNumber % 2]))(
    00491                 Context,
    00492                 PortNumber,
    00493                 AccessType,
    00494                 (PUSHORT)Data
    00495                 );
    00496             if (NT_SUCCESS(Status)) {
    00497                 return TRUE;
    00498             }
    00499         } else {
    00500             // Dispatch to the two uchar handlers for this ushort port
    00501             Success1 = VdmDispatchIoToHandler(
    00502                 VdmIoHandler,
    00503                 Context,
    00504                 PortNumber,
    00505                 Size /2,
    00506                 Read,
    00507                 Data
    00508                 );
    00509
    00510             Success2 = VdmDispatchIoToHandler(
    00511                 VdmIoHandler,
    00512                 Context,
    00513                 PortNumber + 1,
    00514                 Size / 2,
    00515                 Read,
    00516                 (PULONG)((PUCHAR)Data + 1)
    00517                 );
    00518
    00519             return (Success1 || Success2);
    00520
    00521         }
    00522         return FALSE;
    00523
    00524     case 4:
    00525         if (VdmIoHandler->IoFunctions[FnIndex].UlongIo) {
    00526             Status = (*(VdmIoHandler->IoFunctions[FnIndex].UlongIo))(
    00527                 Context,
    00528                 PortNumber,
    00529                 AccessType,
    00530                 Data
    00531                 );
    00532             if (NT_SUCCESS(Status)) {
    00533                 return TRUE;
    00534             }
    00535         } else {
    00536             // Dispatch to the two ushort handlers for this port
    00537             Success1 = VdmDispatchIoToHandler(
    00538                 VdmIoHandler,
    00539                 Context,
    00540                 PortNumber,
    00541                 Size /2,
    00542                 Read,
    00543                 Data);
    00544             Success2 = VdmDispatchIoToHandler(
    00545                 VdmIoHandler,
    00546                 Context,
    00547                 PortNumber + 2,
    00548                 Size / 2,
    00549                 Read,
    00550                 (PULONG)((PUSHORT)Data + 1)
    00551                 );
    00552
    00553             return (Success1 || Success2);
    00554         }
    00555         return FALSE;
    00556     }
    00557 }
    00558
    00559 BOOLEAN
    00560 VdmDispatchUnalignedIoToHandler(
    00561     IN PVDM_IO_HANDLER VdmIoHandler,
    00562     IN ULONG Context,
    00563     IN ULONG PortNumber,
    00564     IN ULONG Size,
    00565     IN BOOLEAN Read,
    00566     IN OUT PULONG Data
    00567     )
    00568 /*++
    00569
    00570 Routine Description:
    00571
    00572      This routine converts the unaligned IO to the necessary number of aligned
    00573      IOs to smaller ports.
    00574
    00575 Arguments:
    00576
    00577     VdmIoHandler -- Supplies a pointer to the handler table
    00578     Context -- Supplies 32 bits of data set when the port was trapped
    00579     PortNumber -- Supplies the port number the IO was done to
    00580     Size -- Supplies the size of the IO operation.
    00581     Read -- Indicates whether the IO operation was a read or a write.
    00582     Result -- Supplies a pointer to the location to put the result
    00583
    00584 Return Value:
    00585
    00586     True if one or more handlers were called to take care of the IO.
    00587     False if no handler was called to take care of the IO.
    00588
    00589 --*/
    00590 {
    00591     ULONG Offset;
    00592     BOOLEAN Success;
    00593
    00594     ASSERT((Size > 1));
    00595     ASSERT((PortNumber % Size));
    00596
    00597     Offset = 0;
    00598
    00599     //
    00600     //  The possible unaligned io situations are as follows.
    00601     //
    00602     //  1.  Uchar aligned Ulong io
    00603     //          We have to dispatch a uchar io, a ushort io, and a uchar io
    00604     //
    00605     //  2.  Ushort aligned Ulong Io
    00606     //          We have to dispatch a ushort io, and a ushort io
    00607     //
    00608     //  3.  Uchar aligned Ushort Io
    00609     //          We have to dispatch a uchar io and a uchar io
    00610     //
    00611
    00612     // if the port is uchar aligned
    00613     if ((PortNumber % Size) & 1) {
    00614         Success = VdmDispatchIoToHandler(
    00615             VdmIoHandler,
    00616             Context,
    00617             PortNumber,
    00618             1,
    00619             Read,
    00620             Data
    00621             );
    00622         Offset += 1;
    00623     // else it is ushort aligned (and therefore must be a ulong port)
    00624     } else {
    00625         Success = VdmDispatchIoToHandler(
    00626             VdmIoHandler,
    00627             Context,
    00628             PortNumber,
    00629             2,
    00630             Read,
    00631             Data
    00632             );
    00633         Offset += 2;
    00634     }
    00635
    00636     // if it is a ulong port, we know we have a ushort IO to dispatch
    00637     if (Size == 4) {
    00638         Success |= VdmDispatchIoToHandler(
    00639             VdmIoHandler,
    00640             Context,
    00641             PortNumber + Offset,
    00642             2,
    00643             Read,
    00644             (PULONG)((PUCHAR)Data + Offset)
    00645             );
    00646         Offset += 2;
    00647     }
    00648
    00649     // If we haven't dispatched the entire port, dispatch the final uchar
    00650     if (Offset != 4) {
    00651         Success |= VdmDispatchIoToHandler(
    00652             VdmIoHandler,
    00653             Context,
    00654             PortNumber + Offset,
    00655             1,
    00656             Read,
    00657             (PULONG)((PUCHAR)Data + Offset)
    00658             );
    00659     }
    00660
    00661     return Success;
    00662 }
    00663
    00664
    00665 BOOLEAN
    00666 VdmDispatchStringIoToHandler(
    00667     IN PVDM_IO_HANDLER VdmIoHandler,
    00668     IN ULONG Context,
    00669     IN ULONG PortNumber,
    00670     IN ULONG Size,
    00671     IN ULONG Count,
    00672     IN BOOLEAN Read,
    00673     IN ULONG Data
    00674     )
    00675 /*++
    00676
    00677 Routine Description:
    00678
    00679      This routine calls the handler for the IO.  If there is not a handler
    00680      of the proper size, or the io is not aligned, it will simulate the io
    00681      to the normal io handlers.
    00682
    00683 Arguments:
    00684
    00685     VdmIoHandler -- Supplies a pointer to the handler table
    00686     Context -- Supplies 32 bits of data set when the port was trapped
    00687     PortNumber -- Supplies the port number the IO was done to
    00688     Size -- Supplies the size of the IO operation.
    00689     Count -- Supplies the number of IO operations.
    00690     Read -- Indicates whether the IO operation was a read or a write.
    00691     Data -- Supplies a segmented address at which to put the result.
    00692
    00693 Return Value:
    00694
    00695     True if one or more handlers were called to take care of the IO.
    00696     False if no handler was called to take care of the IO.
    00697
    00698 --*/
    00699 {
    00700     BOOLEAN Success = FALSE;
    00701     USHORT FnIndex;
    00702     NTSTATUS Status;
    00703
    00704     if (Read) {
    00705         FnIndex = 0;
    00706     } else {
    00707         FnIndex = 1;
    00708     }
    00709
    00710     Status = KeWaitForSingleObject(
    00711         &VdmStringIoMutex,
    00712         Executive,
    00713         KernelMode,
    00714         FALSE,
    00715         NULL
    00716         );
    00717
    00718     if (!NT_SUCCESS(Status)) {
    00719         return FALSE;
    00720     }
    00721
    00722     switch (Size) {
    00723     case 1:
    00724         Success = VdmCallStringIoHandler(
    00725             VdmIoHandler,
    00726             (PVOID)VdmIoHandler->IoFunctions[FnIndex].UcharStringIo[PortNumber % 4],
    00727             Context,
    00728             PortNumber,
    00729             Size,
    00730             Count,
    00731             Read,
    00732             Data
    00733             );
    00734     case 2:
    00735         Success = VdmCallStringIoHandler(
    00736             VdmIoHandler,
    00737             (PVOID)VdmIoHandler->IoFunctions[FnIndex].UshortStringIo[PortNumber % 2],
    00738             Context,
    00739             PortNumber,
    00740             Size,
    00741             Count,
    00742             Read,
    00743             Data
    00744             );
    00745     case 4:
    00746         Success = VdmCallStringIoHandler(
    00747             VdmIoHandler,
    00748             (PVOID)VdmIoHandler->IoFunctions[FnIndex].UlongStringIo,
    00749             Context,
    00750             PortNumber,
    00751             Size,
    00752             Count,
    00753             Read,
    00754             Data
    00755             );
    00756     }
    00757     KeReleaseMutex(&VdmStringIoMutex, FALSE);
    00758     return Success;
    00759 }
    00760
    00761 #define STRINGIO_BUFFER_SIZE 1024
    00762 UCHAR VdmStringIoBuffer[STRINGIO_BUFFER_SIZE];
    00763
    00764 BOOLEAN
    00765 VdmCallStringIoHandler(
    00766     IN PVDM_IO_HANDLER VdmIoHandler,
    00767     IN PVOID StringIoRoutine,
    00768     IN ULONG Context,
    00769     IN ULONG PortNumber,
    00770     IN ULONG Size,
    00771     IN ULONG Count,
    00772     IN BOOLEAN Read,
    00773     IN ULONG Data
    00774     )
    00775 /*++
    00776
    00777 Routine Description:
    00778
    00779     This routine actually performs the call to string io routine.  It takes
    00780     care of buffering the user data in kernel space so that the device driver
    00781     does not have to.  If there is not a string io function, or the io is
    00782     misaligned, it will be simulated as a series of normal io operations
    00783
    00784 Arguments:
    00785
    00786     StringIoRoutine -- Supplies a pointer to the string Io routine
    00787     Context -- Supplies 32 bits of data set when the port was trapped
    00788     PortNumber -- Supplies the number of the port to perform Io to
    00789     Size -- Supplies the size of the io operations
    00790     Count -- Supplies the number of Io operations in the string.
    00791     Read -- Indicates a read operation
    00792     Data -- Supplies a pointer to the user buffer to perform the io on.
    00793
    00794 Returns
    00795
    00796     TRUE if a handler was called
    00797     FALSE if not.
    00798
    00799 --*/
    00800 {
    00801     ULONG TotalBytes,BytesDone,BytesToDo,LoopCount,NumberIo;
    00802     PUCHAR CurrentDataPtr;
    00803     UCHAR AccessType;
    00804     EXCEPTION_RECORD ExceptionRecord;
    00805     NTSTATUS Status;
    00806     BOOLEAN Success;
    00807
    00808     Success = VdmConvertToLinearAddress(
    00809         Data,
    00810         &CurrentDataPtr
    00811         );
    00812
    00813     if (!Success) {
    00814         ExceptionRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
    00815         ExceptionRecord.ExceptionFlags = 0;
    00816         ExceptionRecord.NumberParameters = 0;
    00817         ExRaiseException(&ExceptionRecord);
    00818         // Cause kernel exit, rather than Io reflection
    00819         return TRUE;
    00820     }
    00821
    00822
    00823     TotalBytes = Count * Size;
    00824     BytesDone = 0;
    00825
    00826     if (PortNumber % Size) {
    00827         StringIoRoutine = NULL;
    00828     }
    00829
    00830     if (Read) {
    00831         AccessType = EMULATOR_READ_ACCESS;
    00832     } else {
    00833         AccessType = EMULATOR_WRITE_ACCESS;
    00834     }
    00835
    00836
    00837     // Set up try out here to avoid overhead in loop
    00838     try {
    00839         while (BytesDone < TotalBytes) {
    00840             if ((BytesDone + STRINGIO_BUFFER_SIZE) > TotalBytes) {
    00841                 BytesToDo = TotalBytes - BytesDone;
    00842             } else {
    00843                 BytesToDo = STRINGIO_BUFFER_SIZE;
    00844             }
    00845
    00846             ASSERT((!(BytesToDo % Size)));
    00847
    00848             if (!Read) {
    00849                 RtlMoveMemory(VdmStringIoBuffer, CurrentDataPtr, BytesToDo);
    00850             }
    00851
    00852             NumberIo = BytesToDo / Size;
    00853
    00854             if (StringIoRoutine) {
    00855                 // in order to avoid having 3 separate calls, one for each size
    00856                 // we simply cast the parameters appropriately for the
    00857                 // byte routine.
    00858
    00859                 Status = (*((PDRIVER_IO_PORT_UCHAR_STRING)StringIoRoutine))(
    00860                     Context,
    00861                     PortNumber,
    00862                     AccessType,
    00863                     VdmStringIoBuffer,
    00864                     NumberIo
    00865                     );
    00866
    00867                 if (NT_SUCCESS(Status)) {
    00868                     Success |= TRUE;
    00869                 }
    00870             } else {
    00871                 if (PortNumber % Size) {
    00872                     for (LoopCount = 0; LoopCount < NumberIo; LoopCount++ ) {
    00873                         Success |= VdmDispatchUnalignedIoToHandler(
    00874                             VdmIoHandler,
    00875                             Context,
    00876                             PortNumber,
    00877                             Size,
    00878                             Read,
    00879                             (PULONG)(VdmStringIoBuffer + LoopCount * Size)
    00880                             );
    00881                     }
    00882                 } else {
    00883                     for (LoopCount = 0; LoopCount < NumberIo; LoopCount++ ) {
    00884                         Success |= VdmDispatchIoToHandler(
    00885                             VdmIoHandler,
    00886                             Context,
    00887                             PortNumber,
    00888                             Size,
    00889                             Read,
    00890                             (PULONG)(VdmStringIoBuffer + LoopCount * Size)
    00891                             );
    00892                     }
    00893
    00894                 }
    00895             }
    00896
    00897             if (Read) {
    00898                 RtlMoveMemory(CurrentDataPtr, VdmStringIoBuffer, BytesToDo);
    00899             }
    00900
    00901             BytesDone += BytesToDo;
    00902             CurrentDataPtr += BytesToDo;
    00903         }
    00904     } except(EXCEPTION_EXECUTE_HANDLER) {
    00905         ExceptionRecord.ExceptionCode = GetExceptionCode();
    00906         ExceptionRecord.ExceptionFlags = 0;
    00907         ExceptionRecord.NumberParameters = 0;
    00908         ExRaiseException(&ExceptionRecord);
    00909         // Cause kernel exit, rather than Io reflection
    00910         Success = TRUE;
    00911     }
    00912     return Success;
    00913
    00914 }
    00915
    00916
    00917 BOOLEAN
    00918 VdmConvertToLinearAddress(
    00919     IN ULONG SegmentedAddress,
    00920     OUT PVOID *LinearAddress
    00921     )
    00922 /*++
    00923
    00924 Routine Description:
    00925
    00926     This routine converts the specified segmented address into a linear
    00927     address, based on processor mode in user mode.
    00928
    00929 Arguments:
    00930
    00931     SegmentedAddress -- Supplies the segmented address to convert.
    00932     LinearAddress -- Supplies a pointer to the destination for the
    00933         coresponding linear address
    00934
    00935 Return Value:
    00936
    00937     True if the address was converted.
    00938     False otherwise
    00939
    00940 Note:
    00941
    00942     A linear address of 0 is a valid return
    00943 --*/
    00944 {
    00945     PKTHREAD Thread;
    00946     PKIA32_FRAME TrapFrame;
    00947     BOOLEAN Success;
    00948     KXDESCRIPTOR XDescriptor;
    00949     ULONG Base, Limit, Flags;
    00950
    00951     Thread = KeGetCurrentThread();
    00952     TrapFrame = (PKIA32_FRAME) VdmGetTrapFrame(Thread);
    00953
    00954     if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
    00955         *LinearAddress = (PVOID)(((SegmentedAddress & 0xFFFF0000) >> 12) +
    00956             (SegmentedAddress & 0xFFFF));
    00957         Success = TRUE;
    00958     } else {
    00959         Success = KeIA32UnscrambleLdtEntry(
    00960             (USHORT)((SegmentedAddress & 0xFFFF0000) >> 12),
    00961             &XDescriptor
    00962             );
    00963         if (Success) {
    00964             *LinearAddress = (PVOID)(XDescriptor.Words.Bits.Base +
    00965                              (SegmentedAddress & 0xFFFF));
    00966         }
    00967     }
    00968     return Success;
    00969 }
    00970
    00971 VOID
    00972 KeIA32VdmInitialize(
    00973     VOID
    00974     )
    00975 /*++
    00976
    00977 Routine Description:
    00978
    00979     This routine initializes the vdm stuff
    00980
    00981 Arguments:
    00982
    00983     None
    00984
    00985 Return Value:
    00986
    00987     None
    00988 --*/
    00989 {
    00990     NTSTATUS Status;
    00991     OBJECT_ATTRIBUTES ObjectAttributes;
    00992     HANDLE RegistryHandle = NULL;
    00993     UNICODE_STRING WorkString;
    00994     UCHAR KeyInformation[sizeof(KEY_VALUE_BASIC_INFORMATION) + 30];
    00995     ULONG ResultLength;
    00996
    00997     KeInitializeMutex( &VdmStringIoMutex, MUTEX_LEVEL_VDM_IO );
    00998
    00999     //
    01000     // Set up and open KeyPath to wow key
    01001     //
    01002
    01003     RtlInitUnicodeString(
    01004         &WorkString,
    01005         L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Wow"
    01006         );
    01007
    01008     InitializeObjectAttributes(
    01009         &ObjectAttributes,
    01010         &WorkString,
    01011         OBJ_CASE_INSENSITIVE,
    01012         (HANDLE)NULL,
    01013         NULL
    01014         );
    01015
    01016     Status = ZwOpenKey(
    01017         &RegistryHandle,
    01018         KEY_READ,
    01019         &ObjectAttributes
    01020         );
    01021
    01022     //
    01023     // If there is no Wow key, don't allow Vdms to run
    01024     //
    01025     if (!NT_SUCCESS(Status)) {
    01026         return;
    01027     }
    01028
    01029     //
    01030     // Set up for using virtual interrupt extensions if they are available
    01031     //
    01032
    01033 #ifdef USE_VME
    01034
    01035     //
    01036     // Get the Pentium Feature disable value.
    01037     // If this value is present, don't enable vme stuff.
    01038     //
    01039     RtlInitUnicodeString(
    01040         &WorkString,
    01041         L"DisableVme"
    01042         );
    01043
    01044     Status = ZwQueryValueKey(
    01045         RegistryHandle,
    01046         &WorkString,
    01047         KeyValueBasicInformation,
    01048         &KeyInformation,
    01049         sizeof(KEY_VALUE_BASIC_INFORMATION) + 30,
    01050         &ResultLength
    01051         );
    01052
    01053     if (!NT_SUCCESS(Status)) {
    01054
    01055         //
    01056         // If we have the extensions, set the appropriate bits
    01057         // in cr4
    01058         //
    01059                 //
    01060                 // The merced processor emulates the P6, but we don't
    01061                 // plan on implementing it... We might implement the PVI
    01062                 // stuff though...
    01063                 //
    01064         if (KeFeatureBits & KF_V86_VIS) {
    01065             KiIpiGenericCall(
    01066                 KiIA32VdmEnablePentiumExtentions,
    01067                 TRUE
    01068                 );
    01069             KeIA32VirtualIntExtensions = V86_VIRTUAL_INT_EXTENSIONS;
    01070         }
    01071     }
    01072
    01073     //
    01074     // If we have V86 mode int extensions, we don't want to run with
    01075     // IOPL in v86 mode
    01076     //
    01077     if (!KeIA32VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) {
    01078         //
    01079         // Read registry to determine if Vdms will run with IOPL in v86 mode
    01080         //
    01081
    01082         //
    01083         // Get the VdmIOPL value.
    01084         //
    01085         RtlInitUnicodeString(
    01086             &WorkString,
    01087             L"VdmIOPL"
    01088             );
    01089
    01090         Status = ZwQueryValueKey(
    01091             RegistryHandle,
    01092             &WorkString,
    01093             KeyValueBasicInformation,
    01094             &KeyInformation,
    01095             sizeof(KEY_VALUE_BASIC_INFORMATION) + 30,
    01096             &ResultLength
    01097             );
    01098
    01099         //
    01100         // If the value exists, let Vdms run with IOPL in V86 mode
    01101         //
    01102         if (NT_SUCCESS(Status)) {
    01103             //
    01104             // KeEflagsAndMaskV86 and KeEflagsOrMaskV86 are used
    01105             // in SANITIZE_FLAGS, and the Vdm code to make sure the
    01106             // values in EFlags for v86 mode trap frames are acceptable
    01107             //
    01108             KeIA32EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK;
    01109             KeIA32EFlagsOrMaskV86 = EFLAGS_IOPL_MASK;
    01110
    01111             //
    01112             // KeVdmIoplAllowed is used by the Vdm code to determine if
    01113             // the virtual interrupt flag is in EFlags, or 40:xx
    01114             //
    01115             KeIA32VdmIoplAllowed = TRUE;
    01116
    01117         }
    01118     }
    01119 #endif
    01120     ZwClose(RegistryHandle);
    01121 }
    01122
    01123
    01124 BOOLEAN
    01125 KeIA32VdmInsertQueueApc (
    01126     IN PKAPC             Apc,
    01127     IN PKTHREAD          Thread,
    01128     IN KPROCESSOR_MODE   ApcMode,
    01129     IN PKKERNEL_ROUTINE  KernelRoutine,
    01130     IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,
    01131     IN PKNORMAL_ROUTINE  NormalRoutine  OPTIONAL,
    01132     IN PVOID             NormalContext   OPTIONAL,
    01133     IN PVOID             SystemArgument1 OPTIONAL,
    01134     IN PVOID             SystemArgument2 OPTIONAL,
    01135     IN KPRIORITY         Increment
    01136     )
    01137
    01138 /*++
    01139
    01140 Routine Description:
    01141
    01142     This function initializes, and queues a vdm type of APC to the
    01143     specified thread.
    01144
    01145
    01146     A Vdm type of APC:
    01147        - OriginalApcEnvironment
    01148        - will only be queued to one thread at a time
    01149        - if UserMode Fires on the next system exit. A UserMode apc should
    01150          not be queued if the current vdm context is not application mode.
    01151
    01152 Arguments:
    01153
    01154     Apc - Supplies a pointer to a control object of type APC.
    01155
    01156     Thread - Supplies a pointer to a dispatcher object of type thread.
    01157
    01158     ApcMode - Supplies the processor mode user\kernel of the Apc
    01159
    01160     KernelRoutine - Supplies a pointer to a function that is to be
    01161         executed at IRQL APC_LEVEL in kernel mode.
    01162
    01163     RundownRoutine - Supplies an optional pointer to a function that is to be
    01164         called if the APC is in a thread's APC queue when the thread terminates.
    01165
    01166     NormalRoutine - Supplies an optional pointer to a function that is
    01167         to be executed at IRQL 0 in the specified processor mode. If this
    01168         parameter is not specified, then the ProcessorMode and NormalContext
    01169         parameters are ignored.
    01170
    01171     NormalContext - Supplies a pointer to an arbitrary data structure which is
    01172         to be passed to the function specified by the NormalRoutine parameter.
    01173
    01174     SystemArgument1, SystemArgument2 - Supply a set of two arguments that
    01175         contain untyped data provided by the executive.
    01176
    01177     Increment - Supplies the priority increment that is to be applied if
    01178         queuing the APC causes a thread wait to be satisfied.
    01179
    01180
    01181 Return Value:
    01182
    01183     If APC queuing is disabled, then a value of FALSE is returned.
    01184     Otherwise a value of TRUE is returned.
    01185
    01186
    01187 --*/
    01188 {
    01189
    01190     PKAPC_STATE ApcState;
    01191     PKTHREAD ApcThread;
    01192     KIRQL   OldIrql;
    01193     BOOLEAN Inserted;
    01194
    01195     //
    01196     // Raise IRQL to dispatcher level and lock dispatcher database.
    01197     //
    01198
    01199     KiLockDispatcherDatabase(&OldIrql);
    01200
    01201     //
    01202     // If the apc object not initialized, then initialize it and acquire
    01203     // the target thread APC queue lock.
    01204     //
    01205
    01206     if (Apc->Type != ApcObject) {
    01207         Apc->Type = ApcObject;
    01208         Apc->Size = sizeof(KAPC);
    01209         Apc->ApcStateIndex  = OriginalApcEnvironment;
    01210     } else {
    01211
    01212         //
    01213         // Acquire the APC thread APC queue lock.
    01214         //
    01215         // If the APC is inserted in the corresponding APC queue, and the
    01216         // APC thread is not the same thread as the target thread, then
    01217         // the APC is removed from its current queue, the APC pending state
    01218         // is updated, the APC thread APC queue lock is released, and the
    01219         // target thread APC queue lock is acquired. Otherwise, the APC
    01220         // thread and the target thread are same thread and the APC is already
    01221         // queued to the correct thread.
    01222         //
    01223         // If the APC is not inserted in an APC queue, then release the
    01224         // APC thread APC queue lock and acquire the target thread APC queue
    01225         // lock.
    01226         //
    01227
    01228         ApcThread = Apc->Thread;
    01229         if (ApcThread) {
    01230             KiAcquireSpinLock(&ApcThread->ApcQueueLock);
    01231             if (Apc->Inserted) {
    01232                 if (ApcThread == Apc->Thread && Apc->Thread != Thread) {
    01233                     Apc->Inserted = FALSE;
    01234                     RemoveEntryList(&Apc->ApcListEntry);
    01235                     ApcState = Apc->Thread->ApcStatePointer[Apc->ApcStateIndex];
    01236                     if (IsListEmpty(&ApcState->ApcListHead[Apc->ApcMode]) != FALSE) {
    01237                         if (Apc->ApcMode == KernelMode) {
    01238                             ApcState->KernelApcPending = FALSE;
    01239
    01240                         } else {
    01241                             ApcState->UserApcPending = FALSE;
    01242                         }
    01243                     }
    01244
    01245                 } else {
    01246                     KiReleaseSpinLock(&ApcThread->ApcQueueLock);
    01247                     KiUnlockDispatcherDatabase(OldIrql);
    01248                     return TRUE;
    01249                 }
    01250             }
    01251
    01252             KiReleaseSpinLock(&ApcThread->ApcQueueLock);
    01253         }
    01254     }
    01255
    01256
    01257     KiAcquireSpinLock(&Thread->ApcQueueLock);
    01258
    01259     Apc->ApcMode = ApcMode;
    01260     Apc->Thread  = Thread;
    01261     Apc->KernelRoutine   = KernelRoutine;
    01262     Apc->RundownRoutine  = RundownRoutine;
    01263     Apc->NormalRoutine   = NormalRoutine;
    01264     Apc->SystemArgument1 = SystemArgument1;
    01265     Apc->SystemArgument2 = SystemArgument2;
    01266     Apc->NormalContext   = NormalContext;
    01267
    01268     //
    01269     // Unlock the target thread APC queue.
    01270     //
    01271
    01272     KiReleaseSpinLock(&Thread->ApcQueueLock);
    01273
    01274     //
    01275     // If APC queuing is enable, then attempt to queue the APC object.
    01276     //
    01277
    01278     if (Thread->ApcQueueable && KiInsertQueueApc(Apc, Increment)) {
    01279         Inserted = TRUE;
    01280
    01281         //
    01282         // If UserMode:
    01283         //    For vdm a UserMode Apc is only queued by a kernel mode
    01284         //    apc which is on the current thread for the target thread.
    01285         //    Force UserApcPending for User mode apcstate, so that
    01286         //    the apc will fire when this thread exits the kernel.
    01287         //
    01288
    01289         if (ApcMode == UserMode) {
    01290             KiBoostPriorityThread(Thread, Increment);
    01291             Thread->ApcState.UserApcPending = TRUE;
    01292         }
    01293
    01294     } else {
    01295         Inserted = FALSE;
    01296     }
    01297
    01298     //
    01299     // Unlock the dispatcher database, lower IRQL to its previous value, and
    01300     // return whether the APC object was inserted.
    01301     //
    01302
    01303     KiUnlockDispatcherDatabase(OldIrql);
    01304     return Inserted;
    01305 }
    01306
    01307
    01308 VOID
    01309 KeIA32VdmClearApcObject(
    01310     IN PKAPC Apc
    01311     )
    01312 /*++
    01313
    01314 Routine Description:
    01315
    01316     Clears a VDM APC object, synchronously with Ke386VdmInsertQueueApc, and
    01317     is expected to be called by one of the vdm kernel apc routine or the
    01318     rundown routine.
    01319
    01320
    01321 Arguments:
    01322
    01323     Apc - Supplies a pointer to a control object of type APC.
    01324
    01325
    01326 Return Value:
    01327
    01328     void
    01329
    01330 --*/
    01331 {
    01332
    01333     KIRQL   OldIrql;
    01334
    01335     //
    01336     // Take Dispatcher database lock, to sync with Ke386VDMInsertQueueApc
    01337     //
    01338
    01339     KiLockDispatcherDatabase(&OldIrql);
    01340     Apc->Thread  = NULL;
    01341     KiUnlockDispatcherDatabase(OldIrql);
    01342
    01343 }
    01344
    01345 //
    01346 //  END of ACTIVE CODE
    01347 //
    01348
    01349 #if VDM_IO_TEST
    01350 NTSTATUS
    01351 TestIoByteRoutine(
    01352     IN ULONG Port,
    01353     IN UCHAR AccessMode,
    01354     IN OUT PUCHAR Data
    01355     )
    01356 {
    01357     if (AccessMode & EMULATOR_READ_ACCESS) {
    01358         *Data = Port - 400;
    01359     }
    01360
    01361     return STATUS_SUCCESS;
    01362 }
    01363
    01364 NTSTATUS
    01365 TestIoWordReadRoutine(
    01366     IN ULONG Port,
    01367     IN UCHAR AccessMode,
    01368     IN OUT PUSHORT Data
    01369     )
    01370 {
    01371     if (AccessMode & EMULATOR_READ_ACCESS) {
    01372         *Data = Port - 200;
    01373     }
    01374
    01375     return STATUS_SUCCESS;
    01376 }
    01377
    01378 NTSTATUS
    01379 TestIoWordWriteRoutine(
    01380     IN ULONG Port,
    01381     IN UCHAR AccessMode,
    01382     IN OUT PUSHORT Data
    01383     )
    01384 {
    01385     DbgPrint("Word Write routine port # %lx, %x\n",Port,*Data);
    01386
    01387     return STATUS_SUCCESS;
    01388 }
    01389
    01390 NTSTATUS
    01391 TestIoDwordRoutine(
    01392     IN ULONG Port,
    01393     IN USHORT AccessMode,
    01394     IN OUT PULONG Data
    01395     )
    01396 {
    01397     if (AccessMode & EMULATOR_READ_ACCESS) {
    01398         *Data = Port;
    01399     }
    01400
    01401     return STATUS_SUCCESS;
    01402 }
    01403
    01404 NTSTATUS
    01405 TestIoStringRoutine(
    01406     IN ULONG Port,
    01407     IN USHORT AccessMode,
    01408     IN OUT PSHORT Data,
    01409     IN ULONG Count
    01410     )
    01411 {
    01412     ULONG i;
    01413
    01414     if (AccessMode & EMULATOR_READ_ACCESS) {
    01415         for (i = 0;i < Count ;i++ ) {
    01416             Data[i] = i;
    01417         }
    01418     } else {
    01419         DbgPrint("String Port Called for write port #%lx,",Port);
    01420         for (i = 0;i < Count ;i++ ) {
    01421             DbgPrint("%x\n",Data[i]);
    01422         }
    01423     }
    01424
    01425     return STATUS_SUCCESS;
    01426 }
    01427
    01428 PROCESS_IO_PORT_HANDLER_INFORMATION IoPortHandler;
    01429 EMULATOR_ACCESS_ENTRY Entry[4];
    01430 BOOLEAN Connect = TRUE, Disconnect = FALSE;
    01431
    01432 VOID
    01433 TestIoHandlerStuff(
    01434     VOID
    01435     )
    01436 {
    01437     NTSTATUS Status;
    01438
    01439     IoPortHandler.Install = TRUE;
    01440     IoPortHandler.NumEntries = 5L;
    01441     IoPortHandler.EmulatorAccessEntries = Entry;
    01442
    01443     Entry[0].BasePort = 0x400;
    01444     Entry[0].NumConsecutivePorts = 0x30;
    01445     Entry[0].AccessType = Uchar;
    01446     Entry[0].AccessMode = EMULATOR_READ_ACCESS | EMULATOR_WRITE_ACCESS;
    01447     Entry[0].StringSupport = FALSE;
    01448     Entry[0].Routine = TestIoByteRoutine;
    01449
    01450     Entry[1].BasePort = 0x400;
    01451     Entry[1].NumConsecutivePorts = 0x18;
    01452     Entry[1].AccessType = Ushort;
    01453     Entry[1].AccessMode = EMULATOR_READ_ACCESS | EMULATOR_WRITE_ACCESS;
    01454     Entry[1].StringSupport = FALSE;
    01455     Entry[1].Routine = TestIoWordReadRoutine;
    01456
    01457     Entry[2].BasePort = 0x400;
    01458     Entry[2].NumConsecutivePorts = 0xc;
    01459     Entry[2].AccessType = Ulong;
    01460     Entry[2].AccessMode = EMULATOR_READ_ACCESS | EMULATOR_WRITE_ACCESS;
    01461     Entry[2].StringSupport = FALSE;
    01462     Entry[2].Routine = TestIoDwordRoutine;
    01463
    01464     Entry[3].BasePort = 0x400;
    01465     Entry[3].NumConsecutivePorts = 0x18;
    01466     Entry[3].AccessType = Ushort;
    01467     Entry[3].AccessMode = EMULATOR_READ_ACCESS | EMULATOR_WRITE_ACCESS;
    01468     Entry[3].StringSupport = TRUE;
    01469     Entry[3].Routine = TestIoStringRoutine;
    01470
    01471      if (Connect) {
    01472         Status = ZwSetInformationProcess(
    01473             NtCurrentProcess(),
    01474             ProcessIoPortHandlers,
    01475             &IoPortHandler,
    01476             sizeof(PROCESS_IO_PORT_HANDLER_INFORMATION)
    01477             ) ;
    01478         if (!NT_SUCCESS(Status)) {
    01479             DbgBreakPoint();
    01480         }
    01481         Connect = FALSE;
    01482     }
    01483
    01484     IoPortHandler.Install = FALSE;
    01485     if (Disconnect) {
    01486         Status = ZwSetInformationProcess(
    01487             NtCurrentProcess(),
    01488             ProcessIoPortHandlers,
    01489             &IoPortHandler,
    01490             sizeof(PROCESS_IO_PORT_HANDLER_INFORMATION)
    01491             );
    01492         if (!NT_SUCCESS(Status)) {
    01493             DbgBreakPoint();
    01494         }
    01495         Disconnect = FALSE;
    01496     }
    01497 }
    01498 #endif
    01499
    01500
    01501 #endif