00001
#include "ki.h"
00002
#include "ki386.h"
00003
00004 PVOID
00005
Ki386AllocateContiguousMemory(
00006 IN OUT
PIDENTITY_MAP IdentityMap,
00007 IN ULONG Pages,
00008 IN BOOLEAN Low4Meg
00009 );
00010
00011 BOOLEAN
00012
Ki386IdentityMapMakeValid(
00013 IN OUT
PIDENTITY_MAP IdentityMap,
00014 IN PHARDWARE_PTE PageTableEntry,
00015 OUT PVOID *Page OPTIONAL
00016 );
00017
00018 BOOLEAN
00019
Ki386MapAddress(
00020 IN OUT
PIDENTITY_MAP IdentityMap,
00021 IN ULONG Va,
00022 IN PHYSICAL_ADDRESS PhysicalAddress
00023 );
00024
00025 PVOID
00026
Ki386ConvertPte(
00027 IN OUT PHARDWARE_PTE Pte
00028 );
00029
00030 PHYSICAL_ADDRESS
00031
Ki386BuildIdentityBuffer(
00032 IN OUT
PIDENTITY_MAP IdentityMap,
00033 IN PVOID StartVa,
00034 IN ULONG Length,
00035 OUT PULONG PagesToMap
00036 );
00037
00038
#ifdef ALLOC_PRAGMA
00039
00040
#pragma alloc_text(INIT,Ki386AllocateContiguousMemory)
00041
#pragma alloc_text(INIT,Ki386BuildIdentityBuffer)
00042
#pragma alloc_text(INIT,Ki386ClearIdentityMap)
00043
#pragma alloc_text(INIT,Ki386ConvertPte)
00044
#pragma alloc_text(INIT,Ki386CreateIdentityMap)
00045
#pragma alloc_text(INIT,Ki386EnableTargetLargePage)
00046
#pragma alloc_text(INIT,Ki386IdentityMapMakeValid)
00047
#pragma alloc_text(INIT,Ki386MapAddress)
00048
00049
#endif
00050
00051 #define PTES_PER_PAGE (PAGE_SIZE / sizeof(HARDWARE_PTE))
00052
00053 BOOLEAN
00054 Ki386CreateIdentityMap(
00055 IN OUT
PIDENTITY_MAP IdentityMap,
00056 IN PVOID StartVa,
00057 IN PVOID EndVa
00058 )
00059 {
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 ULONG pageDirectoryIndex;
00090 ULONG pagesToMap;
00091 PCHAR currentVa;
00092 ULONG length;
00093 BOOLEAN result;
00094 PHARDWARE_PTE pageDirectory;
00095 PHARDWARE_PTE pageDirectoryEntry;
00096 PHYSICAL_ADDRESS identityAddress;
00097
00098
#if defined(_X86PAE_)
00099
00100 ULONG pageDirectoryPointerTableIndex;
00101 PHARDWARE_PTE pageDirectoryPointerTable;
00102 PHARDWARE_PTE pageDirectoryPointerTableEntry;
00103
00104
#endif
00105
00106
00107
00108
00109
00110 RtlZeroMemory( IdentityMap,
sizeof(
IDENTITY_MAP) );
00111 length = (PCHAR)EndVa - (PCHAR)StartVa;
00112
00113
00114
00115
00116
00117 identityAddress =
Ki386BuildIdentityBuffer( IdentityMap,
00118 StartVa,
00119 length,
00120 &pagesToMap );
00121
if( identityAddress.QuadPart == 0) {
00122
00123
00124
00125
00126
00127
00128
return FALSE;
00129 }
00130
00131 IdentityMap->IdentityAddr = identityAddress.LowPart;
00132
00133
00134
00135
00136
00137 currentVa = StartVa;
00138
do {
00139
00140
00141
00142
00143
00144 result =
Ki386MapAddress( IdentityMap,
00145 (ULONG)currentVa,
00146 identityAddress );
00147
if (result ==
FALSE) {
00148
return FALSE;
00149 }
00150
00151
00152
00153
00154
00155 result =
Ki386MapAddress( IdentityMap,
00156 identityAddress.LowPart,
00157 identityAddress );
00158
if (result ==
FALSE) {
00159
return FALSE;
00160 }
00161
00162
00163
00164
00165
00166
00167 currentVa +=
PAGE_SIZE;
00168 identityAddress.QuadPart +=
PAGE_SIZE;
00169 pagesToMap -= 1;
00170
00171 }
while (pagesToMap > 0);
00172
00173
00174
00175
00176
00177
00178
#if defined(_X86PAE_)
00179
00180
00181
00182
00183
00184
00185 pageDirectoryPointerTable = IdentityMap->TopLevelDirectory;
00186
for (pageDirectoryPointerTableIndex = 0;
00187 pageDirectoryPointerTableIndex < (1 <<
PPI_BITS);
00188 pageDirectoryPointerTableIndex++) {
00189
00190 pageDirectoryPointerTableEntry =
00191 &pageDirectoryPointerTable[ pageDirectoryPointerTableIndex ];
00192
00193
if (pageDirectoryPointerTableEntry->Valid == 0) {
00194
continue;
00195 }
00196
00197 pageDirectory =
00198 (PHARDWARE_PTE)
Ki386ConvertPte( pageDirectoryPointerTableEntry );
00199
00200
#else
00201
pageDirectory = IdentityMap->TopLevelDirectory;
00202
#endif
00203
00204
for (pageDirectoryIndex = 0;
00205 pageDirectoryIndex <
PTES_PER_PAGE;
00206 pageDirectoryIndex++) {
00207
00208 pageDirectoryEntry = &pageDirectory[ pageDirectoryIndex ];
00209
if (pageDirectoryEntry->Valid == 0) {
00210
continue;
00211 }
00212
00213
Ki386ConvertPte( pageDirectoryEntry );
00214 }
00215
00216
#if defined(_X86PAE_)
00217
}
00218
#endif
00219
00220 identityAddress =
MmGetPhysicalAddress( IdentityMap->TopLevelDirectory );
00221 IdentityMap->IdentityCR3 = identityAddress.LowPart;
00222
00223
return TRUE;
00224 }
00225
00226 PVOID
00227 Ki386AllocateContiguousMemory(
00228 IN OUT
PIDENTITY_MAP IdentityMap,
00229 IN ULONG Pages,
00230 IN BOOLEAN Low4Meg
00231 )
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 {
00252 ULONG pageListIndex;
00253 PVOID page;
00254 ULONG allocationSize;
00255 PHYSICAL_ADDRESS highestAddress;
00256
00257
if (Low4Meg !=
FALSE) {
00258
00259
00260
00261
00262
00263
00264 highestAddress.LowPart = 0xFFFFFFFF;
00265 highestAddress.HighPart = 0;
00266
00267 }
else {
00268
00269
00270
00271
00272
00273 highestAddress.LowPart = 0xFFFFFFFF;
00274 highestAddress.HighPart = 0xFFFFFFFF;
00275 }
00276
00277 allocationSize = Pages *
PAGE_SIZE;
00278 page =
MmAllocateContiguousMemory( allocationSize, highestAddress );
00279
if (page !=
NULL) {
00280
00281
00282
00283
00284
00285
00286 pageListIndex = IdentityMap->PagesAllocated;
00287 IdentityMap->PageList[ pageListIndex ] = page;
00288 IdentityMap->PagesAllocated++;
00289
00290
00291
00292
00293
00294 RtlZeroMemory( page, allocationSize );
00295 }
00296
00297
return page;
00298 }
00299
00300 BOOLEAN
00301 Ki386IdentityMapMakeValid(
00302 IN OUT
PIDENTITY_MAP IdentityMap,
00303 IN PHARDWARE_PTE PageTableEntry,
00304 OUT PVOID *Page OPTIONAL
00305 )
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 {
00334 PVOID page;
00335
00336
if (PageTableEntry->Valid != 0) {
00337
00338
00339
00340
00341
00342
00343 page = (PVOID)((ULONG)(PageTableEntry->PageFrameNumber <<
PAGE_SHIFT));
00344
00345 }
else {
00346
00347
00348
00349
00350
00351 page =
Ki386AllocateContiguousMemory( IdentityMap, 1,
FALSE );
00352
if (page ==
NULL) {
00353
return FALSE;
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 PageTableEntry->PageFrameNumber = ((ULONG)page) >>
PAGE_SHIFT;
00366 PageTableEntry->Valid = 1;
00367 }
00368
00369
if (ARGUMENT_PRESENT( Page )) {
00370 *Page = page;
00371 }
00372
00373
return TRUE;
00374 }
00375
00376 BOOLEAN
00377 Ki386MapAddress(
00378 IN OUT
PIDENTITY_MAP IdentityMap,
00379 IN ULONG Va,
00380 IN PHYSICAL_ADDRESS PhysicalAddress
00381 )
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 {
00401 PHARDWARE_PTE pageTable;
00402 PHARDWARE_PTE pageTableEntry;
00403 PHARDWARE_PTE pageDirectory;
00404 PHARDWARE_PTE pageDirectoryEntry;
00405 PVOID table;
00406 ULONG index;
00407 BOOLEAN result;
00408
00409
#if defined(_X86PAE_)
00410
PHARDWARE_PTE pageDirectoryPointerTable;
00411 PHARDWARE_PTE pageDirectoryPointerTableEntry;
00412
#endif
00413
00414
if (IdentityMap->TopLevelDirectory ==
NULL) {
00415
00416
00417
00418
00419
00420
00421 table =
Ki386AllocateContiguousMemory( IdentityMap, 1,
TRUE );
00422
if (table ==
FALSE) {
00423
return FALSE;
00424 }
00425
00426 IdentityMap->TopLevelDirectory = table;
00427 }
00428
00429
#if defined(_X86PAE_)
00430
00431 index =
KiGetPpeIndex( Va );
00432 pageDirectoryPointerTable = IdentityMap->TopLevelDirectory;
00433 pageDirectoryPointerTableEntry = &pageDirectoryPointerTable[ index ];
00434
00435 result =
Ki386IdentityMapMakeValid( IdentityMap,
00436 pageDirectoryPointerTableEntry,
00437 &pageDirectory );
00438
if (result ==
FALSE) {
00439
return FALSE;
00440 }
00441
00442
#else
00443
00444 pageDirectory = IdentityMap->TopLevelDirectory;
00445
00446
#endif
00447
00448
00449
00450
00451
00452
00453
00454 index =
KiGetPdeIndex( Va );
00455 pageDirectoryEntry = &pageDirectory[ index ];
00456 result =
Ki386IdentityMapMakeValid( IdentityMap,
00457 pageDirectoryEntry,
00458 &pageTable );
00459
if (result ==
FALSE) {
00460
return FALSE;
00461 }
00462 pageDirectoryEntry->Write = 1;
00463
00464
00465
00466
00467
00468 index =
KiGetPteIndex( Va );
00469 pageTableEntry = &pageTable[ index ];
00470
00471
#if defined(_X86PAE_)
00472
pageTableEntry->PageFrameNumber = PhysicalAddress.QuadPart >>
PAGE_SHIFT;
00473
#else
00474
pageTableEntry->PageFrameNumber = PhysicalAddress.LowPart >>
PAGE_SHIFT;
00475
#endif
00476
pageTableEntry->Valid = 1;
00477
00478
return TRUE;
00479 }
00480
00481 PVOID
00482 Ki386ConvertPte(
00483 IN OUT PHARDWARE_PTE Pte
00484 )
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 {
00499 PVOID va;
00500 PHYSICAL_ADDRESS physicalAddress;
00501
00502 va = (PVOID)(Pte->PageFrameNumber <<
PAGE_SHIFT);
00503 physicalAddress =
MmGetPhysicalAddress( va );
00504
00505
#if defined(_X86PAE_)
00506
Pte->PageFrameNumber = physicalAddress.QuadPart >>
PAGE_SHIFT;
00507
#else
00508
Pte->PageFrameNumber = physicalAddress.LowPart >>
PAGE_SHIFT;
00509
#endif
00510
00511
return va;
00512 }
00513
00514 PHYSICAL_ADDRESS
00515 Ki386BuildIdentityBuffer(
00516 IN OUT
PIDENTITY_MAP IdentityMap,
00517 IN PVOID StartVa,
00518 IN ULONG Length,
00519 OUT PULONG PagesToMap
00520 )
00521 {
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 ULONG pagesToMap;
00547 ULONG pagesRemaining;
00548 PCHAR nextVirtualAddress;
00549 PHYSICAL_ADDRESS nextPhysicalAddress;
00550 PHYSICAL_ADDRESS physicalAddress;
00551 PHYSICAL_ADDRESS firstPhysicalAddress;
00552 ULONG pageOffset;
00553 PCHAR identityBuffer;
00554
00555
00556
00557
00558
00559
00560 pagesToMap =
ADDRESS_AND_SIZE_TO_SPAN_PAGES( StartVa, Length );
00561 nextVirtualAddress = StartVa;
00562 firstPhysicalAddress =
MmGetPhysicalAddress( StartVa );
00563 nextPhysicalAddress = firstPhysicalAddress;
00564
00565
00566
00567
00568
00569 pagesRemaining = pagesToMap;
00570
while (
TRUE) {
00571
00572 physicalAddress =
MmGetPhysicalAddress( nextVirtualAddress );
00573
if (physicalAddress.QuadPart != nextPhysicalAddress.QuadPart) {
00574
00575
00576
00577
00578
00579
break;
00580 }
00581
00582
if (physicalAddress.HighPart != 0) {
00583
00584
00585
00586
00587
00588
break;
00589 }
00590
00591 pagesRemaining -= 1;
00592
if (pagesRemaining == 0) {
00593
00594
00595
00596
00597
00598
00599
00600 *PagesToMap = pagesToMap;
00601
return firstPhysicalAddress;
00602 }
00603
00604 nextVirtualAddress +=
PAGE_SIZE;
00605 nextPhysicalAddress.QuadPart +=
PAGE_SIZE;
00606 }
00607
00608
00609
00610
00611
00612
00613 identityBuffer =
Ki386AllocateContiguousMemory( IdentityMap,
00614 pagesToMap,
00615
TRUE );
00616
if (identityBuffer == 0) {
00617
00618
00619
00620
00621
00622
00623 physicalAddress.QuadPart = 0;
00624
00625 }
else {
00626
00627
00628
00629
00630
00631 pageOffset = (ULONG)StartVa & (
PAGE_SIZE-1);
00632 identityBuffer += pageOffset;
00633
00634 RtlCopyMemory( identityBuffer, StartVa, Length );
00635 physicalAddress =
MmGetPhysicalAddress( identityBuffer );
00636
00637 *PagesToMap = pagesToMap;
00638 }
00639
00640
return physicalAddress;
00641 }
00642
00643
00644
00645
VOID
00646 Ki386ClearIdentityMap(
00647 IN
PIDENTITY_MAP IdentityMap
00648 )
00649 {
00650
00651
00652
00653
00654
00655
00656
00657 ULONG index;
00658 PVOID page;
00659
00660
00661
00662
00663
00664
00665
for (index = 0; index < IdentityMap->PagesAllocated; index++) {
00666
00667 page = IdentityMap->PageList[ index ];
00668
MmFreeContiguousMemory( page );
00669 }
00670 }
00671
00672
VOID
00673 Ki386EnableTargetLargePage(
00674 IN
PIDENTITY_MAP IdentityMap
00675 )
00676 {
00677
00678
00679
00680
00681
00682
00683
00684
Ki386EnableCurrentLargePage(IdentityMap->IdentityAddr,
00685 IdentityMap->IdentityCR3);
00686 }