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

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