00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
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
00221
00222
00223
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
00277
00278 }
00279
00280
00281
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
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
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
00354
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
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
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
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
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 {
00568
NTSTATUS Status;
00569 BOOLEAN Success1, Success2;
00570
USHORT FnIndex;
00571 UCHAR AccessType;
00572
00573
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
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
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
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
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
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
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
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
00736 }
else {
00737 Success =
VdmDispatchIoToHandler(
00738 VdmIoHandler,
00739 Context,
00740 PortNumber,
00741 2,
00742 Read,
00743 Data
00744 );
00745
Offset += 2;
00746 }
00747
00748
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
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
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
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
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
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
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
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
00973
00974
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
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
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
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
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
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
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
01140
01141
if (!
NT_SUCCESS(
Status)) {
01142
return;
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
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
01171
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
01184
01185
01186
if (!
KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) {
01187
01188
01189
01190
01191
01192
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
01210
01211
if (
NT_SUCCESS(
Status)) {
01212
01213
01214
01215
01216
01217
KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK;
01218
KeI386EFlagsOrMaskV86 = EFLAGS_IOPL_MASK;
01219
01220
01221
01222
01223
01224
KeI386VdmIoplAllowed =
TRUE;
01225
01226 }
01227 }
01228
01229 ZwClose(RegistryHandle);
01230
01231
01232
01233
01234
01235
01236
01237
01238
if (
KeI386MachineType & MACHINE_TYPE_PC_9800_COMPATIBLE) {
01239
01240
01241
01242
01243
01244
VdmFixedStateLinear = FIXED_NTVDMSTATE_LINEAR_PC_98;
01245 }
else {
01246
01247
01248
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
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316 {
01317
01318
PKAPC_STATE ApcState;
01319
PKTHREAD ApcThread;
01320 KIRQL OldIrql;
01321 BOOLEAN Inserted;
01322
01323
01324
01325
01326
01327
KiLockDispatcherDatabase(&OldIrql);
01328
01329
01330
01331
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
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
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
01398
01399
01400 KiReleaseSpinLock(&Thread->ApcQueueLock);
01401
01402
01403
01404
01405
01406
if (Thread->ApcQueueable &&
KiInsertQueueApc(Apc,
Increment)) {
01407 Inserted =
TRUE;
01408
01409
01410
01411
01412
01413
01414
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
01428
01429
01430
01431
KiUnlockDispatcherDatabase(OldIrql);
01432
return Inserted;
01433 }
01434
01435
01436
VOID
01437 Ke386VdmClearApcObject(
01438 IN
PKAPC Apc
01439 )
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459 {
01460
01461 KIRQL OldIrql;
01462
01463
01464
01465
01466
01467
KiLockDispatcherDatabase(&OldIrql);
01468 Apc->Thread =
NULL;
01469
KiUnlockDispatcherDatabase(OldIrql);
01470
01471 }
01472
01473
01474
01475
01476
01477
01478
01479
01480
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 = 5
L;
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