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

physsect.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 Copyright (c) 1992 Digital Equipment Corporation 00005 00006 Module Name: 00007 00008 physsect.c 00009 00010 Abstract: 00011 00012 This module contains the routine for mapping physical sections for 00013 ALPHA machines. 00014 00015 Author: 00016 00017 Lou Perazzoli (loup) 22-May-1989 00018 Joe Notarangelo 21-Sep-1992 00019 00020 Revision History: 00021 00022 Landy Wang (landyw) 08-April-1998 : Modifications for 3-level 64-bit NT. 00023 00024 --*/ 00025 00026 #include "mi.h" 00027 00028 //#define FIRSTDBG 1 00029 //#define AGGREGATE_DBG FIRSTDBG 00030 00031 00032 static 00033 ULONG 00034 MaximumAlignment( ULONG ); 00035 00036 static 00037 ULONG 00038 AggregatePages( PMMPTE, ULONG, ULONG, PULONG ); 00039 00040 00041 00042 NTSTATUS 00043 MiMapViewOfPhysicalSection ( 00044 IN PCONTROL_AREA ControlArea, 00045 IN PEPROCESS Process, 00046 IN PVOID *CapturedBase, 00047 IN PLARGE_INTEGER SectionOffset, 00048 IN PSIZE_T CapturedViewSize, 00049 IN ULONG ProtectionMask, 00050 IN ULONG_PTR ZeroBits, 00051 IN ULONG AllocationType, 00052 IN BOOLEAN WriteCombined, 00053 OUT PBOOLEAN ReleasedWsMutex 00054 ) 00055 00056 /*++ 00057 00058 Routine Description: 00059 00060 This routine maps the specified physical section into the 00061 specified process's address space. 00062 00063 Arguments: 00064 00065 see MmMapViewOfSection above... 00066 00067 ControlArea - Supplies the control area for the section. 00068 00069 Process - Supplies the process pointer which is receiving the section. 00070 00071 ProtectionMask - Supplies the initial page protection-mask. 00072 00073 ReleasedWsMutex - Supplies FALSE, receives TRUE if the working set 00074 mutex is released. 00075 00076 Return Value: 00077 00078 Status of the map view operation. 00079 00080 Environment: 00081 00082 Kernel Mode, working set mutex and address creation mutex held. 00083 00084 --*/ 00085 00086 { 00087 PMMVAD Vad; 00088 PVOID StartingAddress; 00089 PVOID EndingAddress; 00090 KIRQL OldIrql; 00091 KIRQL OldIrql2; 00092 PMMPTE PointerPpe; 00093 PMMPTE PointerPde; 00094 PMMPTE PointerPte; 00095 PMMPTE LastPte; 00096 MMPTE TempPte; 00097 PMMPFN Pfn2; 00098 ULONG PhysicalViewSize; 00099 ULONG Alignment; 00100 ULONG PagesToMap; 00101 ULONG NextPfn; 00102 PVOID UsedPageTableHandle; 00103 PVOID UsedPageDirectoryHandle; 00104 PMI_PHYSICAL_VIEW PhysicalView; 00105 00106 // 00107 // Physical memory section. 00108 // 00109 00110 #ifdef FIRSTDBG 00111 00112 DbgPrint( "MM: Physsect CaptureBase = %x SectionOffset = %x\n", 00113 CapturedBase, SectionOffset->LowPart ); 00114 DbgPrint( "MM: Physsect Allocation Type = %x, MEM_LARGE_PAGES = %x\n", 00115 AllocationType, MEM_LARGE_PAGES ); 00116 00117 #endif //FIRSTDBG 00118 00119 // 00120 // Compute the alignment we require for the virtual mapping. 00121 // The default is 64K to match protection boundaries. 00122 // Larger page sizes are used if MEM_LARGE_PAGES is requested. 00123 // The Alpha AXP architecture supports granularity hints so that 00124 // larger pages can be defined in the following multiples of 00125 // PAGE_SIZE: 00126 // 8**(GH) * PAGE_SIZE, where GH element of {0,1,2,3} 00127 // 00128 00129 Alignment = X64K; 00130 00131 if( AllocationType & MEM_LARGE_PAGES ){ 00132 00133 // 00134 // MaxAlignment is the maximum boundary alignment of the 00135 // SectionOffset (where the maximum boundary is one of the possible 00136 // granularity hints boundaries) 00137 // 00138 00139 ULONG MaxAlignment = MaximumAlignment( SectionOffset->LowPart ); 00140 00141 Alignment = (MaxAlignment > Alignment) ? MaxAlignment : Alignment; 00142 00143 #ifdef FIRSTDBG 00144 00145 DbgPrint( "MM: Alignment = %x, SectionOffset = %x\n", 00146 Alignment, SectionOffset->LowPart ); 00147 00148 #endif //FIRSTDBG 00149 00150 } 00151 00152 00153 LOCK_WS_UNSAFE (Process); 00154 00155 if (*CapturedBase == NULL) { 00156 00157 // 00158 // Attempt to locate address space. This could raise an 00159 // exception. 00160 // 00161 00162 try { 00163 00164 // 00165 // Find a starting address on an alignment boundary. 00166 // 00167 00168 00169 PhysicalViewSize = (SectionOffset->LowPart + *CapturedViewSize) - 00170 (ULONG)MI_64K_ALIGN(SectionOffset->LowPart); 00171 StartingAddress = MiFindEmptyAddressRange (PhysicalViewSize, 00172 Alignment, 00173 (ULONG)ZeroBits); 00174 00175 } except (EXCEPTION_EXECUTE_HANDLER) { 00176 00177 return GetExceptionCode(); 00178 } 00179 00180 EndingAddress = (PVOID)(((ULONG)StartingAddress + 00181 PhysicalViewSize - 1L) | (PAGE_SIZE - 1L)); 00182 StartingAddress = (PVOID)((ULONG)StartingAddress + 00183 (SectionOffset->LowPart & (X64K - 1))); 00184 00185 if (ZeroBits > 0) { 00186 if (EndingAddress > (PVOID)((ULONG)0xFFFFFFFF >> ZeroBits)) { 00187 return STATUS_NO_MEMORY; 00188 } 00189 } 00190 00191 } else { 00192 00193 // 00194 // Check to make sure the specified base address to ending address 00195 // is currently unused. 00196 // 00197 00198 PhysicalViewSize = (SectionOffset->LowPart + *CapturedViewSize) - 00199 (ULONG)MI_64K_ALIGN(SectionOffset->LowPart); 00200 StartingAddress = (PVOID)((ULONG)MI_64K_ALIGN(*CapturedBase) + 00201 (SectionOffset->LowPart & (X64K - 1))); 00202 EndingAddress = (PVOID)(((ULONG)StartingAddress + 00203 *CapturedViewSize - 1L) | (PAGE_SIZE - 1L)); 00204 00205 Vad = MiCheckForConflictingVad (StartingAddress, EndingAddress); 00206 if (Vad != (PMMVAD)NULL) { 00207 #if 0 00208 MiDumpConflictingVad (StartingAddress, EndingAddress, Vad); 00209 #endif 00210 00211 return STATUS_CONFLICTING_ADDRESSES; 00212 } 00213 } 00214 00215 // 00216 // An unoccuppied address range has been found, build the virtual 00217 // address descriptor to describe this range. 00218 // 00219 00220 // 00221 // Establish an exception handler and attempt to allocate 00222 // the pool and charge quota. Note that the InsertVad routine 00223 // will also charge quota which could raise an exception. 00224 // 00225 00226 try { 00227 00228 PhysicalView = (PMI_PHYSICAL_VIEW)ExAllocatePoolWithTag (NonPagedPool, 00229 sizeof(MI_PHYSICAL_VIEW), 00230 MI_PHYSICAL_VIEW_KEY); 00231 if (PhysicalView == NULL) { 00232 ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES); 00233 } 00234 00235 Vad = (PMMVAD)ExAllocatePoolWithTag (NonPagedPool, sizeof(MMVAD), ' daV'); 00236 if (Vad == NULL) { 00237 ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES); 00238 } 00239 00240 PhysicalView->Vad = Vad; 00241 PhysicalView->StartVa = StartingAddress; 00242 PhysicalView->EndVa = EndingAddress; 00243 00244 Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress); 00245 Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress); 00246 Vad->ControlArea = ControlArea; 00247 Vad->u.LongFlags = 0; 00248 Vad->u2.VadFlags2.Inherit = ViewUnmap; 00249 Vad->u.VadFlags.PhysicalMapping = 1; 00250 Vad->u4.Banked = NULL; 00251 // Vad->u.VadFlags.ImageMap = 0; 00252 Vad->u.VadFlags.Protection = ProtectionMask; 00253 Vad->u2.VadFlags2.CopyOnWrite = 0; 00254 // Vad->u.VadFlags.LargePages = 0; 00255 Vad->FirstPrototypePte = 00256 (PMMPTE)(MI_CONVERT_PHYSICAL_BUS_TO_PFN(*SectionOffset)); 00257 00258 // 00259 // Set the first prototype PTE field in the Vad. 00260 // 00261 00262 Vad->LastContiguousPte = 00263 (PMMPTE)(MI_CONVERT_PHYSICAL_BUS_TO_PFN(*SectionOffset)); 00264 00265 // 00266 // Insert the VAD. This could get an exception. 00267 // 00268 00269 MiInsertVad (Vad); 00270 00271 } except (EXCEPTION_EXECUTE_HANDLER) { 00272 00273 if (PhysicalView != NULL) { 00274 ExFreePool (PhysicalView); 00275 } 00276 00277 if (Vad != (PMMVAD)NULL) { 00278 00279 // 00280 // The pool allocation suceeded, but the quota charge 00281 // in InsertVad failed, deallocate the pool and return 00282 // an error. 00283 // 00284 00285 ExFreePool (Vad); 00286 return GetExceptionCode(); 00287 } 00288 return STATUS_INSUFFICIENT_RESOURCES; 00289 } 00290 00291 // Increment the count of the number of views for the 00292 // section object. This requires the PFN mutex to be held. 00293 // 00294 00295 LOCK_AWE (Process, OldIrql); 00296 LOCK_PFN2 (OldIrql2); 00297 00298 InsertHeadList (&Process->PhysicalVadList, &PhysicalView->ListEntry); 00299 00300 ControlArea->NumberOfMappedViews += 1; 00301 ControlArea->NumberOfUserReferences += 1; 00302 ASSERT (ControlArea->NumberOfSectionReferences != 0); 00303 00304 UNLOCK_PFN2 (OldIrql2); 00305 UNLOCK_AWE (Process, OldIrql); 00306 00307 // 00308 // Build the PTEs in the address space. 00309 // 00310 00311 PointerPpe = MiGetPpeAddress (StartingAddress); 00312 PointerPde = MiGetPdeAddress (StartingAddress); 00313 PointerPte = MiGetPteAddress (StartingAddress); 00314 LastPte = MiGetPteAddress (EndingAddress); 00315 00316 #if defined (_WIN64) 00317 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 00318 if (PointerPde->u.Long == 0) { 00319 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00320 ASSERT (MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0); 00321 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 00322 } 00323 #endif 00324 00325 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 00326 00327 Pfn2 = MI_PFN_ELEMENT(PointerPde->u.Hard.PageFrameNumber); 00328 00329 PagesToMap = ( ((ULONG)EndingAddress - (ULONG)StartingAddress) 00330 + (PAGE_SIZE-1) ) >> PAGE_SHIFT; 00331 00332 NextPfn = MI_CONVERT_PHYSICAL_BUS_TO_PFN(*SectionOffset); 00333 00334 #ifdef FIRSTDBG 00335 00336 DbgPrint( "MM: Physsect, PagesToMap = %x NextPfn = %x\n", 00337 PagesToMap, NextPfn ); 00338 00339 #endif //FIRSTDBG 00340 00341 MI_MAKE_VALID_PTE (TempPte, 00342 NextPfn, 00343 ProtectionMask, 00344 PointerPte); 00345 00346 if (WriteCombined == TRUE) { 00347 MI_SET_PTE_WRITE_COMBINE (TempPte); 00348 } 00349 00350 if (TempPte.u.Hard.Write) { 00351 TempPte.u.Hard.Dirty = 1; 00352 } 00353 00354 while (PointerPte <= LastPte) { 00355 00356 ULONG PagesTogether; 00357 ULONG GranularityHint; 00358 00359 // 00360 // Compute the number of pages that can be mapped together 00361 // 00362 00363 if (AllocationType & MEM_LARGE_PAGES) { 00364 PagesTogether = AggregatePages (PointerPte, 00365 NextPfn, 00366 PagesToMap, 00367 &GranularityHint); 00368 } else { 00369 PagesTogether = 1; 00370 GranularityHint = 0; 00371 } 00372 00373 #ifdef FIRSTDBG 00374 00375 DbgPrint( "MM: Physsect PointerPte = %x, NextPfn = %x\n", 00376 PointerPte, NextPfn ); 00377 DbgPrint( "MM: Va = %x TempPte.Pfn = %x\n", 00378 MiGetVirtualAddressMappedByPte( PointerPte ), 00379 TempPte.u.Hard.PageFrameNumber ); 00380 DbgPrint( "MM: PagesToMap = %x\n", PagesToMap ); 00381 DbgPrint( "MM: PagesTogether = %x, GH = %x\n", 00382 PagesTogether, GranularityHint ); 00383 00384 #endif //FIRSTDBG 00385 00386 TempPte.u.Hard.GranularityHint = GranularityHint; 00387 00388 NextPfn += PagesTogether; 00389 PagesToMap -= PagesTogether; 00390 00391 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte)); 00392 00393 while (PagesTogether--) { 00394 00395 if (MiIsPteOnPdeBoundary (PointerPte)) { 00396 00397 PointerPde = MiGetPteAddress (PointerPte); 00398 00399 if (MiIsPteOnPpeBoundary (PointerPte)) { 00400 PointerPpe = MiGetPteAddress (PointerPde); 00401 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 00402 if (PointerPde->u.Long == 0) { 00403 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00404 ASSERT (MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0); 00405 00406 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 00407 } 00408 } 00409 00410 MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE); 00411 Pfn2 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); 00412 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte)); 00413 } 00414 00415 ASSERT( PointerPte->u.Long == 0 ); 00416 00417 *PointerPte = TempPte; 00418 #if PFN_CONSISTENCY 00419 LOCK_PFN (OldIrql); 00420 #endif 00421 Pfn2->u2.ShareCount += 1; 00422 #if PFN_CONSISTENCY 00423 UNLOCK_PFN (OldIrql); 00424 #endif 00425 00426 // 00427 // Increment the count of non-zero page table entries for this 00428 // page table and the number of private pages for the process. 00429 // 00430 00431 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 00432 00433 PointerPte += 1; 00434 00435 TempPte.u.Hard.PageFrameNumber += 1; 00436 00437 } // while (PagesTogether-- ) 00438 00439 } // while (PointerPte <= LastPte) 00440 00441 UNLOCK_WS_UNSAFE (Process); 00442 *ReleasedWsMutex = TRUE; 00443 00444 // 00445 // Update the current virtual size in the process header. 00446 // 00447 00448 *CapturedViewSize = (ULONG)EndingAddress - (ULONG)StartingAddress + 1L; 00449 Process->VirtualSize += *CapturedViewSize; 00450 00451 if (Process->VirtualSize > Process->PeakVirtualSize) { 00452 Process->PeakVirtualSize = Process->VirtualSize; 00453 } 00454 00455 // 00456 // Translate the virtual address to a quasi-virtual address for 00457 // use by drivers that touch mapped devices. Note: the routine 00458 // HalCreateQva will not translate the StartingAddress if the 00459 // StartingAddress is within system memory address space. 00460 // 00461 // N.B. - It will not work to attempt map addresses that begin in 00462 // system memory and extend through i/o space. 00463 // 00464 00465 *CapturedBase = HalCreateQva( *SectionOffset, StartingAddress ); 00466 00467 return STATUS_SUCCESS; 00468 } 00469 00470 00471 ULONG 00472 MaximumAlignment( 00473 IN ULONG Offset 00474 ) 00475 /*++ 00476 00477 Routine Description: 00478 00479 This routine returns the maximum granularity hint alignment boundary 00480 to which Offset is naturally aligned. 00481 00482 Arguments: 00483 00484 Offset - Supplies the address offset to check for alignment. 00485 00486 Return Value: 00487 00488 The number which represents the largest natural alignment of Offset. 00489 00490 Environment: 00491 00492 --*/ 00493 { 00494 00495 if( (Offset & (GH3_PAGE_SIZE - 1)) == 0 ){ 00496 return GH3_PAGE_SIZE; 00497 } 00498 00499 if( (Offset & (GH2_PAGE_SIZE - 1)) == 0 ){ 00500 return GH2_PAGE_SIZE; 00501 } 00502 00503 if( (Offset & (GH1_PAGE_SIZE - 1)) == 0 ){ 00504 return GH1_PAGE_SIZE; 00505 } 00506 00507 if( (Offset & (PAGE_SIZE - 1)) == 0 ){ 00508 return PAGE_SIZE; 00509 } 00510 00511 return 0; 00512 } 00513 00514 00515 ULONG 00516 AggregatePages( 00517 IN PMMPTE PointerPte, 00518 IN ULONG Pfn, 00519 IN ULONG Pages, 00520 OUT PULONG GranularityHint 00521 ) 00522 /*++ 00523 00524 Routine Description: 00525 00526 This routine computes the number of standard size pages that can be 00527 aggregated into a single large page and returns the granularity hint 00528 for that size large page. 00529 00530 Arguments: 00531 00532 PointerPte - Supplies the PTE pointer for the starting virtual address 00533 of the mapping. 00534 Pfn - Supplies the starting page frame number of the memory to be 00535 mapped. 00536 Pages - Supplies the number of pages to map. 00537 00538 GranularityHint - Receives the granularity hint for the large page used 00539 to aggregate the standard pages. 00540 00541 Return Value: 00542 00543 The number of pages that can be aggregated together. 00544 00545 Environment: 00546 00547 --*/ 00548 { 00549 00550 ULONG MaxVirtualAlignment; 00551 ULONG MaxPhysicalAlignment; 00552 ULONG MaxPageAlignment; 00553 ULONG MaxAlignment; 00554 00555 // 00556 // Determine the largest page that will map a maximum of Pages. 00557 // The largest page must be both virtually and physically aligned 00558 // to the large page size boundary. 00559 // Determine the largest common alignment for the virtual and 00560 // physical addresses, factor in Pages, and then match to the 00561 // largest page size possible via the granularity hints. 00562 // 00563 00564 MaxVirtualAlignment = MaximumAlignment((ULONG) 00565 MiGetVirtualAddressMappedByPte( PointerPte ) ); 00566 MaxPhysicalAlignment = MaximumAlignment( (ULONG)(Pfn << PAGE_SHIFT) ); 00567 00568 MaxPageAlignment = (ULONG)(Pages << PAGE_SHIFT); 00569 00570 #ifdef AGGREGATE_DBG 00571 00572 DbgPrint( "MM: Aggregate MaxVirtualAlign = %x\n", MaxVirtualAlignment ); 00573 DbgPrint( "MM: Aggregate MaxPhysicalAlign = %x\n", MaxPhysicalAlignment ); 00574 DbgPrint( "MM: Aggregate MaxPageAlign = %x\n", MaxPageAlignment ); 00575 00576 #endif //AGGREGATE_DBG 00577 // 00578 // Maximum alignment is the minimum of the virtual and physical alignments. 00579 // 00580 00581 MaxAlignment = (MaxVirtualAlignment > MaxPhysicalAlignment) ? 00582 MaxPhysicalAlignment : MaxVirtualAlignment; 00583 MaxAlignment = (MaxAlignment > MaxPageAlignment) ? 00584 MaxPageAlignment : MaxAlignment; 00585 00586 // 00587 // Convert MaxAlignment to granularity hint value 00588 // 00589 00590 if( (MaxAlignment & (GH3_PAGE_SIZE - 1)) == 0 ){ 00591 00592 *GranularityHint = GH3; 00593 00594 } else if( (MaxAlignment & (GH2_PAGE_SIZE - 1)) == 0 ){ 00595 00596 *GranularityHint = GH2; 00597 00598 } else if( (MaxAlignment & (GH1_PAGE_SIZE - 1)) == 0 ){ 00599 00600 *GranularityHint = GH1; 00601 00602 } else if( (MaxAlignment & (PAGE_SIZE - 1)) == 0 ){ 00603 00604 *GranularityHint = GH0; 00605 00606 } else { 00607 00608 *GranularityHint = GH0; 00609 00610 #if DBG 00611 00612 DbgPrint( "MM: Aggregate Physical pages - not page aligned\n" ); 00613 00614 #endif //DBG 00615 00616 } // end, if then elseif 00617 00618 // 00619 // Return number of pages aggregated. 00620 // 00621 00622 return( MaxAlignment >> PAGE_SHIFT ); 00623 00624 }

Generated on Sat May 15 19:41:09 2004 for test by doxygen 1.3.7