Leaked source code of windows server 2003
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.

880 lines
24 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. vadtree.c
  5. Abstract:
  6. This module contains the routine to manipulate the virtual address
  7. descriptor tree.
  8. Author:
  9. Lou Perazzoli (loup) 19-May-1989
  10. Landy Wang (landyw) 02-June-1997
  11. Environment:
  12. Kernel mode only, working set mutex held, APCs disabled.
  13. Revision History:
  14. --*/
  15. #include "mi.h"
  16. VOID
  17. VadTreeWalk (
  18. VOID
  19. );
  20. ULONG
  21. FASTCALL
  22. MiVadTreeWalk (
  23. IN PMMVAD Vad,
  24. IN PFILE_OBJECT **FileList
  25. );
  26. #ifdef ALLOC_PRAGMA
  27. #pragma alloc_text(PAGE,MiInsertVad)
  28. #pragma alloc_text(PAGE,MiRemoveVad)
  29. #pragma alloc_text(PAGE,MiFindEmptyAddressRange)
  30. #pragma alloc_text(PAGE, MmPerfVadTreeWalk)
  31. #pragma alloc_text(PAGE, MiVadTreeWalk)
  32. #if DBG
  33. #pragma alloc_text(PAGE,VadTreeWalk)
  34. #endif
  35. #endif
  36. NTSTATUS
  37. MiInsertVad (
  38. IN PMMVAD Vad
  39. )
  40. /*++
  41. Routine Description:
  42. This function inserts a virtual address descriptor into the tree and
  43. reorders the splay tree as appropriate.
  44. Arguments:
  45. Vad - Supplies a pointer to a virtual address descriptor.
  46. Return Value:
  47. NTSTATUS.
  48. --*/
  49. {
  50. ULONG StartBit;
  51. ULONG EndBit;
  52. PMM_AVL_TABLE Root;
  53. PEPROCESS CurrentProcess;
  54. SIZE_T RealCharge;
  55. SIZE_T PageCharge;
  56. SIZE_T PagesReallyCharged;
  57. ULONG FirstPage;
  58. ULONG LastPage;
  59. SIZE_T PagedPoolCharge;
  60. LOGICAL ChargedJobCommit;
  61. NTSTATUS Status;
  62. RTL_BITMAP VadBitMap;
  63. #if (_MI_PAGING_LEVELS >= 3)
  64. ULONG FirstPdPage;
  65. ULONG LastPdPage;
  66. #endif
  67. #if (_MI_PAGING_LEVELS >= 4)
  68. ULONG FirstPpPage;
  69. ULONG LastPpPage;
  70. #endif
  71. ASSERT (Vad->EndingVpn >= Vad->StartingVpn);
  72. CurrentProcess = PsGetCurrentProcess();
  73. //
  74. // Commit charge of MAX_COMMIT means don't charge quota.
  75. //
  76. if (Vad->u.VadFlags.CommitCharge != MM_MAX_COMMIT) {
  77. PageCharge = 0;
  78. PagedPoolCharge = 0;
  79. ChargedJobCommit = FALSE;
  80. //
  81. // Charge quota for the nonpaged pool for the VAD. This is
  82. // done here rather than by using ExAllocatePoolWithQuota
  83. // so the process object is not referenced by the quota charge.
  84. //
  85. Status = PsChargeProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMVAD));
  86. if (!NT_SUCCESS(Status)) {
  87. return STATUS_COMMITMENT_LIMIT;
  88. }
  89. //
  90. // Charge quota for the prototype PTEs if this is a mapped view.
  91. //
  92. if ((Vad->u.VadFlags.PrivateMemory == 0) &&
  93. (Vad->ControlArea != NULL)) {
  94. PagedPoolCharge =
  95. (Vad->EndingVpn - Vad->StartingVpn + 1) << PTE_SHIFT;
  96. Status = PsChargeProcessPagedPoolQuota (CurrentProcess,
  97. PagedPoolCharge);
  98. if (!NT_SUCCESS(Status)) {
  99. PagedPoolCharge = 0;
  100. RealCharge = 0;
  101. goto Failed;
  102. }
  103. }
  104. //
  105. // Add in the charge for page table pages.
  106. //
  107. FirstPage = MiGetPdeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
  108. LastPage = MiGetPdeIndex (MI_VPN_TO_VA (Vad->EndingVpn));
  109. while (FirstPage <= LastPage) {
  110. if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageTables,
  111. FirstPage)) {
  112. PageCharge += 1;
  113. }
  114. FirstPage += 1;
  115. }
  116. #if (_MI_PAGING_LEVELS >= 4)
  117. //
  118. // Add in the charge for page directory parent pages.
  119. //
  120. FirstPpPage = MiGetPxeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
  121. LastPpPage = MiGetPxeIndex (MI_VPN_TO_VA (Vad->EndingVpn));
  122. while (FirstPpPage <= LastPpPage) {
  123. if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectoryParents,
  124. FirstPpPage)) {
  125. PageCharge += 1;
  126. }
  127. FirstPpPage += 1;
  128. }
  129. #endif
  130. #if (_MI_PAGING_LEVELS >= 3)
  131. //
  132. // Add in the charge for page directory pages.
  133. //
  134. FirstPdPage = MiGetPpeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
  135. LastPdPage = MiGetPpeIndex (MI_VPN_TO_VA (Vad->EndingVpn));
  136. while (FirstPdPage <= LastPdPage) {
  137. if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectories,
  138. FirstPdPage)) {
  139. PageCharge += 1;
  140. }
  141. FirstPdPage += 1;
  142. }
  143. #endif
  144. RealCharge = Vad->u.VadFlags.CommitCharge + PageCharge;
  145. if (RealCharge != 0) {
  146. Status = PsChargeProcessPageFileQuota (CurrentProcess, RealCharge);
  147. if (!NT_SUCCESS (Status)) {
  148. RealCharge = 0;
  149. goto Failed;
  150. }
  151. if (CurrentProcess->CommitChargeLimit) {
  152. if (CurrentProcess->CommitCharge + RealCharge > CurrentProcess->CommitChargeLimit) {
  153. if (CurrentProcess->Job) {
  154. PsReportProcessMemoryLimitViolation ();
  155. }
  156. goto Failed;
  157. }
  158. }
  159. if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
  160. if (PsChangeJobMemoryUsage(PS_JOB_STATUS_REPORT_COMMIT_CHANGES, RealCharge) == FALSE) {
  161. goto Failed;
  162. }
  163. ChargedJobCommit = TRUE;
  164. }
  165. if (MiChargeCommitment (RealCharge, CurrentProcess) == FALSE) {
  166. goto Failed;
  167. }
  168. CurrentProcess->CommitCharge += RealCharge;
  169. if (CurrentProcess->CommitCharge > CurrentProcess->CommitChargePeak) {
  170. CurrentProcess->CommitChargePeak = CurrentProcess->CommitCharge;
  171. }
  172. MI_INCREMENT_TOTAL_PROCESS_COMMIT (RealCharge);
  173. ASSERT (RealCharge == Vad->u.VadFlags.CommitCharge + PageCharge);
  174. MM_TRACK_COMMIT (MM_DBG_COMMIT_INSERT_VAD, Vad->u.VadFlags.CommitCharge);
  175. MM_TRACK_COMMIT (MM_DBG_COMMIT_INSERT_VAD_PT, PageCharge);
  176. }
  177. if (PageCharge != 0) {
  178. //
  179. // Since the commitment was successful, charge the page
  180. // table pages.
  181. //
  182. PagesReallyCharged = 0;
  183. FirstPage = MiGetPdeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
  184. while (FirstPage <= LastPage) {
  185. if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageTables,
  186. FirstPage)) {
  187. MI_SET_BIT (MmWorkingSetList->CommittedPageTables,
  188. FirstPage);
  189. MmWorkingSetList->NumberOfCommittedPageTables += 1;
  190. ASSERT32 (MmWorkingSetList->NumberOfCommittedPageTables <
  191. PD_PER_SYSTEM * PDE_PER_PAGE);
  192. PagesReallyCharged += 1;
  193. }
  194. FirstPage += 1;
  195. }
  196. #if (_MI_PAGING_LEVELS >= 3)
  197. //
  198. // Charge the page directory pages.
  199. //
  200. FirstPdPage = MiGetPpeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
  201. while (FirstPdPage <= LastPdPage) {
  202. if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectories,
  203. FirstPdPage)) {
  204. MI_SET_BIT (MmWorkingSetList->CommittedPageDirectories,
  205. FirstPdPage);
  206. MmWorkingSetList->NumberOfCommittedPageDirectories += 1;
  207. #if (_MI_PAGING_LEVELS == 3)
  208. ASSERT (MmWorkingSetList->NumberOfCommittedPageDirectories <
  209. PDE_PER_PAGE);
  210. #endif
  211. PagesReallyCharged += 1;
  212. }
  213. FirstPdPage += 1;
  214. }
  215. #endif
  216. #if (_MI_PAGING_LEVELS >= 4)
  217. //
  218. // Charge the page directory parent pages.
  219. //
  220. FirstPpPage = MiGetPxeIndex (MI_VPN_TO_VA (Vad->StartingVpn));
  221. while (FirstPpPage <= LastPpPage) {
  222. if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageDirectoryParents,
  223. FirstPpPage)) {
  224. MI_SET_BIT (MmWorkingSetList->CommittedPageDirectoryParents,
  225. FirstPpPage);
  226. MmWorkingSetList->NumberOfCommittedPageDirectoryParents += 1;
  227. ASSERT (MmWorkingSetList->NumberOfCommittedPageDirectoryParents <
  228. PDE_PER_PAGE);
  229. PagesReallyCharged += 1;
  230. }
  231. FirstPpPage += 1;
  232. }
  233. #endif
  234. ASSERT (PageCharge == PagesReallyCharged);
  235. }
  236. }
  237. Root = &CurrentProcess->VadRoot;
  238. //
  239. // Set the relevant fields in the Vad bitmap.
  240. //
  241. StartBit = (ULONG)(((ULONG_PTR) MI_64K_ALIGN (MI_VPN_TO_VA (Vad->StartingVpn))) / X64K);
  242. EndBit = (ULONG) (((ULONG_PTR) MI_64K_ALIGN (MI_VPN_TO_VA (Vad->EndingVpn))) / X64K);
  243. //
  244. // Initialize the bitmap inline for speed.
  245. //
  246. VadBitMap.SizeOfBitMap = MiLastVadBit + 1;
  247. VadBitMap.Buffer = VAD_BITMAP_SPACE;
  248. //
  249. // Note VADs like the PEB & TEB start on page (not 64K) boundaries so
  250. // for these, the relevant bits may already be set.
  251. //
  252. #if defined (_WIN64) || defined (_X86PAE_)
  253. if (EndBit > MiLastVadBit) {
  254. EndBit = MiLastVadBit;
  255. }
  256. //
  257. // Only the first (PAGE_SIZE*8*64K) of VA space on NT64 is bitmapped.
  258. //
  259. if (StartBit <= MiLastVadBit) {
  260. RtlSetBits (&VadBitMap, StartBit, EndBit - StartBit + 1);
  261. }
  262. #else
  263. RtlSetBits (&VadBitMap, StartBit, EndBit - StartBit + 1);
  264. #endif
  265. if (MmWorkingSetList->VadBitMapHint == StartBit) {
  266. MmWorkingSetList->VadBitMapHint = EndBit + 1;
  267. }
  268. //
  269. // Set the hint field in the process to this Vad.
  270. //
  271. CurrentProcess->VadRoot.NodeHint = Vad;
  272. if (CurrentProcess->VadFreeHint != NULL) {
  273. if (((ULONG)((PMMVAD)CurrentProcess->VadFreeHint)->EndingVpn +
  274. MI_VA_TO_VPN (X64K)) >=
  275. Vad->StartingVpn) {
  276. CurrentProcess->VadFreeHint = Vad;
  277. }
  278. }
  279. MiInsertNode ((PMMADDRESS_NODE)Vad, Root);
  280. return STATUS_SUCCESS;
  281. Failed:
  282. //
  283. // Return any quotas charged thus far.
  284. //
  285. PsReturnProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMVAD));
  286. if (PagedPoolCharge != 0) {
  287. PsReturnProcessPagedPoolQuota (CurrentProcess, PagedPoolCharge);
  288. }
  289. if (RealCharge != 0) {
  290. PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
  291. }
  292. if (ChargedJobCommit == TRUE) {
  293. PsChangeJobMemoryUsage(PS_JOB_STATUS_REPORT_COMMIT_CHANGES, -(SSIZE_T)RealCharge);
  294. }
  295. return STATUS_COMMITMENT_LIMIT;
  296. }
  297. VOID
  298. MiRemoveVad (
  299. IN PMMVAD Vad
  300. )
  301. /*++
  302. Routine Description:
  303. This function removes a virtual address descriptor from the tree and
  304. reorders the splay tree as appropriate. If any quota or commitment
  305. was charged by the VAD (as indicated by the CommitCharge field) it
  306. is released.
  307. Arguments:
  308. Vad - Supplies a pointer to a virtual address descriptor.
  309. Return Value:
  310. The VAD the caller should free to pool. N.B. This may be different
  311. from the VAD passed in - the caller MUST NOT reference the original VAD
  312. after calling this routine !
  313. --*/
  314. {
  315. PMM_AVL_TABLE Root;
  316. PEPROCESS CurrentProcess;
  317. SIZE_T RealCharge;
  318. PLIST_ENTRY Next;
  319. PMMSECURE_ENTRY Entry;
  320. CurrentProcess = PsGetCurrentProcess();
  321. #if defined(_MIALT4K_)
  322. if (((Vad->u.VadFlags.PrivateMemory) && (Vad->u.VadFlags.NoChange == 0))
  323. ||
  324. (Vad->u2.VadFlags2.LongVad == 0)) {
  325. NOTHING;
  326. }
  327. else {
  328. ASSERT ((((PMMVAD_LONG)Vad)->AliasInformation == NULL) || (CurrentProcess->Wow64Process != NULL));
  329. }
  330. #endif
  331. //
  332. // Commit charge of MAX_COMMIT means don't charge quota.
  333. //
  334. if (Vad->u.VadFlags.CommitCharge != MM_MAX_COMMIT) {
  335. //
  336. // Return the quota charge to the process.
  337. //
  338. PsReturnProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMVAD));
  339. if ((Vad->u.VadFlags.PrivateMemory == 0) &&
  340. (Vad->ControlArea != NULL)) {
  341. PsReturnProcessPagedPoolQuota (CurrentProcess,
  342. (Vad->EndingVpn - Vad->StartingVpn + 1) << PTE_SHIFT);
  343. }
  344. RealCharge = Vad->u.VadFlags.CommitCharge;
  345. if (RealCharge != 0) {
  346. PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
  347. if ((Vad->u.VadFlags.PrivateMemory == 0) &&
  348. (Vad->ControlArea != NULL)) {
  349. #if 0 //commented out so page file quota is meaningful.
  350. if (Vad->ControlArea->FilePointer == NULL) {
  351. //
  352. // Don't release commitment for the page file space
  353. // occupied by a page file section. This will be charged
  354. // as the shared memory is committed.
  355. //
  356. RealCharge -= BYTES_TO_PAGES ((ULONG)Vad->EndingVa -
  357. (ULONG)Vad->StartingVa);
  358. }
  359. #endif
  360. }
  361. MiReturnCommitment (RealCharge);
  362. MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_VAD, RealCharge);
  363. if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
  364. PsChangeJobMemoryUsage(PS_JOB_STATUS_REPORT_COMMIT_CHANGES, -(SSIZE_T)RealCharge);
  365. }
  366. CurrentProcess->CommitCharge -= RealCharge;
  367. MI_INCREMENT_TOTAL_PROCESS_COMMIT (0 - RealCharge);
  368. }
  369. }
  370. if (Vad == CurrentProcess->VadFreeHint) {
  371. CurrentProcess->VadFreeHint = MiGetPreviousVad (Vad);
  372. }
  373. Root = &CurrentProcess->VadRoot;
  374. ASSERT (Root->NumberGenericTableElements >= 1);
  375. if (Vad->u.VadFlags.NoChange) {
  376. if (Vad->u2.VadFlags2.MultipleSecured) {
  377. //
  378. // Free the oustanding pool allocations.
  379. //
  380. Next = ((PMMVAD_LONG) Vad)->u3.List.Flink;
  381. do {
  382. Entry = CONTAINING_RECORD( Next,
  383. MMSECURE_ENTRY,
  384. List);
  385. Next = Entry->List.Flink;
  386. ExFreePool (Entry);
  387. } while (Next != &((PMMVAD_LONG)Vad)->u3.List);
  388. }
  389. }
  390. MiRemoveNode ((PMMADDRESS_NODE)Vad, Root);
  391. //
  392. // If the hint points at the removed Vad, change the hint.
  393. //
  394. if (Root->NodeHint == Vad) {
  395. Root->NodeHint = Root->BalancedRoot.RightChild;
  396. if(Root->NumberGenericTableElements == 0) {
  397. Root->NodeHint = NULL;
  398. }
  399. }
  400. return;
  401. }
  402. NTSTATUS
  403. MiFindEmptyAddressRange (
  404. IN SIZE_T SizeOfRange,
  405. IN ULONG_PTR Alignment,
  406. IN ULONG QuickCheck,
  407. IN PVOID *Base
  408. )
  409. /*++
  410. Routine Description:
  411. The function examines the virtual address descriptors to locate
  412. an unused range of the specified size and returns the starting
  413. address of the range.
  414. Arguments:
  415. SizeOfRange - Supplies the size in bytes of the range to locate.
  416. Alignment - Supplies the alignment for the address. Must be
  417. a power of 2 and greater than the page_size.
  418. QuickCheck - Supplies a zero if a quick check for free memory
  419. after the VadFreeHint exists, non-zero if checking
  420. should start at the lowest address.
  421. Base - Receives the starting address of a suitable range on success.
  422. Return Value:
  423. NTSTATUS.
  424. --*/
  425. {
  426. ULONG FirstBitValue;
  427. ULONG StartPosition;
  428. ULONG BitsNeeded;
  429. PMMVAD NextVad;
  430. PMMVAD FreeHint;
  431. PEPROCESS CurrentProcess;
  432. PVOID StartingVa;
  433. PVOID EndingVa;
  434. NTSTATUS Status;
  435. RTL_BITMAP VadBitMap;
  436. CurrentProcess = PsGetCurrentProcess();
  437. if ((QuickCheck == 0) && (Alignment == X64K)) {
  438. //
  439. // Initialize the bitmap inline for speed.
  440. //
  441. VadBitMap.SizeOfBitMap = MiLastVadBit + 1;
  442. VadBitMap.Buffer = VAD_BITMAP_SPACE;
  443. //
  444. // Skip the first bit here as we don't generally recommend
  445. // that applications map virtual address zero.
  446. //
  447. FirstBitValue = *((PULONG)VAD_BITMAP_SPACE);
  448. *((PULONG)VAD_BITMAP_SPACE) = (FirstBitValue | 0x1);
  449. BitsNeeded = (ULONG) ((MI_ROUND_TO_64K (SizeOfRange)) / X64K);
  450. StartPosition = RtlFindClearBits (&VadBitMap,
  451. BitsNeeded,
  452. MmWorkingSetList->VadBitMapHint);
  453. if (FirstBitValue & 0x1) {
  454. FirstBitValue = (ULONG)-1;
  455. }
  456. else {
  457. FirstBitValue = (ULONG)~0x1;
  458. }
  459. *((PULONG)VAD_BITMAP_SPACE) &= FirstBitValue;
  460. if (StartPosition != NO_BITS_FOUND) {
  461. *Base = (PVOID) (((ULONG_PTR)StartPosition) * X64K);
  462. #if DBG
  463. if (MiCheckForConflictingVad (CurrentProcess, *Base, (ULONG_PTR)*Base + SizeOfRange - 1) != NULL) {
  464. DbgPrint ("MiFindEmptyAddressRange: overlapping VAD %p %p\n", *Base, SizeOfRange);
  465. DbgBreakPoint ();
  466. }
  467. #endif
  468. return STATUS_SUCCESS;
  469. }
  470. FreeHint = CurrentProcess->VadFreeHint;
  471. if (FreeHint != NULL) {
  472. EndingVa = MI_VPN_TO_VA_ENDING (FreeHint->EndingVpn);
  473. NextVad = MiGetNextVad (FreeHint);
  474. if (NextVad == NULL) {
  475. if (SizeOfRange <
  476. (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS + 1) -
  477. MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, Alignment))) {
  478. *Base = (PVOID) MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,
  479. Alignment);
  480. return STATUS_SUCCESS;
  481. }
  482. }
  483. else {
  484. StartingVa = MI_VPN_TO_VA (NextVad->StartingVpn);
  485. if (SizeOfRange <
  486. ((ULONG_PTR)StartingVa -
  487. MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, Alignment))) {
  488. //
  489. // Check to ensure that the ending address aligned upwards
  490. // is not greater than the starting address.
  491. //
  492. if ((ULONG_PTR)StartingVa >
  493. MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,Alignment)) {
  494. *Base = (PVOID)MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,
  495. Alignment);
  496. return STATUS_SUCCESS;
  497. }
  498. }
  499. }
  500. }
  501. }
  502. Status = MiFindEmptyAddressRangeInTree (
  503. SizeOfRange,
  504. Alignment,
  505. &CurrentProcess->VadRoot,
  506. (PMMADDRESS_NODE *)&CurrentProcess->VadFreeHint,
  507. Base);
  508. return Status;
  509. }
  510. #if DBG
  511. VOID
  512. MiNodeTreeWalk (
  513. IN PMM_AVL_TABLE Table
  514. );
  515. VOID
  516. VadTreeWalk (
  517. VOID
  518. )
  519. {
  520. MiNodeTreeWalk (&PsGetCurrentProcess()->VadRoot);
  521. return;
  522. }
  523. #endif
  524. LOGICAL
  525. MiCheckForConflictingVadExistence (
  526. IN PEPROCESS Process,
  527. IN PVOID StartingAddress,
  528. IN PVOID EndingAddress
  529. )
  530. /*++
  531. Routine Description:
  532. The function determines if any addresses between a given starting and
  533. ending address is contained within a virtual address descriptor.
  534. Arguments:
  535. StartingAddress - Supplies the virtual address to locate a containing
  536. descriptor.
  537. EndingAddress - Supplies the virtual address to locate a containing
  538. descriptor.
  539. Return Value:
  540. TRUE if the VAD if found, FALSE if not.
  541. Environment:
  542. Kernel mode, process address creation mutex held.
  543. --*/
  544. {
  545. #if 0
  546. ULONG StartBit;
  547. ULONG EndBit;
  548. if (MiLastVadBit != 0) {
  549. StartBit = (ULONG) (((ULONG_PTR) MI_64K_ALIGN (StartingAddress)) / X64K);
  550. EndBit = (ULONG) (((ULONG_PTR) MI_64K_ALIGN (EndingAddress)) / X64K);
  551. ASSERT (StartBit <= EndBit);
  552. if (EndBit > MiLastVadBit) {
  553. ASSERT (FALSE);
  554. EndBit = MiLastVadBit;
  555. if (StartBit > MiLastVadBit) {
  556. StartBit = MiLastVadBit;
  557. }
  558. }
  559. while (StartBit <= EndBit) {
  560. if (MI_CHECK_BIT (((PULONG)VAD_BITMAP_SPACE), StartBit) != 0) {
  561. return TRUE;
  562. }
  563. StartBit += 1;
  564. }
  565. ASSERT (MiCheckForConflictingVad (Process, StartingAddress, EndingAddress) == NULL);
  566. return FALSE;
  567. }
  568. #endif
  569. if (MiCheckForConflictingVad (Process, StartingAddress, EndingAddress) != NULL) {
  570. return TRUE;
  571. }
  572. return FALSE;
  573. }
  574. PFILE_OBJECT *
  575. MmPerfVadTreeWalk (
  576. IN PEPROCESS TargetProcess
  577. )
  578. /*++
  579. Routine Description:
  580. This routine walks through the VAD tree to find all files mapped
  581. into the specified process. It returns a pointer to a pool allocation
  582. containing the referenced file object pointers.
  583. Arguments:
  584. TargetProcess - Supplies the process to walk. Note this is usually NOT
  585. the same as the current process.
  586. Return Value:
  587. Returns a pointer to a NULL terminated pool allocation containing
  588. the file object pointers which have been referenced in the process,
  589. NULL if the memory could not be allocated.
  590. It is also the responsibility of the caller to dereference each
  591. file object in the list and then free the returned pool.
  592. Environment:
  593. PASSIVE_LEVEL, arbitrary thread context.
  594. --*/
  595. {
  596. PMMVAD Vad;
  597. ULONG VadCount;
  598. PFILE_OBJECT *File;
  599. PFILE_OBJECT *FileObjects;
  600. PMM_AVL_TABLE Table;
  601. PVOID RestartKey;
  602. PMMADDRESS_NODE NewNode;
  603. ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
  604. Table = &TargetProcess->VadRoot;
  605. RestartKey = NULL;
  606. LOCK_ADDRESS_SPACE (TargetProcess);
  607. if (Table->NumberGenericTableElements == 0) {
  608. UNLOCK_ADDRESS_SPACE (TargetProcess);
  609. return NULL;
  610. }
  611. //
  612. // Allocate one additional entry for the NULL terminator.
  613. //
  614. VadCount = (ULONG)(Table->NumberGenericTableElements + 1);
  615. FileObjects = (PFILE_OBJECT *) ExAllocatePoolWithTag (
  616. PagedPool,
  617. VadCount * sizeof(PFILE_OBJECT),
  618. '01pM');
  619. if (FileObjects == NULL) {
  620. UNLOCK_ADDRESS_SPACE (TargetProcess);
  621. return NULL;
  622. }
  623. File = FileObjects;
  624. do {
  625. NewNode = MiEnumerateGenericTableWithoutSplayingAvl (Table,
  626. &RestartKey);
  627. if (NewNode == NULL) {
  628. break;
  629. }
  630. Vad = (PMMVAD) NewNode;
  631. if ((!Vad->u.VadFlags.PrivateMemory) &&
  632. (Vad->ControlArea != NULL) &&
  633. (Vad->ControlArea->FilePointer != NULL)) {
  634. *File = Vad->ControlArea->FilePointer;
  635. ObReferenceObject (*File);
  636. File += 1;
  637. }
  638. } while (TRUE);
  639. ASSERT (File < FileObjects + VadCount);
  640. UNLOCK_ADDRESS_SPACE (TargetProcess);
  641. *File = NULL;
  642. return FileObjects;
  643. }