Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1113 lines
32 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. extsect.c
  5. Abstract:
  6. This module contains the routines which implement the
  7. NtExtendSection service.
  8. Author:
  9. Lou Perazzoli (loup) 8-May-1990
  10. Landy Wang (landyw) 02-June-1997
  11. Revision History:
  12. --*/
  13. #include "mi.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE,NtExtendSection)
  16. #pragma alloc_text(PAGE,MmExtendSection)
  17. #endif
  18. extern SIZE_T MmAllocationFragment;
  19. ULONG MiExtendedSubsectionsConvertedToDynamic;
  20. #if DBG
  21. VOID
  22. MiSubsectionConsistent(
  23. IN PSUBSECTION Subsection
  24. )
  25. /*++
  26. Routine Description:
  27. This function checks to ensure the subsection is consistent.
  28. Arguments:
  29. Subsection - Supplies a pointer to the subsection to be checked.
  30. Return Value:
  31. None.
  32. --*/
  33. {
  34. ULONG Sectors;
  35. ULONG FullPtes;
  36. //
  37. // Compare the disk sectors (4K units) to the PTE allocation
  38. //
  39. Sectors = Subsection->NumberOfFullSectors;
  40. if (Subsection->u.SubsectionFlags.SectorEndOffset) {
  41. Sectors += 1;
  42. }
  43. //
  44. // Calculate how many PTEs are needed to map this number of sectors.
  45. //
  46. FullPtes = Sectors >> (PAGE_SHIFT - MM4K_SHIFT);
  47. if (Sectors & ((1 << (PAGE_SHIFT - MM4K_SHIFT)) - 1)) {
  48. FullPtes += 1;
  49. }
  50. if (FullPtes != Subsection->PtesInSubsection) {
  51. DbgPrint("Mm: Subsection inconsistent (%x vs %x)\n",
  52. FullPtes,
  53. Subsection->PtesInSubsection);
  54. DbgBreakPoint();
  55. }
  56. }
  57. #endif
  58. NTSTATUS
  59. NtExtendSection (
  60. IN HANDLE SectionHandle,
  61. IN OUT PLARGE_INTEGER NewSectionSize
  62. )
  63. /*++
  64. Routine Description:
  65. This function extends the size of the specified section. If
  66. the current size of the section is greater than or equal to the
  67. specified section size, the size is not updated.
  68. Arguments:
  69. SectionHandle - Supplies an open handle to a section object.
  70. NewSectionSize - Supplies the new size for the section object.
  71. Return Value:
  72. NTSTATUS.
  73. --*/
  74. {
  75. KPROCESSOR_MODE PreviousMode;
  76. PVOID Section;
  77. NTSTATUS Status;
  78. LARGE_INTEGER CapturedNewSectionSize;
  79. PAGED_CODE();
  80. //
  81. // Check to make sure the new section size is accessible.
  82. //
  83. PreviousMode = KeGetPreviousMode();
  84. if (PreviousMode != KernelMode) {
  85. try {
  86. ProbeForWriteSmallStructure (NewSectionSize,
  87. sizeof(LARGE_INTEGER),
  88. PROBE_ALIGNMENT (LARGE_INTEGER));
  89. CapturedNewSectionSize = *NewSectionSize;
  90. } except (EXCEPTION_EXECUTE_HANDLER) {
  91. //
  92. // If an exception occurs during the probe or capture
  93. // of the initial values, then handle the exception and
  94. // return the exception code as the status value.
  95. //
  96. return GetExceptionCode();
  97. }
  98. }
  99. else {
  100. CapturedNewSectionSize = *NewSectionSize;
  101. }
  102. //
  103. // Reference the section object.
  104. //
  105. Status = ObReferenceObjectByHandle (SectionHandle,
  106. SECTION_EXTEND_SIZE,
  107. MmSectionObjectType,
  108. PreviousMode,
  109. (PVOID *)&Section,
  110. NULL);
  111. if (!NT_SUCCESS(Status)) {
  112. return Status;
  113. }
  114. Status = MmExtendSection (Section, &CapturedNewSectionSize, FALSE);
  115. ObDereferenceObject (Section);
  116. //
  117. // Update the NewSectionSize field.
  118. //
  119. try {
  120. //
  121. // Return the captured section size.
  122. //
  123. *NewSectionSize = CapturedNewSectionSize;
  124. } except (EXCEPTION_EXECUTE_HANDLER) {
  125. NOTHING;
  126. }
  127. return Status;
  128. }
  129. VOID
  130. MiAppendSubsectionChain (
  131. IN PMSUBSECTION LastSubsection,
  132. IN PMSUBSECTION ExtendedSubsectionHead
  133. )
  134. /*++
  135. Routine Description:
  136. This nonpagable wrapper function extends the specified subsection chain.
  137. Arguments:
  138. LastSubsection - Supplies the last subsection in the existing control area.
  139. ExtendedSubsectionHead - Supplies an anchor pointing to the first
  140. subsection in the chain to append.
  141. Return Value:
  142. None.
  143. --*/
  144. {
  145. KIRQL OldIrql;
  146. PMSUBSECTION NewSubsection;
  147. ASSERT (ExtendedSubsectionHead->NextSubsection != NULL);
  148. ASSERT (ExtendedSubsectionHead->u.SubsectionFlags.SectorEndOffset == 0);
  149. LOCK_PFN (OldIrql);
  150. //
  151. // This subsection may be extending a range that is already
  152. // mapped by a VAD(s). There is no way to tell how many VADs
  153. // already map it so if any do, just leave all the new subsections
  154. // marked the as not reclaimable until the control area is deleted.
  155. //
  156. // If however, there is only the system cache reference and no user
  157. // references to this control area, then the subsections can be marked
  158. // as dynamic now. Note other portions of code (currently only prefetch)
  159. // that issue "dereference from this subsection to the end of file"
  160. // are safe because these portions create user sections first and
  161. // so the first check below will be FALSE.
  162. //
  163. if (LastSubsection->ControlArea->NumberOfUserReferences == 0) {
  164. NewSubsection = (PMSUBSECTION) ExtendedSubsectionHead->NextSubsection;
  165. do {
  166. ASSERT (NewSubsection->u.SubsectionFlags.SubsectionStatic == 1);
  167. MI_SNAP_SUB (NewSubsection, 0x1);
  168. NewSubsection->u.SubsectionFlags.SubsectionStatic = 0;
  169. NewSubsection->u2.SubsectionFlags2.SubsectionConverted = 1;
  170. NewSubsection->NumberOfMappedViews = 1;
  171. MiRemoveViewsFromSection (NewSubsection,
  172. NewSubsection->PtesInSubsection);
  173. MiExtendedSubsectionsConvertedToDynamic += 1;
  174. MI_SNAP_SUB (NewSubsection, 0x2);
  175. NewSubsection = (PMSUBSECTION) NewSubsection->NextSubsection;
  176. } while (NewSubsection != NULL);
  177. }
  178. LastSubsection->u.SubsectionFlags.SectorEndOffset = 0;
  179. LastSubsection->NumberOfFullSectors = ExtendedSubsectionHead->NumberOfFullSectors;
  180. //
  181. // A memory barrier is needed to ensure the writes initializing the
  182. // subsection fields are visible prior to linking the subsection into
  183. // the chain. This is because some reads from these fields are done
  184. // lock free for improved performance.
  185. //
  186. KeMemoryBarrier ();
  187. LastSubsection->NextSubsection = ExtendedSubsectionHead->NextSubsection;
  188. UNLOCK_PFN (OldIrql);
  189. }
  190. NTSTATUS
  191. MmExtendSection (
  192. IN PVOID SectionToExtend,
  193. IN OUT PLARGE_INTEGER NewSectionSize,
  194. IN ULONG IgnoreFileSizeChecking
  195. )
  196. /*++
  197. Routine Description:
  198. This function extends the size of the specified section. If
  199. the current size of the section is greater than or equal to the
  200. specified section size, the size is not updated.
  201. Arguments:
  202. Section - Supplies a pointer to a referenced section object.
  203. NewSectionSize - Supplies the new size for the section object.
  204. IgnoreFileSizeChecking - Supplies the value TRUE is file size
  205. checking should be ignored (i.e., it
  206. is being called from a file system which
  207. has already done the checks). FALSE
  208. if the checks still need to be made.
  209. Return Value:
  210. NTSTATUS.
  211. --*/
  212. {
  213. PMMPTE ProtoPtes;
  214. MMPTE TempPte;
  215. PCONTROL_AREA ControlArea;
  216. PSEGMENT Segment;
  217. PSECTION Section;
  218. PSUBSECTION LastSubsection;
  219. PSUBSECTION Subsection;
  220. PMSUBSECTION ExtendedSubsection;
  221. MSUBSECTION ExtendedSubsectionHead;
  222. PMSUBSECTION LastExtendedSubsection;
  223. ULONG RequiredPtes;
  224. ULONG NumberOfPtes;
  225. ULONG PtesUsed;
  226. ULONG UnusedPtes;
  227. ULONG AllocationSize;
  228. ULONG RunningSize;
  229. ULONG NewSubsectionCount;
  230. UINT64 EndOfFile;
  231. UINT64 NumberOfPtesForEntireFile;
  232. NTSTATUS Status;
  233. LARGE_INTEGER NumberOf4KsForEntireFile;
  234. LARGE_INTEGER Starting4K;
  235. LARGE_INTEGER NextSubsection4KStart;
  236. LARGE_INTEGER Last4KChunk;
  237. ULONG PartialSize;
  238. SIZE_T AllocationFragment;
  239. PKTHREAD CurrentThread;
  240. PAGED_CODE();
  241. Section = (PSECTION)SectionToExtend;
  242. //
  243. // Make sure the section is really extendable - physical and
  244. // image sections are not.
  245. //
  246. Segment = Section->Segment;
  247. ControlArea = Segment->ControlArea;
  248. if ((ControlArea->u.Flags.PhysicalMemory || ControlArea->u.Flags.Image) ||
  249. (ControlArea->FilePointer == NULL)) {
  250. return STATUS_SECTION_NOT_EXTENDED;
  251. }
  252. //
  253. // Acquire the section extension mutex, this blocks other threads from
  254. // updating the size at the same time.
  255. //
  256. CurrentThread = KeGetCurrentThread ();
  257. KeEnterCriticalRegionThread (CurrentThread);
  258. ExAcquireResourceExclusiveLite (&MmSectionExtendResource, TRUE);
  259. //
  260. // Calculate the number of prototype PTE chunks to build for this section.
  261. // A subsection is also allocated for each chunk as all the prototype PTEs
  262. // in any given chunk are initially encoded to point at the same subsection.
  263. //
  264. // The maximum total section size is 16PB (2^54). This is because the
  265. // StartingSector4132 field in each subsection, ie: 2^42-1 bits of file
  266. // offset where the offset is in 4K (not pagesize) units. Thus, a
  267. // subsection may describe a *BYTE* file start offset of maximum
  268. // 2^54 - 4K.
  269. //
  270. // Each subsection can span at most 16TB - 64K.
  271. //
  272. // This is because the NumberOfFullSectors and various other fields
  273. // in the subsection are ULONGs.
  274. //
  275. // The last item to notice is that the NumberOfSubsections is currently
  276. // a USHORT in the ControlArea. Note this does not limit us to 64K-1
  277. // subsections because this field is only relied on for images not data.
  278. //
  279. NumberOfPtesForEntireFile = (NewSectionSize->QuadPart + PAGE_SIZE - 1) >> PAGE_SHIFT;
  280. NumberOfPtes = (ULONG)NumberOfPtesForEntireFile;
  281. if (NewSectionSize->QuadPart > MI_MAXIMUM_SECTION_SIZE) {
  282. Status = STATUS_SECTION_TOO_BIG;
  283. goto ReleaseAndReturn;
  284. }
  285. if (NumberOfPtesForEntireFile > (UINT64)((MAXULONG_PTR / sizeof(MMPTE)) - sizeof (SEGMENT))) {
  286. Status = STATUS_SECTION_TOO_BIG;
  287. goto ReleaseAndReturn;
  288. }
  289. if (NumberOfPtesForEntireFile > (UINT64)NewSectionSize->QuadPart) {
  290. Status = STATUS_SECTION_TOO_BIG;
  291. goto ReleaseAndReturn;
  292. }
  293. if (ControlArea->u.Flags.WasPurged == 0) {
  294. if ((UINT64)NewSectionSize->QuadPart <= (UINT64)Section->SizeOfSection.QuadPart) {
  295. *NewSectionSize = Section->SizeOfSection;
  296. goto ReleaseAndReturnSuccess;
  297. }
  298. }
  299. //
  300. // If a file handle was specified, set the allocation size of the file.
  301. //
  302. if (IgnoreFileSizeChecking == FALSE) {
  303. //
  304. // Release the resource so we don't deadlock with the file
  305. // system trying to extend this section at the same time.
  306. //
  307. ExReleaseResourceLite (&MmSectionExtendResource);
  308. //
  309. // Get a different resource to single thread query/set operations.
  310. //
  311. ExAcquireResourceExclusiveLite (&MmSectionExtendSetResource, TRUE);
  312. //
  313. // Query the file size to see if this file really needs extending.
  314. //
  315. // If the specified size is less than the current size, return
  316. // the current size.
  317. //
  318. Status = FsRtlGetFileSize (ControlArea->FilePointer,
  319. (PLARGE_INTEGER)&EndOfFile);
  320. if (!NT_SUCCESS (Status)) {
  321. ExReleaseResourceLite (&MmSectionExtendSetResource);
  322. KeLeaveCriticalRegionThread (CurrentThread);
  323. return Status;
  324. }
  325. if ((UINT64)NewSectionSize->QuadPart > EndOfFile) {
  326. //
  327. // Don't allow section extension unless the section was originally
  328. // created with write access. The check couldn't be done at create
  329. // time without breaking existing binaries, so the caller gets the
  330. // error at this point instead.
  331. //
  332. if (((Section->InitialPageProtection & PAGE_READWRITE) |
  333. (Section->InitialPageProtection & PAGE_EXECUTE_READWRITE)) == 0) {
  334. #if DBG
  335. DbgPrint("Section extension failed %x\n", Section);
  336. #endif
  337. ExReleaseResourceLite (&MmSectionExtendSetResource);
  338. KeLeaveCriticalRegionThread (CurrentThread);
  339. return STATUS_SECTION_NOT_EXTENDED;
  340. }
  341. //
  342. // Current file is smaller, attempt to set a new end of file.
  343. //
  344. EndOfFile = *(PUINT64)NewSectionSize;
  345. Status = FsRtlSetFileSize (ControlArea->FilePointer,
  346. (PLARGE_INTEGER)&EndOfFile);
  347. if (!NT_SUCCESS (Status)) {
  348. ExReleaseResourceLite (&MmSectionExtendSetResource);
  349. KeLeaveCriticalRegionThread (CurrentThread);
  350. return Status;
  351. }
  352. }
  353. if (Segment->ExtendInfo) {
  354. ExAcquireFastMutex (&MmSectionBasedMutex);
  355. if (Segment->ExtendInfo) {
  356. Segment->ExtendInfo->CommittedSize = EndOfFile;
  357. }
  358. ExReleaseFastMutex (&MmSectionBasedMutex);
  359. }
  360. //
  361. // Release the query/set resource and reacquire the extend section
  362. // resource.
  363. //
  364. ExReleaseResourceLite (&MmSectionExtendSetResource);
  365. ExAcquireResourceExclusiveLite (&MmSectionExtendResource, TRUE);
  366. }
  367. //
  368. // Find the last subsection.
  369. //
  370. ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
  371. if (((PMAPPED_FILE_SEGMENT)Segment)->LastSubsectionHint != NULL) {
  372. LastSubsection = (PSUBSECTION) ((PMAPPED_FILE_SEGMENT)Segment)->LastSubsectionHint;
  373. }
  374. else {
  375. if (ControlArea->u.Flags.Rom == 1) {
  376. LastSubsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  377. }
  378. else {
  379. LastSubsection = (PSUBSECTION)(ControlArea + 1);
  380. }
  381. }
  382. while (LastSubsection->NextSubsection != NULL) {
  383. ASSERT (LastSubsection->UnusedPtes == 0);
  384. LastSubsection = LastSubsection->NextSubsection;
  385. }
  386. MI_CHECK_SUBSECTION (LastSubsection);
  387. //
  388. // Does the structure need extending?
  389. //
  390. if (NumberOfPtes <= Segment->TotalNumberOfPtes) {
  391. //
  392. // The segment is already large enough, just update
  393. // the section size and return.
  394. //
  395. Section->SizeOfSection = *NewSectionSize;
  396. if (Segment->SizeOfSegment < (UINT64)NewSectionSize->QuadPart) {
  397. //
  398. // Only update if it is really bigger.
  399. //
  400. Segment->SizeOfSegment = *(PUINT64)NewSectionSize;
  401. Mi4KStartFromSubsection(&Starting4K, LastSubsection);
  402. Last4KChunk.QuadPart = (NewSectionSize->QuadPart >> MM4K_SHIFT) - Starting4K.QuadPart;
  403. ASSERT (Last4KChunk.HighPart == 0);
  404. LastSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  405. LastSubsection->u.SubsectionFlags.SectorEndOffset =
  406. NewSectionSize->LowPart & MM4K_MASK;
  407. MI_CHECK_SUBSECTION (LastSubsection);
  408. }
  409. goto ReleaseAndReturnSuccess;
  410. }
  411. //
  412. // Add new structures to the section - locate the last subsection
  413. // and add there.
  414. //
  415. RequiredPtes = NumberOfPtes - Segment->TotalNumberOfPtes;
  416. PtesUsed = 0;
  417. if (RequiredPtes < LastSubsection->UnusedPtes) {
  418. //
  419. // There are ample PTEs to extend the section already allocated.
  420. //
  421. PtesUsed = RequiredPtes;
  422. RequiredPtes = 0;
  423. }
  424. else {
  425. PtesUsed = LastSubsection->UnusedPtes;
  426. RequiredPtes -= PtesUsed;
  427. }
  428. LastSubsection->PtesInSubsection += PtesUsed;
  429. LastSubsection->UnusedPtes -= PtesUsed;
  430. Segment->SizeOfSegment += (UINT64)PtesUsed * PAGE_SIZE;
  431. Segment->TotalNumberOfPtes += PtesUsed;
  432. if (RequiredPtes == 0) {
  433. //
  434. // There is no extension necessary, update the high VBN.
  435. //
  436. Mi4KStartFromSubsection(&Starting4K, LastSubsection);
  437. Last4KChunk.QuadPart = (NewSectionSize->QuadPart >> MM4K_SHIFT) - Starting4K.QuadPart;
  438. ASSERT (Last4KChunk.HighPart == 0);
  439. LastSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  440. LastSubsection->u.SubsectionFlags.SectorEndOffset =
  441. NewSectionSize->LowPart & MM4K_MASK;
  442. MI_CHECK_SUBSECTION (LastSubsection);
  443. }
  444. else {
  445. //
  446. // An extension is required. Allocate the subsection and prototype
  447. // PTEs now.
  448. //
  449. NewSubsectionCount = 0;
  450. NumberOf4KsForEntireFile.QuadPart = Segment->SizeOfSegment >> MM4K_SHIFT;
  451. AllocationSize = (ULONG) ROUND_TO_PAGES (RequiredPtes * sizeof(MMPTE));
  452. AllocationFragment = MmAllocationFragment;
  453. RunningSize = 0;
  454. ExtendedSubsectionHead = *(PMSUBSECTION)LastSubsection;
  455. LastExtendedSubsection = &ExtendedSubsectionHead;
  456. ASSERT (LastExtendedSubsection->NextSubsection == NULL);
  457. //
  458. // Initializing NextSubsection4KStart is not needed for correctness
  459. // but without it the compiler cannot compile this code
  460. // W4 to check for use of uninitialized variables.
  461. //
  462. NextSubsection4KStart.QuadPart = 0;
  463. do {
  464. PartialSize = AllocationSize - RunningSize;
  465. //
  466. // Bound the size of each prototype PTE allocation so both :
  467. // 1. it can succeed even in cases where the pool is fragmented.
  468. // 2. later on last control area dereference, each subsection
  469. // is converted to dynamic and can be pruned/recreated
  470. // individually without losing (or requiring) contiguous pool.
  471. //
  472. if (PartialSize > AllocationFragment) {
  473. PartialSize = (ULONG) AllocationFragment;
  474. }
  475. //
  476. // Allocate an extended subsection.
  477. //
  478. ExtendedSubsection = (PMSUBSECTION) ExAllocatePoolWithTag (NonPagedPool,
  479. sizeof(MSUBSECTION),
  480. 'dSmM');
  481. if (ExtendedSubsection == NULL) {
  482. goto ExtensionFailed;
  483. }
  484. ExtendedSubsection->NextSubsection = NULL;
  485. LastExtendedSubsection->NextSubsection = (PSUBSECTION) ExtendedSubsection;
  486. ProtoPtes = (PMMPTE)ExAllocatePoolWithTag (PagedPool,
  487. PartialSize,
  488. MMSECT);
  489. ExtendedSubsection->SubsectionBase = ProtoPtes;
  490. if (ProtoPtes == NULL) {
  491. goto ExtensionFailed;
  492. }
  493. ASSERT (ControlArea->FilePointer != NULL);
  494. ExtendedSubsection->u.LongFlags = 0;
  495. ExtendedSubsection->ControlArea = ControlArea;
  496. ExtendedSubsection->PtesInSubsection = PartialSize / sizeof(MMPTE);
  497. ExtendedSubsection->UnusedPtes = 0;
  498. RunningSize += PartialSize;
  499. if (RunningSize > (RequiredPtes * sizeof(MMPTE))) {
  500. UnusedPtes = RunningSize / sizeof(MMPTE) - RequiredPtes;
  501. ExtendedSubsection->PtesInSubsection -= UnusedPtes;
  502. ExtendedSubsection->UnusedPtes = UnusedPtes;
  503. }
  504. //
  505. // Fill in the prototype PTEs for this subsection.
  506. //
  507. // Set all the PTEs to the initial execute-read-write protection.
  508. // The section will control access to these and the segment
  509. // must provide a method to allow other users to map the file
  510. // for various protections.
  511. //
  512. TempPte.u.Long = MiGetSubsectionAddressForPte (ExtendedSubsection);
  513. TempPte.u.Soft.Prototype = 1;
  514. TempPte.u.Soft.Protection = Segment->SegmentPteTemplate.u.Soft.Protection;
  515. MiFillMemoryPte (ProtoPtes, PartialSize, TempPte.u.Long);
  516. ExtendedSubsection->u.SubsectionFlags.Protection =
  517. (unsigned) TempPte.u.Soft.Protection;
  518. ExtendedSubsection->DereferenceList.Flink = NULL;
  519. ExtendedSubsection->DereferenceList.Blink = NULL;
  520. ExtendedSubsection->NumberOfMappedViews = 0;
  521. ExtendedSubsection->u2.LongFlags2 = 0;
  522. //
  523. // This subsection may be extending a range that is already
  524. // mapped by a VAD(s). There is no way to tell how many VADs
  525. // already map it so just mark the entire subsection as not
  526. // reclaimable until the control area is deleted.
  527. //
  528. // This also saves other portions of code that issue "dereference
  529. // from this subsection to the end of file" as these subsections are
  530. // marked as static not dynamic (at least until segment dereference
  531. // time).
  532. //
  533. // When this chain is appended to the control area at the end of
  534. // this routine an attempt is made to convert the subsection chain
  535. // to dynamic if no user mapped views are active.
  536. //
  537. ExtendedSubsection->u.SubsectionFlags.SubsectionStatic = 1;
  538. //
  539. // Adjust the previous subsection to account for the new length.
  540. // Note that since the next allocation in this loop may fail,
  541. // the very first previous subsection changes are not rippled
  542. // to the chained subsection until the loop completes successfully.
  543. //
  544. if (LastExtendedSubsection == &ExtendedSubsectionHead) {
  545. Mi4KStartFromSubsection (&Starting4K, LastExtendedSubsection);
  546. Last4KChunk.QuadPart = NumberOf4KsForEntireFile.QuadPart -
  547. Starting4K.QuadPart;
  548. if (LastExtendedSubsection->u.SubsectionFlags.SectorEndOffset) {
  549. Last4KChunk.QuadPart += 1;
  550. }
  551. ASSERT (Last4KChunk.HighPart == 0);
  552. LastExtendedSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  553. LastExtendedSubsection->u.SubsectionFlags.SectorEndOffset = 0;
  554. //
  555. // If the number of sectors doesn't completely fill the PTEs
  556. // (only possible when the page size is not MM4K), then
  557. // fill it now.
  558. //
  559. if (LastExtendedSubsection->NumberOfFullSectors & ((1 << (PAGE_SHIFT - MM4K_SHIFT)) - 1)) {
  560. LastExtendedSubsection->NumberOfFullSectors += 1;
  561. }
  562. MI_CHECK_SUBSECTION (LastExtendedSubsection);
  563. Starting4K.QuadPart += LastExtendedSubsection->NumberOfFullSectors;
  564. NextSubsection4KStart.QuadPart = Starting4K.QuadPart;
  565. }
  566. else {
  567. NextSubsection4KStart.QuadPart += LastExtendedSubsection->NumberOfFullSectors;
  568. }
  569. //
  570. // Initialize the newly allocated subsection.
  571. //
  572. Mi4KStartForSubsection (&NextSubsection4KStart, ExtendedSubsection);
  573. if (RunningSize < AllocationSize) {
  574. //
  575. // Not the final subsection so all quantities are full pages.
  576. //
  577. ExtendedSubsection->NumberOfFullSectors =
  578. (PartialSize / sizeof (MMPTE)) << (PAGE_SHIFT - MM4K_SHIFT);
  579. ExtendedSubsection->u.SubsectionFlags.SectorEndOffset = 0;
  580. }
  581. else {
  582. //
  583. // The final subsection so quantities are not always full pages.
  584. //
  585. Last4KChunk.QuadPart =
  586. (NewSectionSize->QuadPart >> MM4K_SHIFT) - NextSubsection4KStart.QuadPart;
  587. ASSERT (Last4KChunk.HighPart == 0);
  588. ExtendedSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  589. ExtendedSubsection->u.SubsectionFlags.SectorEndOffset =
  590. NewSectionSize->LowPart & MM4K_MASK;
  591. }
  592. MI_CHECK_SUBSECTION (ExtendedSubsection);
  593. LastExtendedSubsection = ExtendedSubsection;
  594. NewSubsectionCount += 1;
  595. } while (RunningSize < AllocationSize);
  596. ASSERT (ControlArea->DereferenceList.Flink == NULL);
  597. //
  598. // Link the newly created subsection chain into the existing list.
  599. // Note this any adjustments (NumberOfFullSectors, etc) made to
  600. // the temp copy of the last subsection in the existing control
  601. // area must be *CAREFULLY* copied to the real copy in the chain (the
  602. // entire structure cannot just be block copied) as other fields
  603. // in the real copy (ie: NumberOfMappedViews may be changed in
  604. // parallel by another thread).
  605. //
  606. if (ControlArea->NumberOfUserReferences == 0) {
  607. ASSERT (IgnoreFileSizeChecking == TRUE);
  608. }
  609. Segment->TotalNumberOfPtes += RequiredPtes;
  610. MiAppendSubsectionChain ((PMSUBSECTION)LastSubsection,
  611. &ExtendedSubsectionHead);
  612. ControlArea->NumberOfSubsections =
  613. (USHORT)(ControlArea->NumberOfSubsections + NewSubsectionCount);
  614. if (LastExtendedSubsection != &ExtendedSubsectionHead) {
  615. ((PMAPPED_FILE_SEGMENT)Segment)->LastSubsectionHint =
  616. LastExtendedSubsection;
  617. }
  618. }
  619. Segment->SizeOfSegment = *(PUINT64)NewSectionSize;
  620. Section->SizeOfSection = *NewSectionSize;
  621. ReleaseAndReturnSuccess:
  622. Status = STATUS_SUCCESS;
  623. ReleaseAndReturn:
  624. ExReleaseResourceLite (&MmSectionExtendResource);
  625. KeLeaveCriticalRegionThread (CurrentThread);
  626. return Status;
  627. ExtensionFailed:
  628. //
  629. // Required pool to extend the section could not be allocated.
  630. // Reset the subsection and control area fields to their
  631. // original values.
  632. //
  633. LastSubsection->PtesInSubsection -= PtesUsed;
  634. LastSubsection->UnusedPtes += PtesUsed;
  635. Segment->TotalNumberOfPtes -= PtesUsed;
  636. Segment->SizeOfSegment -= ((UINT64)PtesUsed * PAGE_SIZE);
  637. //
  638. // Free all the previous allocations and return an error.
  639. //
  640. LastSubsection = ExtendedSubsectionHead.NextSubsection;
  641. while (LastSubsection != NULL) {
  642. Subsection = LastSubsection->NextSubsection;
  643. if (LastSubsection->SubsectionBase != NULL) {
  644. ExFreePool (LastSubsection->SubsectionBase);
  645. }
  646. ExFreePool (LastSubsection);
  647. LastSubsection = Subsection;
  648. }
  649. Status = STATUS_INSUFFICIENT_RESOURCES;
  650. goto ReleaseAndReturn;
  651. }
  652. PMMPTE
  653. FASTCALL
  654. MiGetProtoPteAddressExtended (
  655. IN PMMVAD Vad,
  656. IN ULONG_PTR Vpn
  657. )
  658. /*++
  659. Routine Description:
  660. This function calculates the address of the prototype PTE
  661. for the corresponding virtual address.
  662. Arguments:
  663. Vad - Supplies a pointer to the virtual address desciptor which
  664. encompasses the virtual address.
  665. Vpn - Supplies the virtual page number to locate a prototype PTE for.
  666. Return Value:
  667. The corresponding prototype PTE address.
  668. --*/
  669. {
  670. PSUBSECTION Subsection;
  671. PCONTROL_AREA ControlArea;
  672. ULONG PteOffset;
  673. ControlArea = Vad->ControlArea;
  674. if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) {
  675. Subsection = (PSUBSECTION)(ControlArea + 1);
  676. }
  677. else {
  678. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  679. }
  680. //
  681. // Locate the subsection which contains the First Prototype PTE
  682. // for this VAD.
  683. //
  684. while ((Subsection->SubsectionBase == NULL) ||
  685. (Vad->FirstPrototypePte < Subsection->SubsectionBase) ||
  686. (Vad->FirstPrototypePte >=
  687. &Subsection->SubsectionBase[Subsection->PtesInSubsection])) {
  688. //
  689. // Get the next subsection.
  690. //
  691. Subsection = Subsection->NextSubsection;
  692. if (Subsection == NULL) {
  693. return NULL;
  694. }
  695. }
  696. ASSERT (Subsection->SubsectionBase != NULL);
  697. //
  698. // How many PTEs beyond this subsection must we go?
  699. //
  700. PteOffset = (ULONG) (((Vpn - Vad->StartingVpn) +
  701. (ULONG)(Vad->FirstPrototypePte - Subsection->SubsectionBase)) -
  702. Subsection->PtesInSubsection);
  703. ASSERT (PteOffset < 0xF0000000);
  704. PteOffset += Subsection->PtesInSubsection;
  705. //
  706. // Locate the subsection which contains the prototype PTEs.
  707. //
  708. while (PteOffset >= Subsection->PtesInSubsection) {
  709. PteOffset -= Subsection->PtesInSubsection;
  710. Subsection = Subsection->NextSubsection;
  711. if (Subsection == NULL) {
  712. return NULL;
  713. }
  714. }
  715. //
  716. // The PTEs are in this subsection.
  717. //
  718. ASSERT (Subsection->SubsectionBase != NULL);
  719. ASSERT (PteOffset < Subsection->PtesInSubsection);
  720. return &Subsection->SubsectionBase[PteOffset];
  721. }
  722. PSUBSECTION
  723. FASTCALL
  724. MiLocateSubsection (
  725. IN PMMVAD Vad,
  726. IN ULONG_PTR Vpn
  727. )
  728. /*++
  729. Routine Description:
  730. This function calculates the address of the subsection
  731. for the corresponding virtual address.
  732. This function only works for mapped files NOT mapped images.
  733. Arguments:
  734. Vad - Supplies a pointer to the virtual address desciptor which
  735. encompasses the virtual address.
  736. Vpn - Supplies the virtual page number to locate a prototype PTE for.
  737. Return Value:
  738. The corresponding prototype subsection.
  739. --*/
  740. {
  741. PSUBSECTION Subsection;
  742. PCONTROL_AREA ControlArea;
  743. ULONG PteOffset;
  744. ControlArea = Vad->ControlArea;
  745. if (ControlArea->u.Flags.Rom == 0) {
  746. Subsection = (PSUBSECTION)(ControlArea + 1);
  747. }
  748. else {
  749. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  750. }
  751. if (ControlArea->u.Flags.Image) {
  752. if (ControlArea->u.Flags.GlobalOnlyPerSession == 1) {
  753. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  754. }
  755. //
  756. // There is only one subsection, don't look any further.
  757. //
  758. return Subsection;
  759. }
  760. ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
  761. //
  762. // Locate the subsection which contains the First Prototype PTE
  763. // for this VAD. Note all the SubsectionBase values must be non-NULL
  764. // for the subsection range spanned by the VAD because the VAD still
  765. // exists. Carefully skip over preceding subsections not mapped by
  766. // this VAD because if no other VADs map them either, their base
  767. // can be NULL.
  768. //
  769. while ((Subsection->SubsectionBase == NULL) ||
  770. (Vad->FirstPrototypePte < Subsection->SubsectionBase) ||
  771. (Vad->FirstPrototypePte >=
  772. &Subsection->SubsectionBase[Subsection->PtesInSubsection])) {
  773. //
  774. // Get the next subsection.
  775. //
  776. Subsection = Subsection->NextSubsection;
  777. if (Subsection == NULL) {
  778. return NULL;
  779. }
  780. }
  781. ASSERT (Subsection->SubsectionBase != NULL);
  782. //
  783. // How many PTEs beyond this subsection must we go?
  784. //
  785. PteOffset = (ULONG)((Vpn - Vad->StartingVpn) +
  786. (ULONG)(Vad->FirstPrototypePte - Subsection->SubsectionBase));
  787. ASSERT (PteOffset < 0xF0000000);
  788. //
  789. // Locate the subsection which contains the prototype PTEs.
  790. //
  791. while (PteOffset >= Subsection->PtesInSubsection) {
  792. PteOffset -= Subsection->PtesInSubsection;
  793. Subsection = Subsection->NextSubsection;
  794. if (Subsection == NULL) {
  795. return NULL;
  796. }
  797. ASSERT (Subsection->SubsectionBase != NULL);
  798. }
  799. //
  800. // The PTEs are in this subsection.
  801. //
  802. ASSERT (Subsection->SubsectionBase != NULL);
  803. return Subsection;
  804. }