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

largepag.c

Go to the documentation of this file.
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 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 } 00225 00226 PVOID 00227 Ki386AllocateContiguousMemory( 00228 IN OUT PIDENTITY_MAP IdentityMap, 00229 IN ULONG Pages, 00230 IN BOOLEAN Low4Meg 00231 ) 00232 /*++ 00233 00234 This function allocates page-aligned, physically contiguous memory. 00235 The allocation is recorded in the IdentityMap structure, so that it 00236 can be freed on cleanup. 00237 00238 Arguments: 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 } 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 If the page table has the valid bit set, this function merely returns 00309 the address referenced by the page table entry. 00310 00311 If the page table does not have the valid bit set, then another page 00312 is allocated and inserted into the page table entry and the entry is 00313 marked valid. 00314 00315 NOTE: 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 } 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 Creates a new virtual->physical mapping in the identity map. 00386 00387 Arguments: 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 } 00480 00481 PVOID 00482 Ki386ConvertPte( 00483 IN OUT PHARDWARE_PTE Pte 00484 ) 00485 /*++ 00486 00487 Converts the virtual frame number in a PTE to a physical frame number. 00488 00489 Arguments: 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 } 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 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 } 00642 00643 00644 00645 VOID 00646 Ki386ClearIdentityMap( 00647 IN PIDENTITY_MAP IdentityMap 00648 ) 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 } 00671 00672 VOID 00673 Ki386EnableTargetLargePage( 00674 IN PIDENTITY_MAP IdentityMap 00675 ) 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 }

Generated on Sat May 15 19:40:36 2004 for test by doxygen 1.3.7