test: largepag.c File Reference

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

# largepag.c File Reference

`#include "ki.h"`
`#include "ki386.h"`

Go to the source code of this file.

## Defines

#define | PTES_PER_PAGE (PAGE_SIZE / sizeof(HARDWARE_PTE))

## Functions

PVOID | Ki386AllocateContiguousMemory (IN OUT PIDENTITY_MAP IdentityMap, IN ULONG Pages, IN BOOLEAN Low4Meg)
BOOLEAN | Ki386IdentityMapMakeValid (IN OUT PIDENTITY_MAP IdentityMap, IN PHARDWARE_PTE PageTableEntry, OUT PVOID *Page OPTIONAL)
BOOLEAN | Ki386MapAddress (IN OUT PIDENTITY_MAP IdentityMap, IN ULONG Va, IN PHYSICAL_ADDRESS PhysicalAddress)
PVOID | Ki386ConvertPte (IN OUT PHARDWARE_PTE Pte)
PHYSICAL_ADDRESS | Ki386BuildIdentityBuffer (IN OUT PIDENTITY_MAP IdentityMap, IN PVOID StartVa, IN ULONG Length, OUT PULONG PagesToMap)
BOOLEAN | Ki386CreateIdentityMap (IN OUT PIDENTITY_MAP IdentityMap, IN PVOID StartVa, IN PVOID EndVa)
VOID | Ki386ClearIdentityMap (IN PIDENTITY_MAP IdentityMap)
VOID | Ki386EnableTargetLargePage (IN PIDENTITY_MAP IdentityMap)

## Define Documentation

#define PTES_PER_PAGE (PAGE_SIZE / sizeof(HARDWARE_PTE))

| Definition at line 51 of file largepag.c. Referenced by Ki386CreateIdentityMap().

## Function Documentation

PVOID Ki386AllocateContiguousMemory | ( | IN OUT PIDENTITY_MAP | IdentityMap,
|  | IN ULONG | Pages,
|  | IN BOOLEAN | Low4Meg
| ) |

Definition at line 227 of file largepag.c.

References FALSE, MmAllocateContiguousMemory(), NULL, and PAGE_SIZE.

Referenced by Ki386BuildIdentityBuffer(), Ki386IdentityMapMakeValid(), and Ki386MapAddress().

    00238          :
    00239
    00240     IdentityMap - Context pointer for this identity mapping.
    00241
    00242     Pages - Number of pages to allocate
    00243
    00244     Low4Meg - Indicates whether the allocation must be below 4M.
    00245
    00246 Return Value:
    00247
    00248     Pointer to the new page on success, NULL otherwise.
    00249
    00250 --*/
    00251 {
    00252     ULONG pageListIndex;
    00253     PVOID page;
    00254     ULONG allocationSize;
    00255     PHYSICAL_ADDRESS highestAddress;
    00256
    00257     if (Low4Meg != FALSE) {
    00258
    00259         //
    00260         // The caller has specified that a page must reside physically
    00261         // below 4 MB.
    00262         //
    00263
    00264         highestAddress.LowPart = 0xFFFFFFFF;
    00265         highestAddress.HighPart = 0;
    00266
    00267     } else {
    00268
    00269         //
    00270         // Memory can reside anywhere
    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         // Record that this page was allocated so that it can be freed when
    00283         // the IdentityMap structure is cleared.
    00284         //
    00285
    00286         pageListIndex = IdentityMap->PagesAllocated;
    00287         IdentityMap->PageList[ pageListIndex ] = page;
    00288         IdentityMap->PagesAllocated++;
    00289
    00290         //
    00291         // Initialize it.
    00292         //
    00293
    00294         RtlZeroMemory( page, allocationSize );
    00295     }
    00296
    00297     return page;
    00298 }

PHYSICAL_ADDRESS Ki386BuildIdentityBuffer | ( | IN OUT PIDENTITY_MAP | IdentityMap,
|  | IN PVOID | StartVa,
|  | IN ULONG | Length,
|  | OUT PULONG | PagesToMap
| ) |

Definition at line 515 of file largepag.c.

References ADDRESS_AND_SIZE_TO_SPAN_PAGES, Ki386AllocateContiguousMemory(), MmGetPhysicalAddress(), PAGE_SIZE, and TRUE.

Referenced by Ki386CreateIdentityMap().

    00521 {
    00522
    00523 /*++
    00524
    00525     This function checks to see if the physical memory backing a virtual
    00526     buffer is physically contiguous and lies completely below 4G.
    00527
    00528     If these requirements are met, then the physical address of StartVa is
    00529     returned.
    00530
    00531     If not, then a physically contiguous buffer is allocated, the contents
    00532     of the region is copied in, and its address is returned.
    00533
    00534 Arguments:
    00535
    00536     IdentityMap - Pointer to the identity map building structure.
    00537
    00538     StartVa - Virtual address of the start of the region for which a
    00539               physically contiguous copy is desired.
    00540
    00541     Length - Length of the region for which a physically contiguous copy
    00542              is desired.
    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     // Count the number of pages in the buffer, and record the physical
    00557     // address of the start of the buffer.
    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     // Examine each page in the region.
    00567     //
    00568
    00569     pagesRemaining = pagesToMap;
    00570     while (TRUE) {
    00571
    00572         physicalAddress = MmGetPhysicalAddress( nextVirtualAddress );
    00573         if (physicalAddress.QuadPart != nextPhysicalAddress.QuadPart) {
    00574
    00575             //
    00576             // The buffer is not physically contiguous.
    00577             //
    00578
    00579             break;
    00580         }
    00581
    00582         if (physicalAddress.HighPart != 0) {
    00583
    00584             //
    00585             // The buffer does not lie entirely below 4G
    00586             //
    00587
    00588             break;
    00589         }
    00590
    00591         pagesRemaining -= 1;
    00592         if (pagesRemaining == 0) {
    00593
    00594             //
    00595             // All of the pages in the buffer have been examined, and have
    00596             // been found to meet the critera.  Return the physical address
    00597             // of the start of the buffer.
    00598             //
    00599
    00600             *PagesToMap = pagesToMap;
    00601             return firstPhysicalAddress;
    00602         }
    00603
    00604         nextVirtualAddress += PAGE_SIZE;
    00605         nextPhysicalAddress.QuadPart += PAGE_SIZE;
    00606     }
    00607
    00608     //
    00609     // The buffer does not meet the criteria and so its contents must be
    00610     // copied to a buffer that does.
    00611     //
    00612
    00613     identityBuffer = Ki386AllocateContiguousMemory( IdentityMap,
    00614                                                     pagesToMap,
    00615                                                     TRUE );
    00616     if (identityBuffer == 0) {
    00617
    00618         //
    00619         // A contiguous region of the appropriate size could not be located
    00620         // below 4G physical.
    00621         //
    00622
    00623         physicalAddress.QuadPart = 0;
    00624
    00625     } else {
    00626
    00627         //
    00628         // Got an appropriate physical buffer, now copy in the data
    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 }

VOID Ki386ClearIdentityMap | ( | IN PIDENTITY_MAP | IdentityMap | ) |

Definition at line 646 of file largepag.c.

References MmFreeContiguousMemory().

Referenced by KiInitMachineDependent().

    00649 {
    00650 /*++
    00651
    00652     This function just frees the page directory and page tables created in
    00653     Ki386CreateIdentityMap().
    00654
    00655 --*/
    00656
    00657     ULONG index;
    00658     PVOID page;
    00659
    00660     //
    00661     // IdentityMap->PageList is an array of addresses of pages allocated with
    00662     // MmAllocateContiguousMemory().  Walk the array, freeing each page.
    00663     //
    00664
    00665     for (index = 0; index < IdentityMap->PagesAllocated; index++) {
    00666
    00667         page = IdentityMap->PageList[ index ];
    00668         MmFreeContiguousMemory( page );
    00669     }
    00670 }

PVOID Ki386ConvertPte | ( | IN OUT PHARDWARE_PTE | Pte | ) |

Definition at line 482 of file largepag.c.

References MmGetPhysicalAddress(), and PAGE_SHIFT.

Referenced by Ki386CreateIdentityMap().

    00489          :
    00490
    00491     Pte - Pointer to the page table entry to convert.
    00492
    00493 Return Value:
    00494
    00495     None.
    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 }

BOOLEAN Ki386CreateIdentityMap | ( | IN OUT PIDENTITY_MAP | IdentityMap,
|  | IN PVOID | StartVa,
|  | IN PVOID | EndVa
| ) |

Definition at line 54 of file largepag.c.

References FALSE, Ki386BuildIdentityBuffer(), Ki386ConvertPte(), Ki386MapAddress(), MmGetPhysicalAddress(), PAGE_SIZE, PPI_BITS, PTES_PER_PAGE, and TRUE.

Referenced by KiInitMachineDependent().

    00059 {
    00060 /*++
    00061
    00062     This function creates an identity mapping for a region of memory.
    00063
    00064     If the region of memory passed in includes memory that lies above
    00065     4G, then a new buffer is allocated below 4G.
    00066
    00067 Arguments:
    00068
    00069     IdentityMap - Pointer to the structure which will be filled with the newly
    00070                   created top-level directory address.  It also provides
    00071                   storage for the pointers used in alloating and freeing the
    00072                   memory.
    00073
    00074     StartVa - Pointer to the first byte of the region of memory that is to be
    00075               memory mapped.
    00076
    00077     EndVa - Pointer to the byte immediately after the last byte of the region
    00078             that is to be memory mapped.
    00079
    00080 Return Value:
    00081
    00082     TRUE if the function succeeds, FALSE otherwise.
    00083
    00084     Note - Ki386ClearIdentityMap() should be called even on FALSE return to
    00085     free any memory allocated.
    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     // Initialize the IdentityMap structure to a known state.
    00108     //
    00109
    00110     RtlZeroMemory( IdentityMap, sizeof(IDENTITY_MAP) );
    00111     length = (PCHAR)EndVa - (PCHAR)StartVa;
    00112
    00113     //
    00114     // Get the physical address of the input buffer (or suitable copy).
    00115     //
    00116
    00117     identityAddress = Ki386BuildIdentityBuffer( IdentityMap,
    00118                                                 StartVa,
    00119                                                 length,
    00120                                                 &pagesToMap );
    00121     if( identityAddress.QuadPart == 0) {
    00122
    00123         //
    00124         // The input buffer was not contiguous or not below 4G, and a
    00125         // suitable buffer could not be allocated.
    00126         //
    00127
    00128         return FALSE;
    00129     }
    00130
    00131     IdentityMap->IdentityAddr = identityAddress.LowPart;
    00132
    00133     //
    00134     // Set up the mappings.
    00135     //
    00136
    00137     currentVa = StartVa;
    00138     do {
    00139
    00140         //
    00141         // Map in the virtual address
    00142         //
    00143
    00144         result = Ki386MapAddress( IdentityMap,
    00145                                   (ULONG)currentVa,
    00146                                   identityAddress );
    00147         if (result == FALSE) {
    00148             return FALSE;
    00149         }
    00150
    00151         //
    00152         // Map in the identity (physical) address
    00153         //
    00154
    00155         result = Ki386MapAddress( IdentityMap,
    00156                                   identityAddress.LowPart,
    00157                                   identityAddress );
    00158         if (result == FALSE) {
    00159             return FALSE;
    00160         }
    00161
    00162         //
    00163         // Advance both the Va and identityAddress pointers in anticipation
    00164         // of mapping in another page.
    00165         //
    00166
    00167         currentVa += PAGE_SIZE;
    00168         identityAddress.QuadPart += PAGE_SIZE;
    00169         pagesToMap -= 1;
    00170
    00171     } while (pagesToMap > 0);
    00172
    00173     //
    00174     // Now go through the page directory pointer table and page directories,
    00175     // converting virtual page frames to physical ones.
    00176     //
    00177
    00178 #if defined(_X86PAE_)
    00179
    00180     //
    00181     // This PAE-only outer loop walks the page directory pointer table entries
    00182     // and processes each valid page directory referenced.
    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 }

VOID Ki386EnableTargetLargePage | ( | IN PIDENTITY_MAP | IdentityMap | ) |

Definition at line 673 of file largepag.c.

References Ki386EnableCurrentLargePage().

    00676 {
    00677 /*++
    00678
    00679     This function just passes info on to the assembly routine
    00680     Ki386EnableLargePage().
    00681
    00682 --*/
    00683
    00684     Ki386EnableCurrentLargePage(IdentityMap->IdentityAddr,
    00685                                 IdentityMap->IdentityCR3);
    00686 }

BOOLEAN Ki386IdentityMapMakeValid | ( | IN OUT PIDENTITY_MAP | IdentityMap,
|  | IN PHARDWARE_PTE | PageTableEntry,
|  | OUT PVOID *Page | OPTIONAL
| ) |

Definition at line 301 of file largepag.c.

References FALSE, Ki386AllocateContiguousMemory(), NULL, PAGE_SHIFT, and TRUE.

Referenced by Ki386MapAddress().

    00315         : At this point, PTE frames are virtual.  After the entire mapping
    00316           is built, we go through and convert all virtual frames to physical
    00317           ones.
    00318
    00319 Arguments:
    00320
    00321     IdentityMap - Context pointer for this identity mapping.
    00322
    00323     PageTableEntry - Pointer to the page table entry.
    00324
    00325     Page - Virtual address now referenced by the PTE, whether it was
    00326            valid before or not.
    00327
    00328 Return Value:
    00329
    00330     TRUE on success, FALSE otherwise.
    00331
    00332 --*/
    00333 {
    00334     PVOID page;
    00335
    00336     if (PageTableEntry->Valid != 0) {
    00337
    00338         //
    00339         // If it already is present, there is nothing to do except record
    00340         // the virtual page number that is already there.
    00341         //
    00342
    00343         page = (PVOID)((ULONG)(PageTableEntry->PageFrameNumber << PAGE_SHIFT));
    00344
    00345     } else {
    00346
    00347         //
    00348         // The page table entry is not valid.  Allocate a new page table.
    00349         //
    00350
    00351         page = Ki386AllocateContiguousMemory( IdentityMap, 1, FALSE );
    00352         if (page == NULL) {
    00353             return FALSE;
    00354         }
    00355
    00356         //
    00357         // Insert it into the page table entry and mark it valid.
    00358         //
    00359         // NOTE: Virtual page numbers are inserted into the page table
    00360         //       structure as it is being built.  When it is finished, we walk
    00361         //       the tables and convert all of the virtual page numbers to
    00362         //       physical page numbers.
    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 }

BOOLEAN Ki386MapAddress | ( | IN OUT PIDENTITY_MAP | IdentityMap,
|  | IN ULONG | Va,
|  | IN PHYSICAL_ADDRESS | PhysicalAddress
| ) |

Definition at line 377 of file largepag.c.

References FALSE, Ki386AllocateContiguousMemory(), Ki386IdentityMapMakeValid(), KiGetPdeIndex, KiGetPpeIndex, KiGetPteIndex, NULL, PAGE_SHIFT, and TRUE.

Referenced by Ki386CreateIdentityMap().

    00387          :
    00388
    00389     IdentityMap - Context pointer for this identity mapping.
    00390
    00391     Va - Virtual address to map.
    00392
    00393     PhysicalAddress - Physical address to map.
    00394
    00395 Return Value:
    00396
    00397     TRUE on success, FALSE otherwise.
    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         // Allocate a top-level directory structure, either a page directory
    00418         // or a page directory pointer table.
    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     // Get a pointer to the appropriate page directory entry.  If it is
    00450     // not valid, allocate a new page table and mark the page directory
    00451     // entry valid and writeable.
    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     // Get a pointer to the appropriate page table entry and fill it in.
    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 }