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

Generated on Sat May 15 19:42:21 2004 for test by doxygen 1.3.7