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.

8363 lines
216 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. mi.h
  5. Abstract:
  6. This module contains the private data structures and procedure
  7. prototypes for the memory management system.
  8. Author:
  9. Lou Perazzoli (loup) 20-Mar-1989
  10. Landy Wang (landyw) 02-Jun-1997
  11. Revision History:
  12. --*/
  13. #ifndef _MI_
  14. #define _MI_
  15. #pragma warning(disable:4214) // bit field types other than int
  16. #pragma warning(disable:4201) // nameless struct/union
  17. #pragma warning(disable:4324) // alignment sensitive to declspec
  18. #pragma warning(disable:4127) // condition expression is constant
  19. #pragma warning(disable:4115) // named type definition in parentheses
  20. #pragma warning(disable:4232) // dllimport not static
  21. #pragma warning(disable:4206) // translation unit empty
  22. #include "ntos.h"
  23. #include "ntimage.h"
  24. #include "ki.h"
  25. #include "fsrtl.h"
  26. #include "zwapi.h"
  27. #include "pool.h"
  28. #include "stdio.h"
  29. #include "string.h"
  30. #include "safeboot.h"
  31. #include "triage.h"
  32. #include "xip.h"
  33. #if defined(_X86_)
  34. #include "..\mm\i386\mi386.h"
  35. #elif defined(_AMD64_)
  36. #include "..\mm\amd64\miamd.h"
  37. #elif defined(_IA64_)
  38. #include "..\mm\ia64\miia64.h"
  39. #else
  40. #error "mm: a target architecture must be defined."
  41. #endif
  42. #if defined (_WIN64)
  43. #define ASSERT32(exp)
  44. #define ASSERT64(exp) ASSERT(exp)
  45. //
  46. // This macro is used to satisfy the compiler -
  47. // note the assignments are not needed for correctness
  48. // but without it the compiler cannot compile this code
  49. // W4 to check for use of uninitialized variables.
  50. //
  51. #define SATISFY_OVERZEALOUS_COMPILER(x) x
  52. #else
  53. #define ASSERT32(exp) ASSERT(exp)
  54. #define ASSERT64(exp)
  55. #define SATISFY_OVERZEALOUS_COMPILER(x) x
  56. #endif
  57. //
  58. // Special pool constants
  59. //
  60. #define MI_SPECIAL_POOL_PAGABLE 0x8000
  61. #define MI_SPECIAL_POOL_VERIFIER 0x4000
  62. #define MI_SPECIAL_POOL_IN_SESSION 0x2000
  63. #define MI_SPECIAL_POOL_PTE_PAGABLE 0x0002
  64. #define MI_SPECIAL_POOL_PTE_NONPAGABLE 0x0004
  65. #define _2gb 0x80000000 // 2 gigabytes
  66. #define _3gb 0xC0000000 // 3 gigabytes
  67. #define _4gb 0x100000000 // 4 gigabytes
  68. #define MM_FLUSH_COUNTER_MASK (0xFFFFF)
  69. #define MM_FREE_WSLE_SHIFT 4
  70. #define WSLE_NULL_INDEX ((((WSLE_NUMBER)-1) >> MM_FREE_WSLE_SHIFT))
  71. #define MM_FREE_POOL_SIGNATURE (0x50554F4C)
  72. #define MM_MINIMUM_PAGED_POOL_NTAS ((SIZE_T)(48*1024*1024))
  73. #define MM_ALLOCATION_FILLS_VAD ((PMMPTE)(ULONG_PTR)~3)
  74. #define MM_WORKING_SET_LIST_SEARCH 17
  75. #define MM_FLUID_WORKING_SET 8
  76. #define MM_FLUID_PHYSICAL_PAGES 32 //see MmResidentPages below.
  77. #define MM_USABLE_PAGES_FREE 32
  78. #define X64K (ULONG)65536
  79. #define MM_HIGHEST_VAD_ADDRESS ((PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (64 * 1024)))
  80. #define MM_WS_NOT_LISTED ((PLIST_ENTRY)0)
  81. #define MM_WS_TRIMMING ((PLIST_ENTRY)1)
  82. #define MM_WS_SWAPPED_OUT ((PLIST_ENTRY)2)
  83. #if DBG
  84. #define MM_IO_IN_PROGRESS ((PLIST_ENTRY)97)
  85. #endif
  86. #define MM4K_SHIFT 12 //MUST BE LESS THAN OR EQUAL TO PAGE_SHIFT
  87. #define MM4K_MASK 0xfff
  88. #define MMSECTOR_SHIFT 9 //MUST BE LESS THAN OR EQUAL TO PAGE_SHIFT
  89. #define MMSECTOR_MASK 0x1ff
  90. #define MM_LOCK_BY_REFCOUNT 0
  91. #define MM_LOCK_BY_NONPAGE 1
  92. #define MM_MAXIMUM_WRITE_CLUSTER (MM_MAXIMUM_DISK_IO_SIZE / PAGE_SIZE)
  93. //
  94. // Number of PTEs to flush singularly before flushing the entire TB.
  95. //
  96. #define MM_MAXIMUM_FLUSH_COUNT (FLUSH_MULTIPLE_MAXIMUM-1)
  97. //
  98. // Page protections
  99. //
  100. #define MM_ZERO_ACCESS 0 // this value is not used.
  101. #define MM_READONLY 1
  102. #define MM_EXECUTE 2
  103. #define MM_EXECUTE_READ 3
  104. #define MM_READWRITE 4 // bit 2 is set if this is writable.
  105. #define MM_WRITECOPY 5
  106. #define MM_EXECUTE_READWRITE 6
  107. #define MM_EXECUTE_WRITECOPY 7
  108. #define MM_NOCACHE 0x8
  109. #define MM_GUARD_PAGE 0x10
  110. #define MM_DECOMMIT 0x10 //NO_ACCESS, Guard page
  111. #define MM_NOACCESS 0x18 //NO_ACCESS, Guard_page, nocache.
  112. #define MM_UNKNOWN_PROTECTION 0x100 //bigger than 5 bits!
  113. #define MM_LARGE_PAGES 0x111
  114. #define MM_INVALID_PROTECTION ((ULONG)-1) //bigger than 5 bits!
  115. #define MM_KSTACK_OUTSWAPPED 0x1F // Denotes outswapped kernel stack pages.
  116. #define MM_PROTECTION_WRITE_MASK 4
  117. #define MM_PROTECTION_COPY_MASK 1
  118. #define MM_PROTECTION_OPERATION_MASK 7 // mask off guard page and nocache.
  119. #define MM_PROTECTION_EXECUTE_MASK 2
  120. #define MM_SECURE_DELETE_CHECK 0x55
  121. #if defined(_X86PAE_)
  122. //
  123. // PAE mode makes most kernel resources executable to improve
  124. // compatibility with existing driver binaries.
  125. //
  126. #define MI_ADD_EXECUTE_TO_VALID_PTE_IF_PAE(TempPte) \
  127. ASSERT ((TempPte).u.Hard.Valid == 1); \
  128. ((TempPte).u.Long &= ~MmPaeMask);
  129. #define MI_ADD_EXECUTE_TO_INVALID_PTE_IF_PAE(TempPte) \
  130. ASSERT ((TempPte).u.Hard.Valid == 0); \
  131. ((TempPte).u.Soft.Protection |= MM_EXECUTE);
  132. #else
  133. //
  134. // NT64 drivers derived from 32-bit source have to be recompiled so there's
  135. // no need to make everything executable - drivers can specify it explicitly.
  136. //
  137. #define MI_ADD_EXECUTE_TO_VALID_PTE_IF_PAE(TempPte)
  138. #define MI_ADD_EXECUTE_TO_INVALID_PTE_IF_PAE(TempPte)
  139. #endif
  140. //
  141. // Debug flags
  142. //
  143. #define MM_DBG_WRITEFAULT 0x1
  144. #define MM_DBG_PTE_UPDATE 0x2
  145. #define MM_DBG_DUMP_WSL 0x4
  146. #define MM_DBG_PAGEFAULT 0x8
  147. #define MM_DBG_WS_EXPANSION 0x10
  148. #define MM_DBG_MOD_WRITE 0x20
  149. #define MM_DBG_CHECK_PTE 0x40
  150. #define MM_DBG_VAD_CONFLICT 0x80
  151. #define MM_DBG_SECTIONS 0x100
  152. #define MM_DBG_STOP_ON_WOW64_ACCVIO 0x200
  153. #define MM_DBG_SYS_PTES 0x400
  154. #define MM_DBG_CLEAN_PROCESS 0x800
  155. #define MM_DBG_COLLIDED_PAGE 0x1000
  156. #define MM_DBG_DUMP_BOOT_PTES 0x2000
  157. #define MM_DBG_FORK 0x4000
  158. #define MM_DBG_DIR_BASE 0x8000
  159. #define MM_DBG_FLUSH_SECTION 0x10000
  160. #define MM_DBG_PRINTS_MODWRITES 0x20000
  161. #define MM_DBG_PAGE_IN_LIST 0x40000
  162. #define MM_DBG_CHECK_PFN_LOCK 0x80000
  163. #define MM_DBG_PRIVATE_PAGES 0x100000
  164. #define MM_DBG_WALK_VAD_TREE 0x200000
  165. #define MM_DBG_SWAP_PROCESS 0x400000
  166. #define MM_DBG_LOCK_CODE 0x800000
  167. #define MM_DBG_STOP_ON_ACCVIO 0x1000000
  168. #define MM_DBG_PAGE_REF_COUNT 0x2000000
  169. #define MM_DBG_SHOW_FAULTS 0x40000000
  170. #define MM_DBG_SESSIONS 0x80000000
  171. //
  172. // If the PTE.protection & MM_COPY_ON_WRITE_MASK == MM_COPY_ON_WRITE_MASK
  173. // then the PTE is copy on write.
  174. //
  175. #define MM_COPY_ON_WRITE_MASK 5
  176. extern ULONG MmProtectToValue[32];
  177. extern
  178. #if (defined(_WIN64) || defined(_X86PAE_))
  179. ULONGLONG
  180. #else
  181. ULONG
  182. #endif
  183. MmProtectToPteMask[32];
  184. extern ULONG MmMakeProtectNotWriteCopy[32];
  185. extern ACCESS_MASK MmMakeSectionAccess[8];
  186. extern ACCESS_MASK MmMakeFileAccess[8];
  187. //
  188. // Time constants
  189. //
  190. extern const LARGE_INTEGER MmSevenMinutes;
  191. const extern LARGE_INTEGER MmOneSecond;
  192. const extern LARGE_INTEGER MmTwentySeconds;
  193. const extern LARGE_INTEGER MmSeventySeconds;
  194. const extern LARGE_INTEGER MmShortTime;
  195. const extern LARGE_INTEGER MmHalfSecond;
  196. const extern LARGE_INTEGER Mm30Milliseconds;
  197. extern LARGE_INTEGER MmCriticalSectionTimeout;
  198. //
  199. // A month's worth
  200. //
  201. extern ULONG MmCritsectTimeoutSeconds;
  202. //
  203. // this is the csrss process !
  204. //
  205. extern PEPROCESS ExpDefaultErrorPortProcess;
  206. extern SIZE_T MmExtendedCommit;
  207. extern SIZE_T MmTotalProcessCommit;
  208. #if !defined(_WIN64)
  209. extern LIST_ENTRY MmProcessList;
  210. extern PMMPTE MiLargePageHyperPte;
  211. extern PMMPTE MiInitialSystemPageDirectory;
  212. #endif
  213. //
  214. // The total number of pages needed for the loader to successfully hibernate.
  215. //
  216. extern PFN_NUMBER MmHiberPages;
  217. //
  218. // The counters and reasons to retry IO to protect against verifier induced
  219. // failures and temporary conditions.
  220. //
  221. extern ULONG MiIoRetryMask;
  222. extern ULONG MiFaultRetryMask;
  223. extern ULONG MiUserFaultRetryMask;
  224. #define MmIsRetryIoStatus(S) (((S) == STATUS_INSUFFICIENT_RESOURCES) || \
  225. ((S) == STATUS_WORKING_SET_QUOTA) || \
  226. ((S) == STATUS_NO_MEMORY))
  227. #if defined (_MI_MORE_THAN_4GB_)
  228. extern PFN_NUMBER MiNoLowMemory;
  229. #if defined (_WIN64)
  230. #define MI_MAGIC_4GB_RECLAIM 0xffffedf0
  231. #else
  232. #define MI_MAGIC_4GB_RECLAIM 0xffedf0
  233. #endif
  234. #define MI_LOWMEM_MAGIC_BIT (0x80000000)
  235. extern PRTL_BITMAP MiLowMemoryBitMap;
  236. #endif
  237. //
  238. // This is a version of COMPUTE_PAGES_SPANNED that works for 32 and 64 ranges.
  239. //
  240. #define MI_COMPUTE_PAGES_SPANNED(Va, Size) \
  241. ((((ULONG_PTR)(Va) & (PAGE_SIZE -1)) + (Size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)
  242. //++
  243. //
  244. // ULONG
  245. // MI_CONVERT_FROM_PTE_PROTECTION (
  246. // IN ULONG PROTECTION_MASK
  247. // )
  248. //
  249. // Routine Description:
  250. //
  251. // This routine converts a PTE protection into a Protect value.
  252. //
  253. // Arguments:
  254. //
  255. //
  256. // Return Value:
  257. //
  258. // Returns the
  259. //
  260. //--
  261. #define MI_CONVERT_FROM_PTE_PROTECTION(PROTECTION_MASK) \
  262. (MmProtectToValue[PROTECTION_MASK])
  263. #define MI_IS_PTE_PROTECTION_COPY_WRITE(PROTECTION_MASK) \
  264. (((PROTECTION_MASK) & MM_COPY_ON_WRITE_MASK) == MM_COPY_ON_WRITE_MASK)
  265. //++
  266. //
  267. // ULONG
  268. // MI_ROUND_TO_64K (
  269. // IN ULONG LENGTH
  270. // )
  271. //
  272. // Routine Description:
  273. //
  274. //
  275. // The ROUND_TO_64k macro takes a LENGTH in bytes and rounds it up to a multiple
  276. // of 64K.
  277. //
  278. // Arguments:
  279. //
  280. // LENGTH - LENGTH in bytes to round up to 64k.
  281. //
  282. // Return Value:
  283. //
  284. // Returns the LENGTH rounded up to a multiple of 64k.
  285. //
  286. //--
  287. #define MI_ROUND_TO_64K(LENGTH) (((LENGTH) + X64K - 1) & ~((ULONG_PTR)X64K - 1))
  288. extern ULONG MiLastVadBit;
  289. //++
  290. //
  291. // ULONG
  292. // MI_ROUND_TO_SIZE (
  293. // IN ULONG LENGTH,
  294. // IN ULONG ALIGNMENT
  295. // )
  296. //
  297. // Routine Description:
  298. //
  299. //
  300. // The ROUND_TO_SIZE macro takes a LENGTH in bytes and rounds it up to a
  301. // multiple of the alignment.
  302. //
  303. // Arguments:
  304. //
  305. // LENGTH - LENGTH in bytes to round up to.
  306. //
  307. // ALIGNMENT - alignment to round to, must be a power of 2, e.g, 2**n.
  308. //
  309. // Return Value:
  310. //
  311. // Returns the LENGTH rounded up to a multiple of the alignment.
  312. //
  313. //--
  314. #define MI_ROUND_TO_SIZE(LENGTH,ALIGNMENT) \
  315. (((LENGTH) + ((ALIGNMENT) - 1)) & ~((ALIGNMENT) - 1))
  316. //++
  317. //
  318. // PVOID
  319. // MI_64K_ALIGN (
  320. // IN PVOID VA
  321. // )
  322. //
  323. // Routine Description:
  324. //
  325. //
  326. // The MI_64K_ALIGN macro takes a virtual address and returns a 64k-aligned
  327. // virtual address for that page.
  328. //
  329. // Arguments:
  330. //
  331. // VA - Virtual address.
  332. //
  333. // Return Value:
  334. //
  335. // Returns the 64k aligned virtual address.
  336. //
  337. //--
  338. #define MI_64K_ALIGN(VA) ((PVOID)((ULONG_PTR)(VA) & ~((LONG)X64K - 1)))
  339. //++
  340. //
  341. // PVOID
  342. // MI_ALIGN_TO_SIZE (
  343. // IN PVOID VA
  344. // IN ULONG ALIGNMENT
  345. // )
  346. //
  347. // Routine Description:
  348. //
  349. //
  350. // The MI_ALIGN_TO_SIZE macro takes a virtual address and returns a
  351. // virtual address for that page with the specified alignment.
  352. //
  353. // Arguments:
  354. //
  355. // VA - Virtual address.
  356. //
  357. // ALIGNMENT - alignment to round to, must be a power of 2, e.g, 2**n.
  358. //
  359. // Return Value:
  360. //
  361. // Returns the aligned virtual address.
  362. //
  363. //--
  364. #define MI_ALIGN_TO_SIZE(VA,ALIGNMENT) ((PVOID)((ULONG_PTR)(VA) & ~((ULONG_PTR) ALIGNMENT - 1)))
  365. //++
  366. //
  367. // LONGLONG
  368. // MI_STARTING_OFFSET (
  369. // IN PSUBSECTION SUBSECT
  370. // IN PMMPTE PTE
  371. // )
  372. //
  373. // Routine Description:
  374. //
  375. // This macro takes a pointer to a PTE within a subsection and a pointer
  376. // to that subsection and calculates the offset for that PTE within the
  377. // file.
  378. //
  379. // Arguments:
  380. //
  381. // PTE - PTE within subsection.
  382. //
  383. // SUBSECT - Subsection
  384. //
  385. // Return Value:
  386. //
  387. // Offset for issuing I/O from.
  388. //
  389. //--
  390. #define MI_STARTING_OFFSET(SUBSECT,PTE) \
  391. (((LONGLONG)((ULONG_PTR)((PTE) - ((SUBSECT)->SubsectionBase))) << PAGE_SHIFT) + \
  392. ((LONGLONG)((SUBSECT)->StartingSector) << MMSECTOR_SHIFT));
  393. // NTSTATUS
  394. // MiFindEmptyAddressRangeDown (
  395. // IN ULONG_PTR SizeOfRange,
  396. // IN PVOID HighestAddressToEndAt,
  397. // IN ULONG_PTR Alignment,
  398. // OUT PVOID *Base
  399. // )
  400. //
  401. //
  402. // Routine Description:
  403. //
  404. // The function examines the virtual address descriptors to locate
  405. // an unused range of the specified size and returns the starting
  406. // address of the range. This routine looks from the top down.
  407. //
  408. // Arguments:
  409. //
  410. // SizeOfRange - Supplies the size in bytes of the range to locate.
  411. //
  412. // HighestAddressToEndAt - Supplies the virtual address to begin looking
  413. // at.
  414. //
  415. // Alignment - Supplies the alignment for the address. Must be
  416. // a power of 2 and greater than the page_size.
  417. //
  418. //Return Value:
  419. //
  420. // Returns the starting address of a suitable range.
  421. //
  422. #define MiFindEmptyAddressRangeDown(Root,SizeOfRange,HighestAddressToEndAt,Alignment,Base) \
  423. (MiFindEmptyAddressRangeDownTree( \
  424. (SizeOfRange), \
  425. (HighestAddressToEndAt), \
  426. (Alignment), \
  427. Root, \
  428. (Base)))
  429. // PMMVAD
  430. // MiGetPreviousVad (
  431. // IN PMMVAD Vad
  432. // )
  433. //
  434. // Routine Description:
  435. //
  436. // This function locates the virtual address descriptor which contains
  437. // the address range which logically precedes the specified virtual
  438. // address descriptor.
  439. //
  440. // Arguments:
  441. //
  442. // Vad - Supplies a pointer to a virtual address descriptor.
  443. //
  444. // Return Value:
  445. //
  446. // Returns a pointer to the virtual address descriptor containing the
  447. // next address range, NULL if none.
  448. //
  449. //
  450. #define MiGetPreviousVad(VAD) ((PMMVAD)MiGetPreviousNode((PMMADDRESS_NODE)(VAD)))
  451. // PMMVAD
  452. // MiGetNextVad (
  453. // IN PMMVAD Vad
  454. // )
  455. //
  456. // Routine Description:
  457. //
  458. // This function locates the virtual address descriptor which contains
  459. // the address range which logically follows the specified address range.
  460. //
  461. // Arguments:
  462. //
  463. // VAD - Supplies a pointer to a virtual address descriptor.
  464. //
  465. // Return Value:
  466. //
  467. // Returns a pointer to the virtual address descriptor containing the
  468. // next address range, NULL if none.
  469. //
  470. #define MiGetNextVad(VAD) ((PMMVAD)MiGetNextNode((PMMADDRESS_NODE)(VAD)))
  471. // PMMVAD
  472. // MiGetFirstVad (
  473. // Process
  474. // )
  475. //
  476. // Routine Description:
  477. //
  478. // This function locates the virtual address descriptor which contains
  479. // the address range which logically is first within the address space.
  480. //
  481. // Arguments:
  482. //
  483. // Process - Specifies the process in which to locate the VAD.
  484. //
  485. // Return Value:
  486. //
  487. // Returns a pointer to the virtual address descriptor containing the
  488. // first address range, NULL if none.
  489. #define MiGetFirstVad(Process) \
  490. ((PMMVAD)MiGetFirstNode(&Process->VadRoot))
  491. LOGICAL
  492. MiCheckForConflictingVadExistence (
  493. IN PEPROCESS Process,
  494. IN PVOID StartingAddress,
  495. IN PVOID EndingAddress
  496. );
  497. // PMMVAD
  498. // MiCheckForConflictingVad (
  499. // IN PVOID StartingAddress,
  500. // IN PVOID EndingAddress
  501. // )
  502. //
  503. // Routine Description:
  504. //
  505. // The function determines if any addresses between a given starting and
  506. // ending address is contained within a virtual address descriptor.
  507. //
  508. // Arguments:
  509. //
  510. // StartingAddress - Supplies the virtual address to locate a containing
  511. // descriptor.
  512. //
  513. // EndingAddress - Supplies the virtual address to locate a containing
  514. // descriptor.
  515. //
  516. // Return Value:
  517. //
  518. // Returns a pointer to the first conflicting virtual address descriptor
  519. // if one is found, otherwise a NULL value is returned.
  520. //
  521. #define MiCheckForConflictingVad(CurrentProcess,StartingAddress,EndingAddress) \
  522. ((PMMVAD)MiCheckForConflictingNode( \
  523. MI_VA_TO_VPN(StartingAddress), \
  524. MI_VA_TO_VPN(EndingAddress), \
  525. &CurrentProcess->VadRoot))
  526. // PMMCLONE_DESCRIPTOR
  527. // MiGetNextClone (
  528. // IN PMMCLONE_DESCRIPTOR Clone
  529. // )
  530. //
  531. // Routine Description:
  532. //
  533. // This function locates the virtual address descriptor which contains
  534. // the address range which logically follows the specified address range.
  535. //
  536. // Arguments:
  537. //
  538. // Clone - Supplies a pointer to a virtual address descriptor.
  539. //
  540. // Return Value:
  541. //
  542. // Returns a pointer to the virtual address descriptor containing the
  543. // next address range, NULL if none.
  544. //
  545. //
  546. #define MiGetNextClone(CLONE) \
  547. ((PMMCLONE_DESCRIPTOR)MiGetNextNode((PMMADDRESS_NODE)(CLONE)))
  548. // PMMCLONE_DESCRIPTOR
  549. // MiGetPreviousClone (
  550. // IN PMMCLONE_DESCRIPTOR Clone
  551. // )
  552. //
  553. // Routine Description:
  554. //
  555. // This function locates the virtual address descriptor which contains
  556. // the address range which logically precedes the specified virtual
  557. // address descriptor.
  558. //
  559. // Arguments:
  560. //
  561. // Clone - Supplies a pointer to a virtual address descriptor.
  562. //
  563. // Return Value:
  564. //
  565. // Returns a pointer to the virtual address descriptor containing the
  566. // next address range, NULL if none.
  567. #define MiGetPreviousClone(CLONE) \
  568. ((PMMCLONE_DESCRIPTOR)MiGetPreviousNode((PMMADDRESS_NODE)(CLONE)))
  569. // PMMCLONE_DESCRIPTOR
  570. // MiGetFirstClone (
  571. // )
  572. //
  573. // Routine Description:
  574. //
  575. // This function locates the virtual address descriptor which contains
  576. // the address range which logically is first within the address space.
  577. //
  578. // Arguments:
  579. //
  580. // None.
  581. //
  582. // Return Value:
  583. //
  584. // Returns a pointer to the virtual address descriptor containing the
  585. // first address range, NULL if none.
  586. //
  587. #define MiGetFirstClone(_CurrentProcess) \
  588. (((PMM_AVL_TABLE)(_CurrentProcess->CloneRoot))->NumberGenericTableElements == 0 ? NULL : (PMMCLONE_DESCRIPTOR)MiGetFirstNode((PMM_AVL_TABLE)(_CurrentProcess->CloneRoot)))
  589. // VOID
  590. // MiInsertClone (
  591. // IN PMMCLONE_DESCRIPTOR Clone
  592. // )
  593. //
  594. // Routine Description:
  595. //
  596. // This function inserts a virtual address descriptor into the tree and
  597. // reorders the splay tree as appropriate.
  598. //
  599. // Arguments:
  600. //
  601. // Clone - Supplies a pointer to a virtual address descriptor.
  602. //
  603. //
  604. // Return Value:
  605. //
  606. // None.
  607. //
  608. #define MiInsertClone(_CurrentProcess, CLONE) \
  609. { \
  610. ASSERT ((CLONE)->NumberOfPtes != 0); \
  611. ASSERT (_CurrentProcess->CloneRoot != NULL); \
  612. MiInsertNode(((PMMADDRESS_NODE)(CLONE)),(PMM_AVL_TABLE)(_CurrentProcess->CloneRoot)); \
  613. }
  614. // VOID
  615. // MiRemoveClone (
  616. // IN PMMCLONE_DESCRIPTOR Clone
  617. // )
  618. //
  619. // Routine Description:
  620. //
  621. // This function removes a virtual address descriptor from the tree and
  622. // reorders the splay tree as appropriate.
  623. //
  624. // Arguments:
  625. //
  626. // Clone - Supplies a pointer to a virtual address descriptor.
  627. //
  628. // Return Value:
  629. //
  630. // None.
  631. //
  632. #define MiRemoveClone(_CurrentProcess, CLONE) \
  633. ASSERT (_CurrentProcess->CloneRoot != NULL); \
  634. ASSERT (((PMM_AVL_TABLE)_CurrentProcess->CloneRoot)->NumberGenericTableElements != 0); \
  635. MiRemoveNode((PMMADDRESS_NODE)(CLONE),(PMM_AVL_TABLE)(_CurrentProcess->CloneRoot));
  636. // PMMCLONE_DESCRIPTOR
  637. // MiLocateCloneAddress (
  638. // IN PVOID VirtualAddress
  639. // )
  640. //
  641. // /*++
  642. //
  643. // Routine Description:
  644. //
  645. // The function locates the virtual address descriptor which describes
  646. // a given address.
  647. //
  648. // Arguments:
  649. //
  650. // VirtualAddress - Supplies the virtual address to locate a descriptor
  651. // for.
  652. //
  653. // Return Value:
  654. //
  655. // Returns a pointer to the virtual address descriptor which contains
  656. // the supplied virtual address or NULL if none was located.
  657. //
  658. #define MiLocateCloneAddress(_CurrentProcess, VA) \
  659. (_CurrentProcess->CloneRoot ? \
  660. ((PMMCLONE_DESCRIPTOR)MiLocateAddressInTree(((ULONG_PTR)VA), \
  661. (PMM_AVL_TABLE)(_CurrentProcess->CloneRoot))) : \
  662. NULL)
  663. #define MI_VA_TO_PAGE(va) ((ULONG_PTR)(va) >> PAGE_SHIFT)
  664. #define MI_VA_TO_VPN(va) ((ULONG_PTR)(va) >> PAGE_SHIFT)
  665. #define MI_VPN_TO_VA(vpn) (PVOID)((vpn) << PAGE_SHIFT)
  666. #define MI_VPN_TO_VA_ENDING(vpn) (PVOID)(((vpn) << PAGE_SHIFT) | (PAGE_SIZE - 1))
  667. #define MiGetByteOffset(va) ((ULONG_PTR)(va) & (PAGE_SIZE - 1))
  668. #define MI_PFN_ELEMENT(index) (&MmPfnDatabase[index])
  669. //
  670. // Make a write-copy PTE, only writable.
  671. //
  672. #define MI_MAKE_PROTECT_NOT_WRITE_COPY(PROTECT) \
  673. (MmMakeProtectNotWriteCopy[PROTECT])
  674. //
  675. // Define macros to lock and unlock the PFN database.
  676. //
  677. #define MiLockPfnDatabase(OldIrql) \
  678. OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock)
  679. #define MiUnlockPfnDatabase(OldIrql) \
  680. KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql)
  681. #define MiLockPfnDatabaseAtDpcLevel() \
  682. KeAcquireQueuedSpinLockAtDpcLevel(&KeGetCurrentPrcb()->LockQueue[LockQueuePfnLock])
  683. #define MiUnlockPfnDatabaseFromDpcLevel() \
  684. KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->LockQueue[LockQueuePfnLock])
  685. #define MiReleasePfnLock() \
  686. KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->LockQueue[LockQueuePfnLock])
  687. #define MiLockSystemSpace(OldIrql) \
  688. OldIrql = KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock)
  689. #define MiUnlockSystemSpace(OldIrql) \
  690. KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock, OldIrql)
  691. #define MiLockSystemSpaceAtDpcLevel() \
  692. KeAcquireQueuedSpinLockAtDpcLevel(&KeGetCurrentPrcb()->LockQueue[LockQueueSystemSpaceLock])
  693. #define MiUnlockSystemSpaceFromDpcLevel() \
  694. KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->LockQueue[LockQueueSystemSpaceLock])
  695. #define MI_MAX_PFN_CALLERS 500
  696. typedef struct _MMPFNTIMINGS {
  697. LARGE_INTEGER HoldTime; // Low bit is set if another processor waited
  698. PVOID AcquiredAddress;
  699. PVOID ReleasedAddress;
  700. } MMPFNTIMINGS, *PMMPFNTIMINGS;
  701. extern ULONG MiPfnTimings;
  702. extern PVOID MiPfnAcquiredAddress;
  703. extern MMPFNTIMINGS MiPfnSorted[];
  704. extern LARGE_INTEGER MiPfnAcquired;
  705. extern LARGE_INTEGER MiPfnReleased;
  706. extern LARGE_INTEGER MiPfnThreshold;
  707. PVOID
  708. MiGetExecutionAddress (
  709. VOID
  710. );
  711. LARGE_INTEGER
  712. MiQueryPerformanceCounter (
  713. IN PLARGE_INTEGER PerformanceFrequency
  714. );
  715. VOID
  716. MiAddLockToTable (
  717. IN PVOID AcquireAddress,
  718. IN PVOID ReleaseAddress,
  719. IN LARGE_INTEGER HoldTime
  720. );
  721. #if defined(_X86_) || defined(_AMD64_)
  722. #define MI_GET_EXECUTION_ADDRESS(varname) varname = MiGetExecutionAddress();
  723. #else
  724. #define MI_GET_EXECUTION_ADDRESS(varname) varname = NULL;
  725. #endif
  726. // #define _MI_INSTRUMENT_PFN 1
  727. #if defined (_MI_INSTRUMENT_PFN)
  728. #define LOCK_PFN_TIMESTAMP() \
  729. { \
  730. MiPfnAcquired = MiQueryPerformanceCounter (NULL);\
  731. MI_GET_EXECUTION_ADDRESS(MiPfnAcquiredAddress); \
  732. }
  733. #define UNLOCK_PFN_TIMESTAMP() \
  734. { \
  735. PVOID ExecutionAddress; \
  736. LARGE_INTEGER PfnHoldTime; \
  737. \
  738. MiPfnReleased = MiQueryPerformanceCounter (NULL); \
  739. MI_GET_EXECUTION_ADDRESS(ExecutionAddress); \
  740. PfnHoldTime.QuadPart = (MiPfnReleased.QuadPart - MiPfnAcquired.QuadPart) & ~0x1; \
  741. MiAddLockToTable (MiPfnAcquiredAddress, ExecutionAddress, PfnHoldTime); \
  742. }
  743. #else
  744. #define LOCK_PFN_TIMESTAMP()
  745. #define UNLOCK_PFN_TIMESTAMP()
  746. #endif
  747. #define LOCK_PFN(OLDIRQL) ASSERT (KeGetCurrentIrql() <= APC_LEVEL); \
  748. MiLockPfnDatabase(OLDIRQL); \
  749. LOCK_PFN_TIMESTAMP();
  750. #define UNLOCK_PFN(OLDIRQL) \
  751. ASSERT (OLDIRQL <= APC_LEVEL); \
  752. UNLOCK_PFN_TIMESTAMP(); \
  753. MiUnlockPfnDatabase(OLDIRQL); \
  754. ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
  755. #define LOCK_PFN2(OLDIRQL) ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL); \
  756. MiLockPfnDatabase(OLDIRQL); \
  757. LOCK_PFN_TIMESTAMP();
  758. #define UNLOCK_PFN2(OLDIRQL) \
  759. ASSERT (OLDIRQL <= DISPATCH_LEVEL); \
  760. UNLOCK_PFN_TIMESTAMP(); \
  761. MiUnlockPfnDatabase(OLDIRQL); \
  762. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  763. #define LOCK_PFN_AT_DPC() ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); \
  764. MiLockPfnDatabaseAtDpcLevel(); \
  765. LOCK_PFN_TIMESTAMP();
  766. #define UNLOCK_PFN_FROM_DPC() \
  767. UNLOCK_PFN_TIMESTAMP(); \
  768. MiUnlockPfnDatabaseFromDpcLevel(); \
  769. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  770. #define UNLOCK_PFN_AND_THEN_WAIT(OLDIRQL) \
  771. { \
  772. KIRQL XXX; \
  773. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); \
  774. ASSERT (OLDIRQL <= APC_LEVEL); \
  775. KiLockDispatcherDatabase (&XXX); \
  776. UNLOCK_PFN_TIMESTAMP(); \
  777. MiReleasePfnLock(); \
  778. (KeGetCurrentThread())->WaitIrql = OLDIRQL; \
  779. (KeGetCurrentThread())->WaitNext = TRUE; \
  780. }
  781. extern KMUTANT MmSystemLoadLock;
  782. #if DBG
  783. #define SYSLOAD_LOCK_OWNED_BY_ME() ASSERT (MmSystemLoadLock.OwnerThread == KeGetCurrentThread())
  784. #else
  785. #define SYSLOAD_LOCK_OWNED_BY_ME()
  786. #endif
  787. #if DBG
  788. #if defined (_MI_COMPRESSION)
  789. extern KIRQL MiCompressionIrql;
  790. #define MM_PFN_LOCK_ASSERT() \
  791. if (MmDebug & 0x80000) { \
  792. KIRQL _OldIrql; \
  793. _OldIrql = KeGetCurrentIrql(); \
  794. ASSERT ((_OldIrql == DISPATCH_LEVEL) || \
  795. ((MiCompressionIrql != 0) && (_OldIrql == MiCompressionIrql))); \
  796. }
  797. #else
  798. #define MM_PFN_LOCK_ASSERT() \
  799. if (MmDebug & 0x80000) { \
  800. KIRQL _OldIrql; \
  801. _OldIrql = KeGetCurrentIrql(); \
  802. ASSERT (_OldIrql == DISPATCH_LEVEL); \
  803. }
  804. #endif
  805. extern PETHREAD MiExpansionLockOwner;
  806. #define MM_SET_EXPANSION_OWNER() ASSERT (MiExpansionLockOwner == NULL); \
  807. MiExpansionLockOwner = PsGetCurrentThread();
  808. #define MM_CLEAR_EXPANSION_OWNER() ASSERT (MiExpansionLockOwner == PsGetCurrentThread()); \
  809. MiExpansionLockOwner = NULL;
  810. #else
  811. #define MM_PFN_LOCK_ASSERT()
  812. #define MM_SET_EXPANSION_OWNER()
  813. #define MM_CLEAR_EXPANSION_OWNER()
  814. #endif //DBG
  815. #define LOCK_EXPANSION(OLDIRQL) ASSERT (KeGetCurrentIrql() <= APC_LEVEL); \
  816. ExAcquireSpinLock (&MmExpansionLock, &OLDIRQL);\
  817. MM_SET_EXPANSION_OWNER ();
  818. #define UNLOCK_EXPANSION(OLDIRQL) MM_CLEAR_EXPANSION_OWNER (); \
  819. ExReleaseSpinLock (&MmExpansionLock, OLDIRQL); \
  820. ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
  821. #define LOCK_EXPANSION2(OLDIRQL) ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL); \
  822. ExAcquireSpinLock (&MmExpansionLock, &OLDIRQL);\
  823. MM_SET_EXPANSION_OWNER ();
  824. #define UNLOCK_EXPANSION2(OLDIRQL) MM_CLEAR_EXPANSION_OWNER (); \
  825. ExReleaseSpinLock (&MmExpansionLock, OLDIRQL); \
  826. ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL);
  827. // #define _MI_INSTRUMENT_WS 1
  828. #if defined (_MI_INSTRUMENT_WS)
  829. #if defined (_MI_INSTRUMENT_PFN)
  830. error - cannot enable both WS & PFN tracing concurrently yet.
  831. #endif
  832. extern KSPIN_LOCK MiInstrumentationLock;
  833. extern EPROCESS MiSystemCacheDummyProcess;
  834. #define LOCK_WS_TIMESTAMP(PROCESS) \
  835. if (PROCESS != NULL) { \
  836. LARGE_INTEGER TimeNow; \
  837. TimeNow = MiQueryPerformanceCounter (NULL); \
  838. PROCESS->Spare0 = (PVOID) (ULONG_PTR) TimeNow.LowPart; \
  839. PROCESS->Spare1 = (PVOID) MiGetExecutionAddress(); \
  840. }
  841. #define UNLOCK_WS_TIMESTAMP(PROCESS) \
  842. if (PROCESS != NULL) { \
  843. PVOID ExecutionAddress; \
  844. LARGE_INTEGER WsHoldTime; \
  845. LARGE_INTEGER WsReleased; \
  846. \
  847. WsReleased = MiQueryPerformanceCounter (NULL); \
  848. MI_GET_EXECUTION_ADDRESS(ExecutionAddress); \
  849. WsHoldTime.QuadPart = ((ULONG_PTR)WsReleased.LowPart - (ULONG_PTR)PROCESS->Spare0) & ~0x1; \
  850. MiAddLockToTable (PROCESS->Spare1, ExecutionAddress, WsHoldTime); \
  851. }
  852. #else
  853. #define LOCK_WS_TIMESTAMP(PROCESS)
  854. #define UNLOCK_WS_TIMESTAMP(PROCESS)
  855. #endif
  856. #define MM_WS_LOCK_ASSERT(WSINFO) \
  857. ASSERT (KeGetCurrentThread () == KeGetOwnerGuardedMutex (&(WSINFO)->WorkingSetMutex))
  858. //
  859. // System working set synchronization definitions.
  860. //
  861. #define MM_SYSTEM_WS_LOCK_TIMESTAMP() \
  862. LOCK_WS_TIMESTAMP(((PEPROCESS)&MiSystemCacheDummyProcess));
  863. #define MM_SYSTEM_WS_UNLOCK_TIMESTAMP() \
  864. UNLOCK_WS_TIMESTAMP(((PEPROCESS)&MiSystemCacheDummyProcess));
  865. #define LOCK_SYSTEM_WS(_Thread) \
  866. KeAcquireGuardedMutex (&MmSystemCacheWs.WorkingSetMutex); \
  867. MM_SYSTEM_WS_LOCK_TIMESTAMP();
  868. #define UNLOCK_SYSTEM_WS() \
  869. MM_SYSTEM_WS_UNLOCK_TIMESTAMP(); \
  870. KeReleaseGuardedMutex (&MmSystemCacheWs.WorkingSetMutex);
  871. //
  872. // Generic working set synchronization definitions.
  873. //
  874. #define LOCK_WORKING_SET(WSINFO) \
  875. ASSERT (MI_IS_SESSION_ADDRESS(WSINFO) == FALSE); \
  876. KeAcquireGuardedMutex (&(WSINFO)->WorkingSetMutex); \
  877. #define UNLOCK_WORKING_SET(WSINFO) \
  878. ASSERT (MI_IS_SESSION_ADDRESS(WSINFO) == FALSE); \
  879. KeReleaseGuardedMutex (&(WSINFO)->WorkingSetMutex);
  880. //
  881. // Session working set synchronization definitions.
  882. //
  883. #define MM_SESSION_SPACE_WS_LOCK_ASSERT() \
  884. MM_WS_LOCK_ASSERT (&MmSessionSpace->Vm);
  885. //
  886. // Process working set synchronization definitions.
  887. //
  888. #define MI_WS_OWNER(PROCESS) (KeGetOwnerGuardedMutex (&(PROCESS)->Vm.WorkingSetMutex) == KeGetCurrentThread ())
  889. #define MI_NOT_WS_OWNER(PROCESS) (!MI_WS_OWNER(PROCESS))
  890. #define MI_IS_WS_UNSAFE(PROCESS) ((PROCESS)->Vm.Flags.AcquiredUnsafe == 1)
  891. #define LOCK_WS(PROCESS) \
  892. KeAcquireGuardedMutex (&((PROCESS)->Vm.WorkingSetMutex)); \
  893. LOCK_WS_TIMESTAMP(PROCESS); \
  894. ASSERT (!MI_IS_WS_UNSAFE(PROCESS));
  895. #define LOCK_WS_UNSAFE(PROCESS) \
  896. ASSERT (KeAreAllApcsDisabled () == TRUE); \
  897. KeAcquireGuardedMutexUnsafe (&((PROCESS)->Vm.WorkingSetMutex));\
  898. LOCK_WS_TIMESTAMP(PROCESS); \
  899. ASSERT (!MI_IS_WS_UNSAFE(PROCESS)); \
  900. (PROCESS)->Vm.Flags.AcquiredUnsafe = 1;
  901. #define MI_MUST_BE_UNSAFE(PROCESS) \
  902. ASSERT (KeGetCurrentIrql() <= APC_LEVEL); \
  903. ASSERT (KeAreAllApcsDisabled () == TRUE); \
  904. ASSERT (MI_WS_OWNER(PROCESS)); \
  905. ASSERT (MI_IS_WS_UNSAFE(PROCESS));
  906. #define MI_MUST_BE_SAFE(PROCESS) \
  907. ASSERT (MI_WS_OWNER(PROCESS)); \
  908. ASSERT (!MI_IS_WS_UNSAFE(PROCESS));
  909. #define UNLOCK_WS(PROCESS) \
  910. MI_MUST_BE_SAFE(PROCESS); \
  911. UNLOCK_WS_TIMESTAMP(PROCESS); \
  912. KeReleaseGuardedMutex (&((PROCESS)->Vm.WorkingSetMutex));
  913. #define UNLOCK_WS_UNSAFE(PROCESS) \
  914. MI_MUST_BE_UNSAFE(PROCESS); \
  915. ASSERT (KeAreAllApcsDisabled () == TRUE); \
  916. (PROCESS)->Vm.Flags.AcquiredUnsafe = 0; \
  917. UNLOCK_WS_TIMESTAMP(PROCESS); \
  918. KeReleaseGuardedMutexUnsafe(&((PROCESS)->Vm.WorkingSetMutex)); \
  919. ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
  920. //
  921. // Address space synchronization definitions.
  922. //
  923. #define LOCK_ADDRESS_SPACE(PROCESS) \
  924. KeAcquireGuardedMutex (&((PROCESS)->AddressCreationLock));
  925. #define LOCK_WS_AND_ADDRESS_SPACE(PROCESS) \
  926. LOCK_ADDRESS_SPACE(PROCESS); \
  927. LOCK_WS_UNSAFE(PROCESS);
  928. #define UNLOCK_WS_AND_ADDRESS_SPACE(PROCESS) \
  929. UNLOCK_WS_UNSAFE(PROCESS); \
  930. UNLOCK_ADDRESS_SPACE(PROCESS);
  931. #define UNLOCK_ADDRESS_SPACE(PROCESS) \
  932. KeReleaseGuardedMutex (&((PROCESS)->AddressCreationLock));
  933. //
  934. // The working set lock may have been acquired safely or unsafely.
  935. // Release and reacquire it regardless.
  936. //
  937. #define UNLOCK_WS_REGARDLESS(PROCESS, WSHELDSAFE) \
  938. ASSERT (MI_WS_OWNER (PROCESS)); \
  939. if (MI_IS_WS_UNSAFE (PROCESS)) { \
  940. UNLOCK_WS_UNSAFE (PROCESS); \
  941. WSHELDSAFE = FALSE; \
  942. } \
  943. else { \
  944. UNLOCK_WS (PROCESS); \
  945. WSHELDSAFE = TRUE; \
  946. }
  947. #define LOCK_WS_REGARDLESS(PROCESS, WSHELDSAFE) \
  948. if (WSHELDSAFE == TRUE) { \
  949. LOCK_WS (PROCESS); \
  950. } \
  951. else { \
  952. LOCK_WS_UNSAFE (PROCESS); \
  953. }
  954. //
  955. // Hyperspace synchronization definitions.
  956. //
  957. #define LOCK_HYPERSPACE(_Process, OLDIRQL) \
  958. ASSERT (_Process == PsGetCurrentProcess ()); \
  959. ExAcquireSpinLock (&_Process->HyperSpaceLock, OLDIRQL);
  960. #define UNLOCK_HYPERSPACE(_Process, VA, OLDIRQL) \
  961. ASSERT (_Process == PsGetCurrentProcess ()); \
  962. MiGetPteAddress(VA)->u.Long = 0; \
  963. ExReleaseSpinLock (&_Process->HyperSpaceLock, OLDIRQL);
  964. #define LOCK_HYPERSPACE_AT_DPC(_Process) \
  965. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); \
  966. ASSERT (_Process == PsGetCurrentProcess ()); \
  967. ExAcquireSpinLockAtDpcLevel (&_Process->HyperSpaceLock);
  968. #define UNLOCK_HYPERSPACE_FROM_DPC(_Process, VA) \
  969. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); \
  970. ASSERT (_Process == PsGetCurrentProcess ()); \
  971. MiGetPteAddress(VA)->u.Long = 0; \
  972. ExReleaseSpinLockFromDpcLevel (&_Process->HyperSpaceLock);
  973. #define MiUnmapPageInHyperSpace(_Process, VA, OLDIRQL) UNLOCK_HYPERSPACE(_Process, VA, OLDIRQL)
  974. #define MiUnmapPageInHyperSpaceFromDpc(_Process, VA) UNLOCK_HYPERSPACE_FROM_DPC(_Process, VA)
  975. #define ZERO_LARGE(LargeInteger) \
  976. (LargeInteger).LowPart = 0; \
  977. (LargeInteger).HighPart = 0;
  978. #define NO_BITS_FOUND ((ULONG)-1)
  979. //++
  980. //
  981. // ULONG
  982. // MI_CHECK_BIT (
  983. // IN PULONG ARRAY
  984. // IN ULONG BIT
  985. // )
  986. //
  987. // Routine Description:
  988. //
  989. // The MI_CHECK_BIT macro checks to see if the specified bit is
  990. // set within the specified array.
  991. //
  992. // Arguments:
  993. //
  994. // ARRAY - First element of the array to check.
  995. //
  996. // BIT - bit number (first bit is 0) to check.
  997. //
  998. // Return Value:
  999. //
  1000. // Returns the value of the bit (0 or 1).
  1001. //
  1002. //--
  1003. #define MI_CHECK_BIT(ARRAY,BIT) \
  1004. (((ULONG)ARRAY[(BIT) / (sizeof(ULONG)*8)] >> ((BIT) & 0x1F)) & 1)
  1005. //++
  1006. //
  1007. // VOID
  1008. // MI_SET_BIT (
  1009. // IN PULONG ARRAY
  1010. // IN ULONG BIT
  1011. // )
  1012. //
  1013. // Routine Description:
  1014. //
  1015. // The MI_SET_BIT macro sets the specified bit within the
  1016. // specified array.
  1017. //
  1018. // Arguments:
  1019. //
  1020. // ARRAY - First element of the array to set.
  1021. //
  1022. // BIT - bit number.
  1023. //
  1024. // Return Value:
  1025. //
  1026. // None.
  1027. //
  1028. //--
  1029. #define MI_SET_BIT(ARRAY,BIT) \
  1030. ARRAY[(BIT) / (sizeof(ULONG)*8)] |= (1 << ((BIT) & 0x1F))
  1031. //++
  1032. //
  1033. // VOID
  1034. // MI_CLEAR_BIT (
  1035. // IN PULONG ARRAY
  1036. // IN ULONG BIT
  1037. // )
  1038. //
  1039. // Routine Description:
  1040. //
  1041. // The MI_CLEAR_BIT macro sets the specified bit within the
  1042. // specified array.
  1043. //
  1044. // Arguments:
  1045. //
  1046. // ARRAY - First element of the array to clear.
  1047. //
  1048. // BIT - bit number.
  1049. //
  1050. // Return Value:
  1051. //
  1052. // None.
  1053. //
  1054. //--
  1055. #define MI_CLEAR_BIT(ARRAY,BIT) \
  1056. ARRAY[(BIT) / (sizeof(ULONG)*8)] &= ~(1 << ((BIT) & 0x1F))
  1057. //
  1058. // These control the mirroring capabilities.
  1059. //
  1060. extern ULONG MmMirroring;
  1061. #define MM_MIRRORING_ENABLED 0x1 // Enable mirroring capabilities.
  1062. #define MM_MIRRORING_VERIFYING 0x2 // The HAL wants to verify the copy.
  1063. extern PRTL_BITMAP MiMirrorBitMap;
  1064. extern PRTL_BITMAP MiMirrorBitMap2;
  1065. extern LOGICAL MiMirroringActive;
  1066. #if defined (_WIN64)
  1067. #define MI_MAGIC_AWE_PTEFRAME 0x3ffedcbffffedcb
  1068. #else
  1069. #define MI_MAGIC_AWE_PTEFRAME 0x3ffedcb
  1070. #endif
  1071. #define MI_PFN_IS_AWE(Pfn1) \
  1072. ((Pfn1->u2.ShareCount <= 3) && \
  1073. (Pfn1->u3.e1.PageLocation == ActiveAndValid) && \
  1074. (Pfn1->u4.VerifierAllocation == 0) && \
  1075. (Pfn1->u3.e1.LargeSessionAllocation == 0) && \
  1076. (Pfn1->u3.e1.StartOfAllocation == 1) && \
  1077. (Pfn1->u3.e1.EndOfAllocation == 1) && \
  1078. (Pfn1->u4.PteFrame == MI_MAGIC_AWE_PTEFRAME))
  1079. //
  1080. // The cache type definitions are carefully chosen to line up with the
  1081. // MEMORY_CACHING_TYPE definitions to ease conversions. Any changes here must
  1082. // be reflected throughout the code.
  1083. //
  1084. typedef enum _MI_PFN_CACHE_ATTRIBUTE {
  1085. MiNonCached,
  1086. MiCached,
  1087. MiWriteCombined,
  1088. MiNotMapped
  1089. } MI_PFN_CACHE_ATTRIBUTE, *PMI_PFN_CACHE_ATTRIBUTE;
  1090. //
  1091. // This conversion array is unfortunately needed because not all
  1092. // hardware platforms support all possible cache values. Note that
  1093. // the first range is for system RAM, the second range is for I/O space.
  1094. //
  1095. extern MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes[2 * MmMaximumCacheType];
  1096. //++
  1097. //
  1098. // MI_PFN_CACHE_ATTRIBUTE
  1099. // MI_TRANSLATE_CACHETYPE (
  1100. // IN MEMORY_CACHING_TYPE InputCacheType,
  1101. // IN ULONG IoSpace
  1102. // )
  1103. //
  1104. // Routine Description:
  1105. //
  1106. // Returns the hardware supported cache type for the requested cachetype.
  1107. //
  1108. // Arguments:
  1109. //
  1110. // InputCacheType - Supplies the desired cache type.
  1111. //
  1112. // IoSpace - Supplies nonzero (not necessarily 1 though) if this is
  1113. // I/O space, zero if it is main memory.
  1114. //
  1115. // Return Value:
  1116. //
  1117. // The actual cache type.
  1118. //
  1119. //--
  1120. FORCEINLINE
  1121. MI_PFN_CACHE_ATTRIBUTE
  1122. MI_TRANSLATE_CACHETYPE(
  1123. IN MEMORY_CACHING_TYPE InputCacheType,
  1124. IN ULONG IoSpace
  1125. )
  1126. {
  1127. ASSERT (InputCacheType <= MmWriteCombined);
  1128. if (IoSpace != 0) {
  1129. IoSpace = MmMaximumCacheType;
  1130. }
  1131. return MiPlatformCacheAttributes[IoSpace + InputCacheType];
  1132. }
  1133. //++
  1134. //
  1135. // VOID
  1136. // MI_SET_CACHETYPE_TRANSLATION (
  1137. // IN MEMORY_CACHING_TYPE InputCacheType,
  1138. // IN ULONG IoSpace,
  1139. // IN MI_PFN_CACHE_ATTRIBUTE NewAttribute
  1140. // )
  1141. //
  1142. // Routine Description:
  1143. //
  1144. // This function sets the hardware supported cachetype for the
  1145. // specified cachetype.
  1146. //
  1147. // Arguments:
  1148. //
  1149. // InputCacheType - Supplies the desired cache type.
  1150. //
  1151. // IoSpace - Supplies nonzero (not necessarily 1 though) if this is
  1152. // I/O space, zero if it is main memory.
  1153. //
  1154. // NewAttribute - Supplies the desired attribute.
  1155. //
  1156. // Return Value:
  1157. //
  1158. // None.
  1159. //
  1160. //--
  1161. FORCEINLINE
  1162. VOID
  1163. MI_SET_CACHETYPE_TRANSLATION(
  1164. IN MEMORY_CACHING_TYPE InputCacheType,
  1165. IN ULONG IoSpace,
  1166. IN MI_PFN_CACHE_ATTRIBUTE NewAttribute
  1167. )
  1168. {
  1169. ASSERT (InputCacheType <= MmWriteCombined);
  1170. if (IoSpace != 0) {
  1171. IoSpace = MmMaximumCacheType;
  1172. }
  1173. MiPlatformCacheAttributes[IoSpace + InputCacheType] = NewAttribute;
  1174. }
  1175. #define MI_MARK_FRAME_AS_KSTACK(_PageFrameIndex) { \
  1176. PMMPFN _Pfn1; \
  1177. _Pfn1 = MI_PFN_ELEMENT (_PageFrameIndex); \
  1178. ASSERT (_Pfn1->u4.KernelStack == 0); \
  1179. _Pfn1->u4.KernelStack = 1; \
  1180. }
  1181. #define MI_UNMARK_PFN_AS_KSTACK(_Pfn1) \
  1182. ASSERT (_Pfn1->u4.KernelStack == 1); \
  1183. _Pfn1->u4.KernelStack = 0;
  1184. //
  1185. // PFN database element.
  1186. //
  1187. //
  1188. // Define pseudo fields for start and end of allocation.
  1189. //
  1190. #define StartOfAllocation ReadInProgress
  1191. #define EndOfAllocation WriteInProgress
  1192. #define LargeSessionAllocation PrototypePte
  1193. typedef struct _MMPFNENTRY {
  1194. ULONG Modified : 1;
  1195. ULONG ReadInProgress : 1;
  1196. ULONG WriteInProgress : 1;
  1197. ULONG PrototypePte: 1;
  1198. ULONG PageColor : 4;
  1199. ULONG PageLocation : 3;
  1200. ULONG RemovalRequested : 1;
  1201. ULONG CacheAttribute : 2;
  1202. ULONG Rom : 1;
  1203. ULONG ParityError : 1;
  1204. ULONG DontUse : 16; // overlays USHORT for reference count field.
  1205. } MMPFNENTRY;
  1206. #if defined (_X86PAE_)
  1207. #pragma pack(1)
  1208. #endif
  1209. typedef struct _MMPFN {
  1210. union {
  1211. PFN_NUMBER Flink;
  1212. WSLE_NUMBER WsIndex;
  1213. PKEVENT Event;
  1214. NTSTATUS ReadStatus;
  1215. //
  1216. // Note: NextStackPfn is actually used as SLIST_ENTRY, however
  1217. // because of its alignment characteristics, using that type would
  1218. // unnecessarily add padding to this structure.
  1219. //
  1220. SINGLE_LIST_ENTRY NextStackPfn;
  1221. } u1;
  1222. PMMPTE PteAddress;
  1223. union {
  1224. PFN_NUMBER Blink;
  1225. ULONG_PTR ShareCount;
  1226. } u2;
  1227. union {
  1228. MMPFNENTRY e1;
  1229. struct {
  1230. USHORT ShortFlags;
  1231. USHORT ReferenceCount;
  1232. } e2;
  1233. } u3;
  1234. #if defined (_WIN64)
  1235. ULONG UsedPageTableEntries;
  1236. #endif
  1237. union {
  1238. MMPTE OriginalPte;
  1239. LONG AweReferenceCount;
  1240. };
  1241. union {
  1242. ULONG_PTR EntireFrame;
  1243. struct {
  1244. #if defined (_WIN64)
  1245. #define MM_NO_PTE_FRAME (0x3FFFFFFFFFFFFFF)
  1246. ULONG_PTR PteFrame: 58;
  1247. #else
  1248. #define MM_NO_PTE_FRAME (0x3FFFFFF)
  1249. ULONG_PTR PteFrame: 26;
  1250. #endif
  1251. ULONG_PTR InPageError : 1;
  1252. ULONG_PTR VerifierAllocation : 1;
  1253. ULONG_PTR AweAllocation : 1;
  1254. ULONG_PTR LockCharged : 1; // maintained for DBG only
  1255. ULONG_PTR KernelStack : 1; // only for valid (not trans) pages
  1256. ULONG_PTR MustBeCached : 1;
  1257. };
  1258. } u4;
  1259. } MMPFN, *PMMPFN;
  1260. #if defined (_X86PAE_)
  1261. #pragma pack()
  1262. #endif
  1263. //
  1264. // No multiplier reciprocal needs to be inlined because the compiler (using Oxt)
  1265. // automatically computes the correct number, avoiding the expensive divide
  1266. // instruction.
  1267. //
  1268. #define MI_PFN_ELEMENT_TO_INDEX(_Pfn) ((PFN_NUMBER)(((ULONG_PTR)(_Pfn) - (ULONG_PTR)MmPfnDatabase) / sizeof (MMPFN)))
  1269. PVOID
  1270. MiGetInstructionPointer (
  1271. VOID
  1272. );
  1273. // #define _MI_DEBUG_DIRTY 1 // Uncomment this for dirty bit logging
  1274. #if defined (_MI_DEBUG_DIRTY)
  1275. extern ULONG MiTrackDirtys;
  1276. #define MI_DIRTY_BACKTRACE_LENGTH 17
  1277. typedef struct _MI_DIRTY_TRACES {
  1278. PETHREAD Thread;
  1279. PEPROCESS Process;
  1280. PMMPFN Pfn;
  1281. PMMPTE PointerPte;
  1282. ULONG_PTR CallerId;
  1283. ULONG_PTR ShareCount;
  1284. USHORT ShortFlags;
  1285. USHORT ReferenceCount;
  1286. PVOID StackTrace [MI_DIRTY_BACKTRACE_LENGTH];
  1287. } MI_DIRTY_TRACES, *PMI_DIRTY_TRACES;
  1288. extern LONG MiDirtyIndex;
  1289. extern PMI_DIRTY_TRACES MiDirtyTraces;
  1290. VOID
  1291. FORCEINLINE
  1292. MiSnapDirty (
  1293. IN PMMPFN Pfn,
  1294. IN ULONG NewValue,
  1295. IN ULONG CallerId
  1296. )
  1297. {
  1298. PEPROCESS Process;
  1299. PMI_DIRTY_TRACES Information;
  1300. ULONG Index;
  1301. ULONG Hash;
  1302. if (MiDirtyTraces == NULL) {
  1303. return;
  1304. }
  1305. Index = InterlockedIncrement (&MiDirtyIndex);
  1306. Index &= (MiTrackDirtys - 1);
  1307. Information = &MiDirtyTraces[Index];
  1308. Process = PsGetCurrentProcess ();
  1309. Information->Thread = PsGetCurrentThread ();
  1310. Information->Process = Process;
  1311. Information->Pfn = Pfn;
  1312. Information->PointerPte = Pfn->PteAddress;
  1313. Information->CallerId = CallerId;
  1314. Information->ShareCount = Pfn->u2.ShareCount;
  1315. Information->ShortFlags = Pfn->u3.e2.ShortFlags;
  1316. Information->ReferenceCount = Pfn->u3.e2.ReferenceCount;
  1317. if (NewValue != 0) {
  1318. Information->Process = (PEPROCESS) ((ULONG_PTR)Process | 0x1);
  1319. }
  1320. RtlZeroMemory (&Information->StackTrace[0], MI_DIRTY_BACKTRACE_LENGTH * sizeof(PVOID));
  1321. #if defined (_WIN64)
  1322. if (KeAreAllApcsDisabled () == TRUE) {
  1323. Information->StackTrace[1] = (PVOID) _ReturnAddress ();
  1324. Information->StackTrace[0] = MiGetInstructionPointer ();
  1325. }
  1326. else
  1327. #endif
  1328. RtlCaptureStackBackTrace (0, MI_DIRTY_BACKTRACE_LENGTH, Information->StackTrace, &Hash);
  1329. }
  1330. #define MI_SNAP_DIRTY(_Pfn, _NewValue, _Callerid) MiSnapDirty(_Pfn, _NewValue, _Callerid)
  1331. #else
  1332. #define MI_SNAP_DIRTY(_Pfn, _NewValue, _Callerid)
  1333. #endif
  1334. #if DBG || defined (_MI_DEBUG_ALTPTE)
  1335. #define _MI_DEBUG_PTE 1 // Enable PTE change logging
  1336. #endif
  1337. #if defined (_MI_DEBUG_PTE)
  1338. #define MI_PTE_BACKTRACE_LENGTH 7
  1339. typedef struct _MI_PTE_TRACES {
  1340. PETHREAD Thread;
  1341. PEPROCESS Process;
  1342. PMMPTE PointerPte;
  1343. MMPTE PteContents;
  1344. MMPTE NewPteContents;
  1345. PVOID StackTrace [MI_PTE_BACKTRACE_LENGTH];
  1346. } MI_PTE_TRACES, *PMI_PTE_TRACES;
  1347. extern LONG MiPteIndex;
  1348. #define MI_PTE_TRACE_SIZE 0x4000
  1349. extern MI_PTE_TRACES MiPteTraces[MI_PTE_TRACE_SIZE];
  1350. extern LONG MiInDebugger;
  1351. VOID
  1352. FORCEINLINE
  1353. MiSnapPte (
  1354. IN PMMPTE PointerPte,
  1355. IN MMPTE NewValue
  1356. )
  1357. {
  1358. ULONG Hash;
  1359. ULONG Index;
  1360. PMI_PTE_TRACES Information;
  1361. Index = InterlockedIncrement (&MiPteIndex);
  1362. Index &= (MI_PTE_TRACE_SIZE - 1);
  1363. Information = &MiPteTraces[Index];
  1364. Information->Thread = PsGetCurrentThread ();
  1365. Information->Process = PsGetCurrentProcess ();
  1366. Information->PteContents = *PointerPte;
  1367. Information->NewPteContents = NewValue;
  1368. Information->PointerPte = PointerPte;
  1369. if ((PointerPte < MiGetPteAddress (MmHighestUserAddress)) &&
  1370. (PointerPte >= MiGetPteAddress (0))) {
  1371. //
  1372. // The current thread must own this process' working set mutex.
  1373. //
  1374. if (MiInDebugger == 0) {
  1375. ASSERT (MI_WS_OWNER (PsGetCurrentProcess()));
  1376. }
  1377. #if !defined(_IA64_)
  1378. if ((NewValue.u.Hard.Valid == 1) && (NewValue.u.Hard.LargePage == 1)) {
  1379. DbgPrint ("Marking PTE %p as large %p\n", PointerPte, NewValue.u.Long);
  1380. DbgBreakPoint ();
  1381. }
  1382. #endif
  1383. }
  1384. RtlZeroMemory (&Information->StackTrace[0], MI_PTE_BACKTRACE_LENGTH * sizeof(PVOID));
  1385. #if defined (_WIN64)
  1386. if (KeAreAllApcsDisabled () == TRUE) {
  1387. Information->StackTrace[1] = (PVOID) _ReturnAddress ();
  1388. Information->StackTrace[0] = MiGetInstructionPointer ();
  1389. }
  1390. else
  1391. #endif
  1392. RtlCaptureStackBackTrace (0, MI_PTE_BACKTRACE_LENGTH, Information->StackTrace, &Hash);
  1393. #if defined (_MI_DEBUG_ALTPTE)
  1394. if (PsGetCurrentProcess()->Wow64Process != NULL) {
  1395. MiLogPteInAltTrace ((PVOID) Information);
  1396. }
  1397. #endif
  1398. }
  1399. #define MI_LOG_PTE_CHANGE(_PointerPte, _PteContents) MiSnapPte(_PointerPte, _PteContents)
  1400. #else
  1401. #define MI_LOG_PTE_CHANGE(_PointerPte, _PteContents)
  1402. #endif
  1403. #define MI_DEBUGGER_WRITE_VALID_PTE_NEW_PROTECTION(_PointerPte, _PteContents) \
  1404. InterlockedIncrement (&MiInDebugger); \
  1405. MI_WRITE_VALID_PTE_NEW_PROTECTION(_PointerPte, _PteContents); \
  1406. InterlockedDecrement (&MiInDebugger);
  1407. #if 0
  1408. #define MI_STAMP_MODIFIED(Pfn,id) (Pfn)->u4.Reserved = (id);
  1409. #else
  1410. #define MI_STAMP_MODIFIED(Pfn,id)
  1411. #endif
  1412. //++
  1413. //
  1414. // VOID
  1415. // MI_SET_MODIFIED (
  1416. // IN PMMPFN Pfn,
  1417. // IN ULONG NewValue,
  1418. // IN ULONG CallerId
  1419. // )
  1420. //
  1421. // Routine Description:
  1422. //
  1423. // Set (or clear) the modified bit in the PFN database element.
  1424. // The PFN lock must be held.
  1425. //
  1426. // Arguments:
  1427. //
  1428. // Pfn - Supplies the PFN to operate on.
  1429. //
  1430. // NewValue - Supplies 1 to set the modified bit, 0 to clear it.
  1431. //
  1432. // CallerId - Supplies a caller ID useful for debugging purposes.
  1433. //
  1434. // Return Value:
  1435. //
  1436. // None.
  1437. //
  1438. //--
  1439. //
  1440. #define MI_SET_MODIFIED(_Pfn, _NewValue, _CallerId) \
  1441. ASSERT ((_Pfn)->u3.e1.Rom == 0); \
  1442. MI_SNAP_DIRTY (_Pfn, _NewValue, _CallerId); \
  1443. if ((_NewValue) != 0) { \
  1444. MI_STAMP_MODIFIED (_Pfn, _CallerId); \
  1445. } \
  1446. (_Pfn)->u3.e1.Modified = (_NewValue);
  1447. //
  1448. // ccNUMA is supported in multiprocessor PAE and WIN64 systems only.
  1449. //
  1450. #if (defined(_WIN64) || defined(_X86PAE_)) && !defined(NT_UP)
  1451. #define MI_MULTINODE
  1452. VOID
  1453. MiDetermineNode (
  1454. IN PFN_NUMBER Page,
  1455. IN PMMPFN Pfn
  1456. );
  1457. #else
  1458. #define MiDetermineNode(x,y) ((y)->u3.e1.PageColor = 0)
  1459. #endif
  1460. #if defined (_WIN64)
  1461. //
  1462. // Note there are some places where these portable macros are not currently
  1463. // used because we are not in the correct address space required.
  1464. //
  1465. #define MI_CAPTURE_USED_PAGETABLE_ENTRIES(PFN) \
  1466. ASSERT ((PFN)->UsedPageTableEntries <= PTE_PER_PAGE); \
  1467. (PFN)->OriginalPte.u.Soft.UsedPageTableEntries = (PFN)->UsedPageTableEntries;
  1468. #define MI_RETRIEVE_USED_PAGETABLE_ENTRIES_FROM_PTE(RBL, PTE) \
  1469. ASSERT ((PTE)->u.Soft.UsedPageTableEntries <= PTE_PER_PAGE); \
  1470. (RBL)->UsedPageTableEntries = (ULONG)(((PMMPTE)(PTE))->u.Soft.UsedPageTableEntries);
  1471. #define MI_ZERO_USED_PAGETABLE_ENTRIES_IN_INPAGE_SUPPORT(INPAGE_SUPPORT) \
  1472. (INPAGE_SUPPORT)->UsedPageTableEntries = 0;
  1473. #define MI_ZERO_USED_PAGETABLE_ENTRIES_IN_PFN(PFN) (PFN)->UsedPageTableEntries = 0;
  1474. #define MI_INSERT_USED_PAGETABLE_ENTRIES_IN_PFN(PFN, INPAGE_SUPPORT) \
  1475. ASSERT ((INPAGE_SUPPORT)->UsedPageTableEntries <= PTE_PER_PAGE); \
  1476. (PFN)->UsedPageTableEntries = (INPAGE_SUPPORT)->UsedPageTableEntries;
  1477. #define MI_ZERO_USED_PAGETABLE_ENTRIES(PFN) \
  1478. (PFN)->UsedPageTableEntries = 0;
  1479. #define MI_CHECK_USED_PTES_HANDLE(VA) \
  1480. ASSERT (MiGetPdeAddress(VA)->u.Hard.Valid == 1);
  1481. #define MI_GET_USED_PTES_HANDLE(VA) \
  1482. ((PVOID)MI_PFN_ELEMENT((PFN_NUMBER)MiGetPdeAddress(VA)->u.Hard.PageFrameNumber))
  1483. #define MI_GET_USED_PTES_FROM_HANDLE(PFN) \
  1484. ((ULONG)(((PMMPFN)(PFN))->UsedPageTableEntries))
  1485. #define MI_INCREMENT_USED_PTES_BY_HANDLE(PFN) \
  1486. (((PMMPFN)(PFN))->UsedPageTableEntries += 1); \
  1487. ASSERT (((PMMPFN)(PFN))->UsedPageTableEntries <= PTE_PER_PAGE)
  1488. #define MI_INCREMENT_USED_PTES_BY_HANDLE_CLUSTER(PFN,INCR) \
  1489. (((PMMPFN)(PFN))->UsedPageTableEntries += (ULONG)(INCR)); \
  1490. ASSERT (((PMMPFN)(PFN))->UsedPageTableEntries <= PTE_PER_PAGE)
  1491. #define MI_DECREMENT_USED_PTES_BY_HANDLE(PFN) \
  1492. (((PMMPFN)(PFN))->UsedPageTableEntries -= 1); \
  1493. ASSERT (((PMMPFN)(PFN))->UsedPageTableEntries < PTE_PER_PAGE)
  1494. #else
  1495. #define MI_CAPTURE_USED_PAGETABLE_ENTRIES(PFN)
  1496. #define MI_RETRIEVE_USED_PAGETABLE_ENTRIES_FROM_PTE(RBL, PTE)
  1497. #define MI_ZERO_USED_PAGETABLE_ENTRIES_IN_INPAGE_SUPPORT(INPAGE_SUPPORT)
  1498. #define MI_ZERO_USED_PAGETABLE_ENTRIES_IN_PFN(PFN)
  1499. #define MI_INSERT_USED_PAGETABLE_ENTRIES_IN_PFN(PFN, INPAGE_SUPPORT)
  1500. #define MI_CHECK_USED_PTES_HANDLE(VA)
  1501. #define MI_GET_USED_PTES_HANDLE(VA) ((PVOID)&MmWorkingSetList->UsedPageTableEntries[MiGetPdeIndex(VA)])
  1502. #define MI_GET_USED_PTES_FROM_HANDLE(PDSHORT) ((ULONG)(*(PUSHORT)(PDSHORT)))
  1503. #define MI_INCREMENT_USED_PTES_BY_HANDLE(PDSHORT) \
  1504. ((*(PUSHORT)(PDSHORT)) += 1); \
  1505. ASSERT (((*(PUSHORT)(PDSHORT)) <= PTE_PER_PAGE))
  1506. #define MI_INCREMENT_USED_PTES_BY_HANDLE_CLUSTER(PDSHORT,INCR) \
  1507. (*(PUSHORT)(PDSHORT)) = (USHORT)((*(PUSHORT)(PDSHORT)) + (INCR)); \
  1508. ASSERT (((*(PUSHORT)(PDSHORT)) <= PTE_PER_PAGE))
  1509. #define MI_DECREMENT_USED_PTES_BY_HANDLE(PDSHORT) \
  1510. ((*(PUSHORT)(PDSHORT)) -= 1); \
  1511. ASSERT (((*(PUSHORT)(PDSHORT)) < PTE_PER_PAGE))
  1512. #endif
  1513. extern PFN_NUMBER MmDynamicPfn;
  1514. extern KGUARDED_MUTEX MmDynamicMemoryMutex;
  1515. //
  1516. // Cache attribute tracking for I/O space mappings.
  1517. //
  1518. #define MI_IO_BACKTRACE_LENGTH 6
  1519. typedef struct _MMIO_TRACKER {
  1520. LIST_ENTRY ListEntry;
  1521. PVOID BaseVa;
  1522. PFN_NUMBER PageFrameIndex;
  1523. PFN_NUMBER NumberOfPages;
  1524. MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
  1525. PVOID StackTrace[MI_IO_BACKTRACE_LENGTH];
  1526. } MMIO_TRACKER, *PMMIO_TRACKER;
  1527. extern KSPIN_LOCK MmIoTrackerLock;
  1528. extern LIST_ENTRY MmIoHeader;
  1529. extern PCHAR MiCacheStrings[];
  1530. MI_PFN_CACHE_ATTRIBUTE
  1531. MiInsertIoSpaceMap (
  1532. IN PVOID BaseVa,
  1533. IN PFN_NUMBER PageFrameIndex,
  1534. IN PFN_NUMBER NumberOfPages,
  1535. IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
  1536. );
  1537. //
  1538. // Total number of committed pages.
  1539. //
  1540. extern SIZE_T MmTotalCommittedPages;
  1541. extern SIZE_T MmTotalCommitLimit;
  1542. extern SIZE_T MmSharedCommit;
  1543. #if DBG
  1544. extern SPFN_NUMBER MiLockedCommit;
  1545. #define MI_INCREMENT_LOCKED_COMMIT() \
  1546. MiLockedCommit += 1;
  1547. #define MI_DECREMENT_LOCKED_COMMIT() \
  1548. ASSERT (MiLockedCommit > 0); \
  1549. MiLockedCommit -= 1;
  1550. #else
  1551. #define MI_INCREMENT_LOCKED_COMMIT()
  1552. #define MI_DECREMENT_LOCKED_COMMIT()
  1553. #endif
  1554. #if defined(_WIN64)
  1555. #define MiChargeCommitmentRegardless() \
  1556. MI_INCREMENT_LOCKED_COMMIT(); \
  1557. InterlockedIncrement64 ((PLONGLONG) &MmTotalCommittedPages);
  1558. #define MiReturnCommitmentRegardless() \
  1559. MI_DECREMENT_LOCKED_COMMIT(); \
  1560. InterlockedDecrement64 ((PLONGLONG) &MmTotalCommittedPages);
  1561. #else
  1562. #define MiChargeCommitmentRegardless() \
  1563. MI_INCREMENT_LOCKED_COMMIT(); \
  1564. InterlockedIncrement ((PLONG) &MmTotalCommittedPages);
  1565. #define MiReturnCommitmentRegardless() \
  1566. MI_DECREMENT_LOCKED_COMMIT(); \
  1567. InterlockedDecrement ((PLONG) &MmTotalCommittedPages);
  1568. #endif
  1569. extern ULONG MiChargeCommitmentFailures[3]; // referenced also in mi.h macros.
  1570. FORCEINLINE
  1571. LOGICAL
  1572. MiChargeCommitmentPfnLockHeld (
  1573. IN LOGICAL Force
  1574. )
  1575. /*++
  1576. Routine Description:
  1577. This routine charges the specified commitment without attempting
  1578. to expand paging files and waiting for the expansion.
  1579. Arguments:
  1580. Force - Supplies TRUE if the lock is short-term and should be forced through
  1581. if necessary.
  1582. Return Value:
  1583. TRUE if the commitment was permitted, FALSE if not.
  1584. Environment:
  1585. Kernel mode, PFN lock is held.
  1586. --*/
  1587. {
  1588. if (MmTotalCommittedPages > MmTotalCommitLimit - 64) {
  1589. if ((Force == 0) && (PsGetCurrentThread()->MemoryMaker == 0)) {
  1590. MiChargeCommitmentFailures[2] += 1;
  1591. return FALSE;
  1592. }
  1593. }
  1594. //
  1595. // No need to do an InterlockedCompareExchange for this, keep it fast.
  1596. //
  1597. MiChargeCommitmentRegardless ();
  1598. return TRUE;
  1599. }
  1600. extern PFN_NUMBER MmSystemLockPagesCount;
  1601. #if DBG
  1602. #define MI_LOCK_ID_COUNTER_MAX 64
  1603. ULONG MiLockIds[MI_LOCK_ID_COUNTER_MAX];
  1604. #define MI_MARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId) \
  1605. ASSERT (Pfn->u4.LockCharged == 0); \
  1606. ASSERT (CallerId < MI_LOCK_ID_COUNTER_MAX); \
  1607. MiLockIds[CallerId] += 1; \
  1608. Pfn->u4.LockCharged = 1;
  1609. #define MI_UNMARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId) \
  1610. ASSERT (Pfn->u4.LockCharged == 1); \
  1611. ASSERT (CallerId < MI_LOCK_ID_COUNTER_MAX); \
  1612. MiLockIds[CallerId] += 1; \
  1613. Pfn->u4.LockCharged = 0;
  1614. #else
  1615. #define MI_MARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId)
  1616. #define MI_UNMARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId)
  1617. #endif
  1618. FORCEINLINE
  1619. LOGICAL
  1620. MI_ADD_LOCKED_PAGE_CHARGE (
  1621. IN PMMPFN Pfn1,
  1622. IN LOGICAL Force,
  1623. IN ULONG CallerId
  1624. )
  1625. /*++
  1626. Routine Description:
  1627. Charge the systemwide count of locked pages if this is the initial
  1628. lock for this page (multiple concurrent locks are only charged once).
  1629. Arguments:
  1630. Pfn - Supplies the PFN index to operate on.
  1631. Force - Supplies TRUE if the lock is short-term and should be forced through
  1632. if necessary.
  1633. CallerId - Supplies the ID of the caller, only used in debug builds.
  1634. Return Value:
  1635. TRUE if the charge succeeded, FALSE if not.
  1636. Environment:
  1637. Kernel mode. PFN lock held.
  1638. --*/
  1639. {
  1640. #if !DBG
  1641. UNREFERENCED_PARAMETER (CallerId);
  1642. #endif
  1643. ASSERT (Pfn1->u3.e2.ReferenceCount != 0);
  1644. if (Pfn1->u3.e2.ReferenceCount == 1) {
  1645. if (Pfn1->u2.ShareCount != 0) {
  1646. ASSERT (Pfn1->u3.e1.PageLocation == ActiveAndValid);
  1647. if ((Pfn1->u3.e1.PrototypePte == 1) &&
  1648. (Pfn1->OriginalPte.u.Soft.Prototype == 1)) {
  1649. //
  1650. // This is a filesystem-backed page - charge commit for
  1651. // it as we have no way to tell when the caller will
  1652. // unlock the page.
  1653. //
  1654. if (MiChargeCommitmentPfnLockHeld (Force) == FALSE) {
  1655. return FALSE;
  1656. }
  1657. }
  1658. MI_MARK_PFN_AS_LOCK_CHARGED (Pfn1, CallerId);
  1659. MmSystemLockPagesCount += 1;
  1660. }
  1661. else {
  1662. ASSERT (Pfn1->u4.LockCharged == 1);
  1663. }
  1664. }
  1665. return TRUE;
  1666. }
  1667. FORCEINLINE
  1668. LOGICAL
  1669. MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (
  1670. IN PMMPFN Pfn1,
  1671. IN LOGICAL Force,
  1672. IN ULONG CallerId
  1673. )
  1674. /*++
  1675. Routine Description:
  1676. Charge the systemwide count of locked pages if this is the initial
  1677. lock for this page (multiple concurrent locks are only charged once).
  1678. Arguments:
  1679. Pfn - the PFN index to operate on.
  1680. Force - Supplies TRUE if the lock is short-term and should be forced through
  1681. if necessary.
  1682. CallerId - the ID of the caller, only used in debug builds.
  1683. Return Value:
  1684. TRUE if the charge succeeded, FALSE if not.
  1685. Environment:
  1686. Kernel mode. PFN lock held.
  1687. --*/
  1688. {
  1689. #if !DBG
  1690. UNREFERENCED_PARAMETER (CallerId);
  1691. #endif
  1692. ASSERT (Pfn1->u3.e1.PageLocation != ActiveAndValid);
  1693. ASSERT (Pfn1->u2.ShareCount == 0);
  1694. if (Pfn1->u3.e2.ReferenceCount == 0) {
  1695. if ((Pfn1->u3.e1.PrototypePte == 1) &&
  1696. (Pfn1->OriginalPte.u.Soft.Prototype == 1)) {
  1697. //
  1698. // This is a filesystem-backed page - charge commit for
  1699. // it as we have no way to tell when the caller will
  1700. // unlock the page.
  1701. //
  1702. if (MiChargeCommitmentPfnLockHeld (Force) == FALSE) {
  1703. return FALSE;
  1704. }
  1705. }
  1706. MI_MARK_PFN_AS_LOCK_CHARGED(Pfn1, CallerId);
  1707. MmSystemLockPagesCount += 1;
  1708. }
  1709. return TRUE;
  1710. }
  1711. //++
  1712. //
  1713. // VOID
  1714. // MI_REMOVE_LOCKED_PAGE_CHARGE (
  1715. // IN PMMPFN Pfn
  1716. // )
  1717. //
  1718. // Routine Description:
  1719. //
  1720. // Remove the charge from the systemwide count of locked pages if this
  1721. // is the last lock for this page (multiple concurrent locks are only
  1722. // charged once).
  1723. //
  1724. // The PFN reference checks are carefully ordered so the most common case
  1725. // is handled first, the next most common case next, etc. The case of
  1726. // a reference count of 2 occurs more than 1000x (yes, 3 orders of
  1727. // magnitude) more than a reference count of 1. And reference counts of >2
  1728. // occur 3 orders of magnitude more frequently than reference counts of
  1729. // exactly 1.
  1730. //
  1731. // Arguments:
  1732. //
  1733. // Pfn - the PFN index to operate on.
  1734. //
  1735. // Return Value:
  1736. //
  1737. // None.
  1738. //
  1739. //--
  1740. //
  1741. #define MI_REMOVE_LOCKED_PAGE_CHARGE(Pfn, CallerId) \
  1742. ASSERT (Pfn->u3.e2.ReferenceCount != 0); \
  1743. if (Pfn->u3.e2.ReferenceCount == 2) { \
  1744. if (Pfn->u2.ShareCount >= 1) { \
  1745. ASSERT (Pfn->u3.e1.PageLocation == ActiveAndValid); \
  1746. MI_UNMARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId); \
  1747. if ((Pfn->u3.e1.PrototypePte == 1) && \
  1748. (Pfn->OriginalPte.u.Soft.Prototype == 1)) { \
  1749. MiReturnCommitmentRegardless(); \
  1750. } \
  1751. MmSystemLockPagesCount -= 1; \
  1752. } \
  1753. else { \
  1754. /* \
  1755. * There are multiple referencers to this page and the \
  1756. * page is no longer valid in any process address space. \
  1757. * The systemwide lock count can only be decremented \
  1758. * by the last dereference. \
  1759. */ \
  1760. NOTHING; \
  1761. } \
  1762. } \
  1763. else if (Pfn->u3.e2.ReferenceCount != 1) { \
  1764. /* \
  1765. * There are still multiple referencers to this page (it may \
  1766. * or may not be resident in any process address space). \
  1767. * Since the systemwide lock count can only be decremented \
  1768. * by the last dereference (and this is not it), no action \
  1769. * is taken here. \
  1770. */ \
  1771. ASSERT (Pfn->u3.e2.ReferenceCount > 2); \
  1772. NOTHING; \
  1773. } \
  1774. else { \
  1775. /* \
  1776. * This page has already been deleted from all process address \
  1777. * spaces. It is sitting in limbo (not on any list) awaiting \
  1778. * this last dereference. \
  1779. */ \
  1780. ASSERT (Pfn->u3.e2.ReferenceCount == 1); \
  1781. ASSERT (Pfn->u3.e1.PageLocation != ActiveAndValid); \
  1782. ASSERT (Pfn->u2.ShareCount == 0); \
  1783. MI_UNMARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId); \
  1784. if ((Pfn->u3.e1.PrototypePte == 1) && \
  1785. (Pfn->OriginalPte.u.Soft.Prototype == 1)) { \
  1786. MiReturnCommitmentRegardless(); \
  1787. } \
  1788. MmSystemLockPagesCount -= 1; \
  1789. }
  1790. //++
  1791. //
  1792. // VOID
  1793. // MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (
  1794. // IN PMMPFN Pfn
  1795. // )
  1796. //
  1797. // Routine Description:
  1798. //
  1799. // Remove the charge from the systemwide count of locked pages if this
  1800. // is the last lock for this page (multiple concurrent locks are only
  1801. // charged once).
  1802. //
  1803. // The PFN reference checks are carefully ordered so the most common case
  1804. // is handled first, the next most common case next, etc. The case of
  1805. // a reference count of 2 occurs more than 1000x (yes, 3 orders of
  1806. // magnitude) more than a reference count of 1. And reference counts of >2
  1807. // occur 3 orders of magnitude more frequently than reference counts of
  1808. // exactly 1.
  1809. //
  1810. // The PFN reference count is then decremented.
  1811. //
  1812. // Arguments:
  1813. //
  1814. // Pfn - the PFN index to operate on.
  1815. //
  1816. // Return Value:
  1817. //
  1818. // None.
  1819. //
  1820. //--
  1821. //
  1822. #define MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF(Pfn, CallerId) \
  1823. ASSERT (Pfn->u3.e2.ReferenceCount != 0); \
  1824. if (Pfn->u3.e2.ReferenceCount == 2) { \
  1825. if (Pfn->u2.ShareCount >= 1) { \
  1826. ASSERT (Pfn->u3.e1.PageLocation == ActiveAndValid); \
  1827. MI_UNMARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId); \
  1828. if ((Pfn->u3.e1.PrototypePte == 1) && \
  1829. (Pfn->OriginalPte.u.Soft.Prototype == 1)) { \
  1830. MiReturnCommitmentRegardless(); \
  1831. } \
  1832. MmSystemLockPagesCount -= 1; \
  1833. } \
  1834. else { \
  1835. /* \
  1836. * There are multiple referencers to this page and the \
  1837. * page is no longer valid in any process address space. \
  1838. * The systemwide lock count can only be decremented \
  1839. * by the last dereference. \
  1840. */ \
  1841. NOTHING; \
  1842. } \
  1843. Pfn->u3.e2.ReferenceCount -= 1; \
  1844. } \
  1845. else if (Pfn->u3.e2.ReferenceCount != 1) { \
  1846. /* \
  1847. * There are still multiple referencers to this page (it may \
  1848. * or may not be resident in any process address space). \
  1849. * Since the systemwide lock count can only be decremented \
  1850. * by the last dereference (and this is not it), no action \
  1851. * is taken here. \
  1852. */ \
  1853. ASSERT (Pfn->u3.e2.ReferenceCount > 2); \
  1854. Pfn->u3.e2.ReferenceCount -= 1; \
  1855. } \
  1856. else { \
  1857. /* \
  1858. * This page has already been deleted from all process address \
  1859. * spaces. It is sitting in limbo (not on any list) awaiting \
  1860. * this last dereference. \
  1861. */ \
  1862. PFN_NUMBER _PageFrameIndex; \
  1863. ASSERT (Pfn->u3.e2.ReferenceCount == 1); \
  1864. ASSERT (Pfn->u3.e1.PageLocation != ActiveAndValid); \
  1865. ASSERT (Pfn->u2.ShareCount == 0); \
  1866. MI_UNMARK_PFN_AS_LOCK_CHARGED(Pfn, CallerId); \
  1867. if ((Pfn->u3.e1.PrototypePte == 1) && \
  1868. (Pfn->OriginalPte.u.Soft.Prototype == 1)) { \
  1869. MiReturnCommitmentRegardless(); \
  1870. } \
  1871. MmSystemLockPagesCount -= 1; \
  1872. _PageFrameIndex = MI_PFN_ELEMENT_TO_INDEX(Pfn); \
  1873. MiDecrementReferenceCount (Pfn, _PageFrameIndex); \
  1874. }
  1875. //++
  1876. //
  1877. // VOID
  1878. // MI_ZERO_WSINDEX (
  1879. // IN PMMPFN Pfn
  1880. // )
  1881. //
  1882. // Routine Description:
  1883. //
  1884. // Zero the Working Set Index field of the argument PFN entry.
  1885. // There is a subtlety here on systems where the WsIndex ULONG is
  1886. // overlaid with an Event pointer and sizeof(ULONG) != sizeof(PKEVENT).
  1887. // Note this will need to be updated if we ever decide to allocate bodies of
  1888. // thread objects on 4GB boundaries.
  1889. //
  1890. // Arguments:
  1891. //
  1892. // Pfn - the PFN index to operate on.
  1893. //
  1894. // Return Value:
  1895. //
  1896. // None.
  1897. //
  1898. //--
  1899. //
  1900. #define MI_ZERO_WSINDEX(Pfn) \
  1901. Pfn->u1.Event = NULL;
  1902. typedef enum _MMSHARE_TYPE {
  1903. Normal,
  1904. ShareCountOnly,
  1905. AndValid
  1906. } MMSHARE_TYPE;
  1907. typedef struct _MMWSLE_HASH {
  1908. PVOID Key;
  1909. WSLE_NUMBER Index;
  1910. } MMWSLE_HASH, *PMMWSLE_HASH;
  1911. //++
  1912. //
  1913. // WSLE_NUMBER
  1914. // MI_WSLE_HASH (
  1915. // IN ULONG_PTR VirtualAddress,
  1916. // IN PMMWSL WorkingSetList
  1917. // )
  1918. //
  1919. // Routine Description:
  1920. //
  1921. // Hash the address
  1922. //
  1923. // Arguments:
  1924. //
  1925. // VirtualAddress - the address to hash.
  1926. //
  1927. // WorkingSetList - the working set to hash the address into.
  1928. //
  1929. // Return Value:
  1930. //
  1931. // The hash key.
  1932. //
  1933. //--
  1934. //
  1935. #define MI_WSLE_HASH(Address, Wsl) \
  1936. ((WSLE_NUMBER)(((ULONG_PTR)PAGE_ALIGN(Address) >> (PAGE_SHIFT - 2)) % \
  1937. ((Wsl)->HashTableSize - 1)))
  1938. //
  1939. // Working Set List Entry.
  1940. //
  1941. typedef struct _MMWSLENTRY {
  1942. ULONG_PTR Valid : 1;
  1943. ULONG_PTR LockedInWs : 1;
  1944. ULONG_PTR LockedInMemory : 1;
  1945. ULONG_PTR Protection : 5;
  1946. ULONG_PTR SameProtectAsProto : 1;
  1947. ULONG_PTR Direct : 1;
  1948. ULONG_PTR Age : 2;
  1949. #if MM_VIRTUAL_PAGE_FILLER
  1950. ULONG_PTR Filler : MM_VIRTUAL_PAGE_FILLER;
  1951. #endif
  1952. ULONG_PTR VirtualPageNumber : MM_VIRTUAL_PAGE_SIZE;
  1953. } MMWSLENTRY;
  1954. typedef struct _MMWSLE {
  1955. union {
  1956. PVOID VirtualAddress;
  1957. ULONG_PTR Long;
  1958. MMWSLENTRY e1;
  1959. } u1;
  1960. } MMWSLE;
  1961. #define MI_GENERATE_VALID_WSLE(Wsle) \
  1962. ((PVOID)(ULONG_PTR)((Wsle)->u1.Long & (~(PAGE_SIZE - 1) | 0x1)))
  1963. #define MI_GET_PROTECTION_FROM_WSLE(Wsl) ((Wsl)->u1.e1.Protection)
  1964. typedef MMWSLE *PMMWSLE;
  1965. //
  1966. // Working Set List. Must be quadword sized.
  1967. //
  1968. typedef struct _MMWSL {
  1969. WSLE_NUMBER FirstFree;
  1970. WSLE_NUMBER FirstDynamic;
  1971. WSLE_NUMBER LastEntry;
  1972. WSLE_NUMBER NextSlot; // The next slot to trim
  1973. PMMWSLE Wsle;
  1974. WSLE_NUMBER LastInitializedWsle;
  1975. WSLE_NUMBER NonDirectCount;
  1976. PMMWSLE_HASH HashTable;
  1977. ULONG HashTableSize;
  1978. ULONG NumberOfCommittedPageTables;
  1979. PVOID HashTableStart;
  1980. PVOID HighestPermittedHashAddress;
  1981. ULONG NumberOfImageWaiters;
  1982. ULONG VadBitMapHint;
  1983. #if _WIN64
  1984. PVOID HighestUserAddress; // Maintained for wow64 processes only
  1985. #endif
  1986. #if defined(_MIALT4K_)
  1987. PMMPTE HighestUserPte;
  1988. PMMPTE HighestAltPte;
  1989. #endif
  1990. #if (_MI_PAGING_LEVELS >= 4)
  1991. PULONG CommittedPageTables;
  1992. ULONG NumberOfCommittedPageDirectories;
  1993. PULONG CommittedPageDirectories;
  1994. ULONG NumberOfCommittedPageDirectoryParents;
  1995. ULONG CommittedPageDirectoryParents[(MM_USER_PAGE_DIRECTORY_PARENT_PAGES + sizeof(ULONG)*8-1)/(sizeof(ULONG)*8)];
  1996. #elif (_MI_PAGING_LEVELS >= 3)
  1997. PULONG CommittedPageTables;
  1998. ULONG NumberOfCommittedPageDirectories;
  1999. ULONG CommittedPageDirectories[(MM_USER_PAGE_DIRECTORY_PAGES + sizeof(ULONG)*8-1)/(sizeof(ULONG)*8)];
  2000. #else
  2001. //
  2002. // This must be at the end.
  2003. // Not used in system cache or session working set lists.
  2004. //
  2005. USHORT UsedPageTableEntries[MM_USER_PAGE_TABLE_PAGES];
  2006. ULONG CommittedPageTables[MM_USER_PAGE_TABLE_PAGES/(sizeof(ULONG)*8)];
  2007. #endif
  2008. } MMWSL, *PMMWSL;
  2009. // #define _MI_DEBUG_WSLE 1 // Enable WSLE change logging
  2010. #if defined (_MI_DEBUG_WSLE)
  2011. #define MI_WSLE_BACKTRACE_LENGTH 8
  2012. typedef struct _MI_WSLE_TRACES {
  2013. PETHREAD Thread;
  2014. PVOID Pad0;
  2015. PMMWSLE Wsle;
  2016. MMWSLE WsleContents;
  2017. MMWSLE NewWsleContents;
  2018. WSLE_NUMBER WorkingSetSize;
  2019. WSLE_NUMBER Quota;
  2020. WSLE_NUMBER LastInitializedWsle;
  2021. PVOID StackTrace [MI_WSLE_BACKTRACE_LENGTH];
  2022. } MI_WSLE_TRACES, *PMI_WSLE_TRACES;
  2023. extern LONG MiWsleIndex;
  2024. #define MI_WSLE_TRACE_SIZE 0x1000
  2025. extern MI_WSLE_TRACES MiWsleTraces[MI_WSLE_TRACE_SIZE];
  2026. #if defined(_X86_)
  2027. extern PMMWSL MmWorkingSetList;
  2028. #endif
  2029. VOID
  2030. FORCEINLINE
  2031. MiSnapWsle (
  2032. IN PMMWSL WorkingSetList,
  2033. IN WSLE_NUMBER WorkingSetIndex,
  2034. IN MMWSLE WsleValue
  2035. )
  2036. {
  2037. PMMSUPPORT WsInfo;
  2038. ULONG Hash;
  2039. ULONG Index;
  2040. PMI_WSLE_TRACES Information;
  2041. PVOID MatchVa;
  2042. WSLE_NUMBER j;
  2043. PMMWSLE Wsle;
  2044. PEPROCESS Process;
  2045. if (WorkingSetList != MmWorkingSetList) {
  2046. return;
  2047. }
  2048. Process = PsGetCurrentProcess ();
  2049. Information = (PMI_WSLE_TRACES) Process->Spare3[0];
  2050. if (Information == NULL) {
  2051. return;
  2052. }
  2053. Wsle = WorkingSetList->Wsle;
  2054. if (WsleValue.u1.e1.Valid == 1) {
  2055. MatchVa = PAGE_ALIGN (WsleValue.u1.VirtualAddress);
  2056. for (j = 0; j <= WorkingSetList->LastInitializedWsle; j += 1) {
  2057. if ((Wsle->u1.e1.Valid == 1) &&
  2058. (PAGE_ALIGN (Wsle->u1.VirtualAddress) == MatchVa) &&
  2059. (j != WorkingSetIndex)) {
  2060. DbgPrint ("MMWSLE2: DUP %p %x %x\n", WsleValue, WorkingSetIndex, j);
  2061. DbgBreakPoint ();
  2062. }
  2063. Wsle += 1;
  2064. }
  2065. }
  2066. WsInfo = &Process->Vm;
  2067. Index = InterlockedIncrement ((PLONG)&Process->Spare3[1]);
  2068. Index &= (MI_WSLE_TRACE_SIZE - 1);
  2069. Information += Index;
  2070. Information->Thread = PsGetCurrentThread ();
  2071. Information->Wsle = &WorkingSetList->Wsle[WorkingSetIndex];
  2072. Information->WsleContents = WorkingSetList->Wsle[WorkingSetIndex];
  2073. Information->NewWsleContents = WsleValue;
  2074. Information->WorkingSetSize = WsInfo->WorkingSetSize;
  2075. Information->Quota = WorkingSetList->Quota;
  2076. Information->LastInitializedWsle = WorkingSetList->LastInitializedWsle;
  2077. if ((PointerPte < MiGetPteAddress (MmHighestUserAddress)) &&
  2078. (PointerPte >= MiGetPteAddress (0))) {
  2079. //
  2080. // The current thread must own this process' working set mutex.
  2081. //
  2082. ASSERT (MI_WS_OWNER (PsGetCurrentProcess()));
  2083. }
  2084. RtlZeroMemory (&Information->StackTrace[0], MI_WSLE_BACKTRACE_LENGTH * sizeof(PVOID));
  2085. #if defined (_WIN64)
  2086. if (KeAreAllApcsDisabled () == TRUE) {
  2087. Information->StackTrace[1] = (PVOID) _ReturnAddress ();
  2088. Information->StackTrace[0] = MiGetInstructionPointer ();
  2089. }
  2090. else
  2091. #endif
  2092. RtlCaptureStackBackTrace (0, MI_WSLE_BACKTRACE_LENGTH, Information->StackTrace, &Hash);
  2093. }
  2094. #define MI_LOG_WSLE_CHANGE(_WorkingSetList, _WorkingSetIndex, _WsleValue) MiSnapWsle(_WorkingSetList, _WorkingSetIndex, _WsleValue)
  2095. #else
  2096. #define MI_LOG_WSLE_CHANGE(_WorkingSetList, _WorkingSetIndex, _WsleValue)
  2097. #endif
  2098. #if defined(_X86_)
  2099. extern PMMWSL MmWorkingSetList;
  2100. #endif
  2101. extern PKEVENT MiHighMemoryEvent;
  2102. extern PKEVENT MiLowMemoryEvent;
  2103. //
  2104. // The claim estimate of unused pages in a working set is limited
  2105. // to grow by this amount per estimation period.
  2106. //
  2107. #define MI_CLAIM_INCR 30
  2108. //
  2109. // The maximum number of different ages a page can be.
  2110. //
  2111. #define MI_USE_AGE_COUNT 4
  2112. #define MI_USE_AGE_MAX (MI_USE_AGE_COUNT - 1)
  2113. //
  2114. // If more than this "percentage" of the working set is estimated to
  2115. // be used then allow it to grow freely.
  2116. //
  2117. #define MI_REPLACEMENT_FREE_GROWTH_SHIFT 5
  2118. //
  2119. // If more than this "percentage" of the working set has been claimed
  2120. // then force replacement in low memory.
  2121. //
  2122. #define MI_REPLACEMENT_CLAIM_THRESHOLD_SHIFT 3
  2123. //
  2124. // If more than this "percentage" of the working set is estimated to
  2125. // be available then force replacement in low memory.
  2126. //
  2127. #define MI_REPLACEMENT_EAVAIL_THRESHOLD_SHIFT 3
  2128. //
  2129. // If while doing replacement a page is found of this age or older then
  2130. // replace it. Otherwise the oldest is selected.
  2131. //
  2132. #define MI_IMMEDIATE_REPLACEMENT_AGE 2
  2133. //
  2134. // When trimming, use these ages for different passes.
  2135. //
  2136. #define MI_MAX_TRIM_PASSES 4
  2137. #define MI_PASS0_TRIM_AGE 2
  2138. #define MI_PASS1_TRIM_AGE 1
  2139. #define MI_PASS2_TRIM_AGE 1
  2140. #define MI_PASS3_TRIM_AGE 1
  2141. #define MI_PASS4_TRIM_AGE 0
  2142. //
  2143. // If not a forced trim, trim pages older than this age.
  2144. //
  2145. #define MI_TRIM_AGE_THRESHOLD 2
  2146. //
  2147. // This "percentage" of a claim is up for grabs in a foreground process.
  2148. //
  2149. #define MI_FOREGROUND_CLAIM_AVAILABLE_SHIFT 3
  2150. //
  2151. // This "percentage" of a claim is up for grabs in a background process.
  2152. //
  2153. #define MI_BACKGROUND_CLAIM_AVAILABLE_SHIFT 1
  2154. //++
  2155. //
  2156. // DWORD
  2157. // MI_CALC_NEXT_VALID_ESTIMATION_SLOT (
  2158. // DWORD Previous,
  2159. // DWORD Minimum,
  2160. // DWORD Maximum,
  2161. // MI_NEXT_ESTIMATION_SLOT_CONST NextEstimationSlotConst,
  2162. // PMMWSLE Wsle
  2163. // )
  2164. //
  2165. // Routine Description:
  2166. //
  2167. // We iterate through the working set array in a non-sequential
  2168. // manner so that the sample is independent of any aging or trimming.
  2169. //
  2170. // This algorithm walks through the working set with a stride of
  2171. // 2^MiEstimationShift elements.
  2172. //
  2173. // Arguments:
  2174. //
  2175. // Previous - Last slot used
  2176. //
  2177. // Minimum - Minimum acceptable slot (ie. the first dynamic one)
  2178. //
  2179. // Maximum - max slot number + 1
  2180. //
  2181. // NextEstimationSlotConst - for this algorithm it contains the stride
  2182. //
  2183. // Wsle - the working set array
  2184. //
  2185. // Return Value:
  2186. //
  2187. // Next slot.
  2188. //
  2189. // Environment:
  2190. //
  2191. // Kernel mode, APCs disabled, working set lock held and PFN lock held.
  2192. //
  2193. //--
  2194. typedef struct _MI_NEXT_ESTIMATION_SLOT_CONST {
  2195. WSLE_NUMBER Stride;
  2196. } MI_NEXT_ESTIMATION_SLOT_CONST;
  2197. #define MI_CALC_NEXT_ESTIMATION_SLOT_CONST(NextEstimationSlotConst, WorkingSetList) \
  2198. (NextEstimationSlotConst).Stride = 1 << MiEstimationShift;
  2199. #define MI_NEXT_VALID_ESTIMATION_SLOT(Previous, StartEntry, Minimum, Maximum, NextEstimationSlotConst, Wsle) \
  2200. ASSERT(((Previous) >= Minimum) && ((Previous) <= Maximum)); \
  2201. ASSERT(((StartEntry) >= Minimum) && ((StartEntry) <= Maximum)); \
  2202. do { \
  2203. (Previous) += (NextEstimationSlotConst).Stride; \
  2204. if ((Previous) > Maximum) { \
  2205. (Previous) = Minimum + ((Previous + 1) & (NextEstimationSlotConst.Stride - 1)); \
  2206. StartEntry += 1; \
  2207. (Previous) = StartEntry; \
  2208. } \
  2209. if ((Previous) > Maximum || (Previous) < Minimum) { \
  2210. StartEntry = Minimum; \
  2211. (Previous) = StartEntry; \
  2212. } \
  2213. } while (Wsle[Previous].u1.e1.Valid == 0);
  2214. //++
  2215. //
  2216. // WSLE_NUMBER
  2217. // MI_NEXT_VALID_AGING_SLOT (
  2218. // DWORD Previous,
  2219. // DWORD Minimum,
  2220. // DWORD Maximum,
  2221. // PMMWSLE Wsle
  2222. // )
  2223. //
  2224. // Routine Description:
  2225. //
  2226. // This finds the next slot to valid slot to age. It walks
  2227. // through the slots sequentialy.
  2228. //
  2229. // Arguments:
  2230. //
  2231. // Previous - Last slot used
  2232. //
  2233. // Minimum - Minimum acceptable slot (ie. the first dynamic one)
  2234. //
  2235. // Maximum - Max slot number + 1
  2236. //
  2237. // Wsle - the working set array
  2238. //
  2239. // Return Value:
  2240. //
  2241. // None.
  2242. //
  2243. // Environment:
  2244. //
  2245. // Kernel mode, APCs disabled, working set lock held and PFN lock held.
  2246. //
  2247. //--
  2248. #define MI_NEXT_VALID_AGING_SLOT(Previous, Minimum, Maximum, Wsle) \
  2249. ASSERT(((Previous) >= Minimum) && ((Previous) <= Maximum)); \
  2250. do { \
  2251. (Previous) += 1; \
  2252. if ((Previous) > Maximum) { \
  2253. Previous = Minimum; \
  2254. } \
  2255. } while ((Wsle[Previous].u1.e1.Valid == 0));
  2256. //++
  2257. //
  2258. // ULONG
  2259. // MI_CALCULATE_USAGE_ESTIMATE (
  2260. // IN PULONG SampledAgeCounts.
  2261. // IN ULONG CounterShift
  2262. // )
  2263. //
  2264. // Routine Description:
  2265. //
  2266. // In Usage Estimation, we count the number of pages of each age in
  2267. // a sample. The function turns the SampledAgeCounts into an
  2268. // estimate of the unused pages.
  2269. //
  2270. // Arguments:
  2271. //
  2272. // SampledAgeCounts - counts of pages of each different age in the sample
  2273. //
  2274. // CounterShift - shift necessary to apply sample to entire WS
  2275. //
  2276. // Return Value:
  2277. //
  2278. // The number of pages to walk in the working set to get a good
  2279. // estimate of the number available.
  2280. //
  2281. //--
  2282. #define MI_CALCULATE_USAGE_ESTIMATE(SampledAgeCounts, CounterShift) \
  2283. (((SampledAgeCounts)[1] + \
  2284. (SampledAgeCounts)[2] + (SampledAgeCounts)[3]) \
  2285. << (CounterShift))
  2286. //++
  2287. //
  2288. // VOID
  2289. // MI_RESET_WSLE_AGE (
  2290. // IN PMMPTE PointerPte,
  2291. // IN PMMWSLE Wsle
  2292. // )
  2293. //
  2294. // Routine Description:
  2295. //
  2296. // Clear the age counter for the working set entry.
  2297. //
  2298. // Arguments:
  2299. //
  2300. // PointerPte - pointer to the working set list entry's PTE.
  2301. //
  2302. // Wsle - pointer to the working set list entry.
  2303. //
  2304. // Return Value:
  2305. //
  2306. // None.
  2307. //
  2308. //--
  2309. #define MI_RESET_WSLE_AGE(PointerPte, Wsle) \
  2310. (Wsle)->u1.e1.Age = 0;
  2311. //++
  2312. //
  2313. // ULONG
  2314. // MI_GET_WSLE_AGE (
  2315. // IN PMMPTE PointerPte,
  2316. // IN PMMWSLE Wsle
  2317. // )
  2318. //
  2319. // Routine Description:
  2320. //
  2321. // Clear the age counter for the working set entry.
  2322. //
  2323. // Arguments:
  2324. //
  2325. // PointerPte - pointer to the working set list entry's PTE
  2326. // Wsle - pointer to the working set list entry
  2327. //
  2328. // Return Value:
  2329. //
  2330. // Age group of the working set entry
  2331. //
  2332. //--
  2333. #define MI_GET_WSLE_AGE(PointerPte, Wsle) \
  2334. ((ULONG)((Wsle)->u1.e1.Age))
  2335. //++
  2336. //
  2337. // VOID
  2338. // MI_INC_WSLE_AGE (
  2339. // IN PMMPTE PointerPte,
  2340. // IN PMMWSLE Wsle,
  2341. // )
  2342. //
  2343. // Routine Description:
  2344. //
  2345. // Increment the age counter for the working set entry.
  2346. //
  2347. // Arguments:
  2348. //
  2349. // PointerPte - pointer to the working set list entry's PTE.
  2350. //
  2351. // Wsle - pointer to the working set list entry.
  2352. //
  2353. // Return Value:
  2354. //
  2355. // None
  2356. //
  2357. //--
  2358. #define MI_INC_WSLE_AGE(PointerPte, Wsle) \
  2359. if ((Wsle)->u1.e1.Age < 3) { \
  2360. (Wsle)->u1.e1.Age += 1; \
  2361. }
  2362. //++
  2363. //
  2364. // VOID
  2365. // MI_UPDATE_USE_ESTIMATE (
  2366. // IN PMMPTE PointerPte,
  2367. // IN PMMWSLE Wsle,
  2368. // IN ULONG *SampledAgeCounts
  2369. // )
  2370. //
  2371. // Routine Description:
  2372. //
  2373. // Update the sampled age counts.
  2374. //
  2375. // Arguments:
  2376. //
  2377. // PointerPte - pointer to the working set list entry's PTE.
  2378. //
  2379. // Wsle - pointer to the working set list entry.
  2380. //
  2381. // SampledAgeCounts - array of age counts to be updated.
  2382. //
  2383. // Return Value:
  2384. //
  2385. // None
  2386. //
  2387. //--
  2388. #define MI_UPDATE_USE_ESTIMATE(PointerPte, Wsle, SampledAgeCounts) \
  2389. (SampledAgeCounts)[(Wsle)->u1.e1.Age] += 1;
  2390. //++
  2391. //
  2392. // BOOLEAN
  2393. // MI_WS_GROWING_TOO_FAST (
  2394. // IN PMMSUPPORT VmSupport
  2395. // )
  2396. //
  2397. // Routine Description:
  2398. //
  2399. // Limit the growth rate of processes as the
  2400. // available memory approaches zero. Note the caller must ensure that
  2401. // MmAvailablePages is low enough so this calculation does not wrap.
  2402. //
  2403. // Arguments:
  2404. //
  2405. // VmSupport - a working set.
  2406. //
  2407. // Return Value:
  2408. //
  2409. // TRUE if the growth rate is too fast, FALSE otherwise.
  2410. //
  2411. //--
  2412. #define MI_WS_GROWING_TOO_FAST(VmSupport) \
  2413. ((VmSupport)->GrowthSinceLastEstimate > \
  2414. (((MI_CLAIM_INCR * (MmAvailablePages*MmAvailablePages)) / (64*64)) + 1))
  2415. #define SECTION_BASE_ADDRESS(_NtSection) \
  2416. (*((PVOID *)&(_NtSection)->PointerToRelocations))
  2417. #define SECTION_LOCK_COUNT_POINTER(_NtSection) \
  2418. ((PLONG)&(_NtSection)->NumberOfRelocations)
  2419. //
  2420. // Memory Management Object structures.
  2421. //
  2422. typedef enum _SECTION_CHECK_TYPE {
  2423. CheckDataSection,
  2424. CheckImageSection,
  2425. CheckUserDataSection,
  2426. CheckBothSection
  2427. } SECTION_CHECK_TYPE;
  2428. typedef struct _MMEXTEND_INFO {
  2429. UINT64 CommittedSize;
  2430. ULONG ReferenceCount;
  2431. } MMEXTEND_INFO, *PMMEXTEND_INFO;
  2432. typedef struct _SEGMENT_FLAGS {
  2433. ULONG_PTR TotalNumberOfPtes4132 : 10;
  2434. ULONG_PTR ExtraSharedWowSubsections : 1;
  2435. #if defined (_WIN64)
  2436. ULONG_PTR Spare : 53;
  2437. #else
  2438. ULONG_PTR Spare : 21;
  2439. #endif
  2440. } SEGMENT_FLAGS, *PSEGMENT_FLAGS;
  2441. typedef struct _SEGMENT {
  2442. struct _CONTROL_AREA *ControlArea;
  2443. ULONG TotalNumberOfPtes;
  2444. ULONG NonExtendedPtes;
  2445. ULONG WritableUserReferences;
  2446. UINT64 SizeOfSegment;
  2447. MMPTE SegmentPteTemplate;
  2448. SIZE_T NumberOfCommittedPages;
  2449. PMMEXTEND_INFO ExtendInfo;
  2450. SEGMENT_FLAGS SegmentFlags;
  2451. PVOID BasedAddress;
  2452. //
  2453. // The fields below are for image & pagefile-backed sections only.
  2454. // Common fields are above and new common entries must be added to
  2455. // both the SEGMENT and MAPPED_FILE_SEGMENT declarations.
  2456. //
  2457. union {
  2458. SIZE_T ImageCommitment; // for image-backed sections only
  2459. PEPROCESS CreatingProcess; // for pagefile-backed sections only
  2460. } u1;
  2461. union {
  2462. PSECTION_IMAGE_INFORMATION ImageInformation; // for images only
  2463. PVOID FirstMappedVa; // for pagefile-backed sections only
  2464. } u2;
  2465. PMMPTE PrototypePte;
  2466. MMPTE ThePtes[MM_PROTO_PTE_ALIGNMENT / PAGE_SIZE];
  2467. } SEGMENT, *PSEGMENT;
  2468. typedef struct _MAPPED_FILE_SEGMENT {
  2469. struct _CONTROL_AREA *ControlArea;
  2470. ULONG TotalNumberOfPtes;
  2471. ULONG NonExtendedPtes;
  2472. ULONG WritableUserReferences;
  2473. UINT64 SizeOfSegment;
  2474. MMPTE SegmentPteTemplate;
  2475. SIZE_T NumberOfCommittedPages;
  2476. PMMEXTEND_INFO ExtendInfo;
  2477. SEGMENT_FLAGS SegmentFlags;
  2478. PVOID BasedAddress;
  2479. struct _MSUBSECTION *LastSubsectionHint;
  2480. } MAPPED_FILE_SEGMENT, *PMAPPED_FILE_SEGMENT;
  2481. typedef struct _EVENT_COUNTER {
  2482. SLIST_ENTRY ListEntry;
  2483. ULONG RefCount;
  2484. KEVENT Event;
  2485. } EVENT_COUNTER, *PEVENT_COUNTER;
  2486. typedef struct _MMSECTION_FLAGS {
  2487. unsigned BeingDeleted : 1;
  2488. unsigned BeingCreated : 1;
  2489. unsigned BeingPurged : 1;
  2490. unsigned NoModifiedWriting : 1;
  2491. unsigned FailAllIo : 1;
  2492. unsigned Image : 1;
  2493. unsigned Based : 1;
  2494. unsigned File : 1;
  2495. unsigned Networked : 1;
  2496. unsigned NoCache : 1;
  2497. unsigned PhysicalMemory : 1;
  2498. unsigned CopyOnWrite : 1;
  2499. unsigned Reserve : 1; // not a spare bit!
  2500. unsigned Commit : 1;
  2501. unsigned FloppyMedia : 1;
  2502. unsigned WasPurged : 1;
  2503. unsigned UserReference : 1;
  2504. unsigned GlobalMemory : 1;
  2505. unsigned DeleteOnClose : 1;
  2506. unsigned FilePointerNull : 1;
  2507. unsigned DebugSymbolsLoaded : 1;
  2508. unsigned SetMappedFileIoComplete : 1;
  2509. unsigned CollidedFlush : 1;
  2510. unsigned NoChange : 1;
  2511. unsigned HadUserReference : 1;
  2512. unsigned ImageMappedInSystemSpace : 1;
  2513. unsigned UserWritable : 1;
  2514. unsigned Accessed : 1;
  2515. unsigned GlobalOnlyPerSession : 1;
  2516. unsigned Rom : 1;
  2517. unsigned filler : 2;
  2518. } MMSECTION_FLAGS;
  2519. typedef struct _CONTROL_AREA {
  2520. PSEGMENT Segment;
  2521. LIST_ENTRY DereferenceList;
  2522. ULONG NumberOfSectionReferences; // All section refs & image flushes
  2523. ULONG NumberOfPfnReferences; // valid + transition prototype PTEs
  2524. ULONG NumberOfMappedViews; // total # mapped views, including
  2525. // system cache & system space views
  2526. ULONG NumberOfSystemCacheViews; // system cache views only
  2527. ULONG NumberOfUserReferences; // user section & view references
  2528. union {
  2529. ULONG LongFlags;
  2530. MMSECTION_FLAGS Flags;
  2531. } u;
  2532. PFILE_OBJECT FilePointer;
  2533. PEVENT_COUNTER WaitingForDeletion;
  2534. USHORT ModifiedWriteCount;
  2535. USHORT FlushInProgressCount;
  2536. } CONTROL_AREA, *PCONTROL_AREA;
  2537. typedef struct _LARGE_CONTROL_AREA {
  2538. PSEGMENT Segment;
  2539. LIST_ENTRY DereferenceList;
  2540. ULONG NumberOfSectionReferences;
  2541. ULONG NumberOfPfnReferences;
  2542. ULONG NumberOfMappedViews;
  2543. USHORT NumberOfSubsections;
  2544. USHORT FlushInProgressCount;
  2545. ULONG NumberOfUserReferences;
  2546. union {
  2547. ULONG LongFlags;
  2548. MMSECTION_FLAGS Flags;
  2549. } u;
  2550. PFILE_OBJECT FilePointer;
  2551. PEVENT_COUNTER WaitingForDeletion;
  2552. USHORT ModifiedWriteCount;
  2553. USHORT NumberOfSystemCacheViews;
  2554. PFN_NUMBER StartingFrame; // only used if Flags.Rom == 1.
  2555. LIST_ENTRY UserGlobalList;
  2556. ULONG SessionId;
  2557. } LARGE_CONTROL_AREA, *PLARGE_CONTROL_AREA;
  2558. typedef struct _MMSUBSECTION_FLAGS {
  2559. unsigned ReadOnly : 1;
  2560. unsigned ReadWrite : 1;
  2561. unsigned SubsectionStatic : 1;
  2562. unsigned GlobalMemory: 1;
  2563. unsigned Protection : 5;
  2564. unsigned Spare : 1;
  2565. unsigned StartingSector4132 : 10; // 2 ** (42+12) == 4MB*4GB == 16K TB
  2566. unsigned SectorEndOffset : 12;
  2567. } MMSUBSECTION_FLAGS;
  2568. typedef struct _SUBSECTION { // Must start on quadword boundary and be quad sized
  2569. PCONTROL_AREA ControlArea;
  2570. union {
  2571. ULONG LongFlags;
  2572. MMSUBSECTION_FLAGS SubsectionFlags;
  2573. } u;
  2574. ULONG StartingSector;
  2575. ULONG NumberOfFullSectors; // (4GB-1) * 4K == 16TB-4K limit per subsection
  2576. #if defined(_MIALT4K_)
  2577. ULONG LastSplitPageProtection; // Protection of last split page in this
  2578. // subsection. This must be saved here
  2579. // because the final subsection may end
  2580. // on a split (merged) page and so we
  2581. // cannot just look forward to the next
  2582. // subsection in that case to obtain
  2583. // the correct permissions.
  2584. #endif
  2585. PMMPTE SubsectionBase;
  2586. ULONG UnusedPtes;
  2587. ULONG PtesInSubsection;
  2588. struct _SUBSECTION *NextSubsection;
  2589. } SUBSECTION, *PSUBSECTION;
  2590. extern const ULONG MMSECT;
  2591. //
  2592. // Accesses to MMSUBSECTION_FLAGS2 are synchronized via the PFN lock
  2593. // (unlike MMSUBSECTION_FLAGS access which is not lock protected at all).
  2594. //
  2595. typedef struct _MMSUBSECTION_FLAGS2 {
  2596. unsigned SubsectionAccessed : 1;
  2597. unsigned SubsectionConverted : 1; // only needed for debug
  2598. unsigned Reserved : 30;
  2599. } MMSUBSECTION_FLAGS2;
  2600. //
  2601. // Mapped data file subsection structure. Not used for images
  2602. // or pagefile-backed shared memory.
  2603. //
  2604. typedef struct _MSUBSECTION { // Must start on quadword boundary and be quad sized
  2605. PCONTROL_AREA ControlArea;
  2606. union {
  2607. ULONG LongFlags;
  2608. MMSUBSECTION_FLAGS SubsectionFlags;
  2609. } u;
  2610. ULONG StartingSector;
  2611. ULONG NumberOfFullSectors; // (4GB-1) * 4K == 16TB-4K limit per subsection
  2612. PMMPTE SubsectionBase;
  2613. ULONG UnusedPtes;
  2614. ULONG PtesInSubsection;
  2615. struct _SUBSECTION *NextSubsection;
  2616. LIST_ENTRY DereferenceList;
  2617. ULONG_PTR NumberOfMappedViews;
  2618. union {
  2619. ULONG LongFlags2;
  2620. MMSUBSECTION_FLAGS2 SubsectionFlags2;
  2621. } u2;
  2622. } MSUBSECTION, *PMSUBSECTION;
  2623. #define MI_MAXIMUM_SECTION_SIZE ((UINT64)16*1024*1024*1024*1024*1024 - ((UINT64)1<<MM4K_SHIFT))
  2624. VOID
  2625. MiDecrementSubsections (
  2626. IN PSUBSECTION FirstSubsection,
  2627. IN PSUBSECTION LastSubsection OPTIONAL
  2628. );
  2629. NTSTATUS
  2630. MiAddViewsForSectionWithPfn (
  2631. IN PMSUBSECTION StartMappedSubsection,
  2632. IN UINT64 LastPteOffset OPTIONAL
  2633. );
  2634. NTSTATUS
  2635. MiAddViewsForSection (
  2636. IN PMSUBSECTION MappedSubsection,
  2637. IN UINT64 LastPteOffset OPTIONAL,
  2638. IN KIRQL OldIrql,
  2639. OUT PULONG Waited
  2640. );
  2641. LOGICAL
  2642. MiReferenceSubsection (
  2643. IN PMSUBSECTION MappedSubsection
  2644. );
  2645. VOID
  2646. MiRemoveViewsFromSection (
  2647. IN PMSUBSECTION StartMappedSubsection,
  2648. IN UINT64 LastPteOffset OPTIONAL
  2649. );
  2650. VOID
  2651. MiRemoveViewsFromSectionWithPfn (
  2652. IN PMSUBSECTION StartMappedSubsection,
  2653. IN UINT64 LastPteOffset OPTIONAL
  2654. );
  2655. VOID
  2656. MiSubsectionConsistent(
  2657. IN PSUBSECTION Subsection
  2658. );
  2659. #if DBG
  2660. #define MI_CHECK_SUBSECTION(_subsection) MiSubsectionConsistent((PSUBSECTION)(_subsection))
  2661. #else
  2662. #define MI_CHECK_SUBSECTION(_subsection)
  2663. #endif
  2664. //++
  2665. //ULONG
  2666. //Mi4KStartForSubsection (
  2667. // IN PLARGE_INTEGER address,
  2668. // IN OUT PSUBSECTION subsection
  2669. // );
  2670. //
  2671. // Routine Description:
  2672. //
  2673. // This macro sets into the specified subsection the supplied information
  2674. // indicating the start address (in 4K units) of this portion of the file.
  2675. //
  2676. // Arguments
  2677. //
  2678. // address - Supplies the 64-bit address (in 4K units) of the start of this
  2679. // portion of the file.
  2680. //
  2681. // subsection - Supplies the subsection address to store the address in.
  2682. //
  2683. // Return Value:
  2684. //
  2685. // None.
  2686. //
  2687. //--
  2688. #define Mi4KStartForSubsection(address, subsection) \
  2689. subsection->StartingSector = ((PLARGE_INTEGER)address)->LowPart; \
  2690. subsection->u.SubsectionFlags.StartingSector4132 = \
  2691. (((PLARGE_INTEGER)(address))->HighPart & 0x3ff);
  2692. //++
  2693. //ULONG
  2694. //Mi4KStartFromSubsection (
  2695. // IN OUT PLARGE_INTEGER address,
  2696. // IN PSUBSECTION subsection
  2697. // );
  2698. //
  2699. // Routine Description:
  2700. //
  2701. // This macro gets the start 4K offset from the specified subsection.
  2702. //
  2703. // Arguments
  2704. //
  2705. // address - Supplies the 64-bit address (in 4K units) to place the
  2706. // start of this subsection into.
  2707. //
  2708. // subsection - Supplies the subsection address to get the address from.
  2709. //
  2710. // Return Value:
  2711. //
  2712. // None.
  2713. //
  2714. //--
  2715. #define Mi4KStartFromSubsection(address, subsection) \
  2716. ((PLARGE_INTEGER)address)->LowPart = subsection->StartingSector; \
  2717. ((PLARGE_INTEGER)address)->HighPart = subsection->u.SubsectionFlags.StartingSector4132;
  2718. typedef struct _MMDEREFERENCE_SEGMENT_HEADER {
  2719. KSPIN_LOCK Lock;
  2720. KSEMAPHORE Semaphore;
  2721. LIST_ENTRY ListHead;
  2722. } MMDEREFERENCE_SEGMENT_HEADER;
  2723. //
  2724. // This entry is used for calling the segment dereference thread
  2725. // to perform page file expansion. It has a similar structure
  2726. // to a control area to allow either a control area or a page file
  2727. // expansion entry to be placed on the list. Note that for a control
  2728. // area the segment pointer is valid whereas for page file expansion
  2729. // it is null.
  2730. //
  2731. typedef struct _MMPAGE_FILE_EXPANSION {
  2732. PSEGMENT Segment;
  2733. LIST_ENTRY DereferenceList;
  2734. SIZE_T RequestedExpansionSize;
  2735. SIZE_T ActualExpansion;
  2736. KEVENT Event;
  2737. LONG InProgress;
  2738. ULONG PageFileNumber;
  2739. } MMPAGE_FILE_EXPANSION, *PMMPAGE_FILE_EXPANSION;
  2740. #define MI_EXTEND_ANY_PAGEFILE ((ULONG)-1)
  2741. #define MI_CONTRACT_PAGEFILES ((SIZE_T)-1)
  2742. typedef struct _MMWORKING_SET_EXPANSION_HEAD {
  2743. LIST_ENTRY ListHead;
  2744. } MMWORKING_SET_EXPANSION_HEAD;
  2745. #define SUBSECTION_READ_ONLY 1L
  2746. #define SUBSECTION_READ_WRITE 2L
  2747. #define SUBSECTION_COPY_ON_WRITE 4L
  2748. #define SUBSECTION_SHARE_ALLOW 8L
  2749. //
  2750. // The MMINPAGE_FLAGS relies on the fact that a pool allocation is always
  2751. // QUADWORD aligned so the low 3 bits are always available.
  2752. //
  2753. typedef struct _MMINPAGE_FLAGS {
  2754. ULONG_PTR Completed : 1;
  2755. ULONG_PTR Available1 : 1;
  2756. ULONG_PTR Available2 : 1;
  2757. #if defined (_WIN64)
  2758. ULONG_PTR PrefetchMdlHighBits : 61;
  2759. #else
  2760. ULONG_PTR PrefetchMdlHighBits : 29;
  2761. #endif
  2762. } MMINPAGE_FLAGS, *PMMINPAGE_FLAGS;
  2763. #define MI_EXTRACT_PREFETCH_MDL(_Support) ((PMDL)((ULONG_PTR)(_Support->u1.PrefetchMdl) & ~(sizeof(QUAD) - 1)))
  2764. typedef struct _MMINPAGE_SUPPORT {
  2765. KEVENT Event;
  2766. IO_STATUS_BLOCK IoStatus;
  2767. LARGE_INTEGER ReadOffset;
  2768. LONG WaitCount;
  2769. #if defined (_WIN64)
  2770. ULONG UsedPageTableEntries;
  2771. #endif
  2772. PETHREAD Thread;
  2773. PFILE_OBJECT FilePointer;
  2774. PMMPTE BasePte;
  2775. PMMPFN Pfn;
  2776. union {
  2777. MMINPAGE_FLAGS e1;
  2778. ULONG_PTR LongFlags;
  2779. PMDL PrefetchMdl; // Only used under _PREFETCH_
  2780. } u1;
  2781. MDL Mdl;
  2782. PFN_NUMBER Page[MM_MAXIMUM_READ_CLUSTER_SIZE + 1];
  2783. SINGLE_LIST_ENTRY ListEntry;
  2784. } MMINPAGE_SUPPORT, *PMMINPAGE_SUPPORT;
  2785. #define MI_PF_DUMMY_PAGE_PTE ((PMMPTE)0x23452345) // Only used by _PREFETCH_
  2786. //
  2787. // Section support.
  2788. //
  2789. typedef struct _SECTION {
  2790. MMADDRESS_NODE Address;
  2791. PSEGMENT Segment;
  2792. LARGE_INTEGER SizeOfSection;
  2793. union {
  2794. ULONG LongFlags;
  2795. MMSECTION_FLAGS Flags;
  2796. } u;
  2797. ULONG InitialPageProtection;
  2798. } SECTION, *PSECTION;
  2799. //
  2800. // Banked memory descriptor. Pointed to by VAD which has
  2801. // the PhysicalMemory flags set and the Banked pointer field as
  2802. // non-NULL.
  2803. //
  2804. typedef struct _MMBANKED_SECTION {
  2805. PFN_NUMBER BasePhysicalPage;
  2806. PMMPTE BasedPte;
  2807. ULONG BankSize;
  2808. ULONG BankShift; //shift for PTEs to calculate bank number
  2809. PBANKED_SECTION_ROUTINE BankedRoutine;
  2810. PVOID Context;
  2811. PMMPTE CurrentMappedPte;
  2812. MMPTE BankTemplate[1];
  2813. } MMBANKED_SECTION, *PMMBANKED_SECTION;
  2814. //
  2815. // Virtual address descriptor
  2816. //
  2817. // ***** NOTE **********
  2818. // The first part of a virtual address descriptor is a MMADDRESS_NODE!!!
  2819. //
  2820. #if defined (_WIN64)
  2821. #define COMMIT_SIZE 51
  2822. #if ((COMMIT_SIZE + PAGE_SHIFT) < 63)
  2823. #error COMMIT_SIZE too small
  2824. #endif
  2825. #else
  2826. #define COMMIT_SIZE 19
  2827. #if ((COMMIT_SIZE + PAGE_SHIFT) < 31)
  2828. #error COMMIT_SIZE too small
  2829. #endif
  2830. #endif
  2831. #define MM_MAX_COMMIT (((ULONG_PTR) 1 << COMMIT_SIZE) - 1)
  2832. #define MM_VIEW_UNMAP 0
  2833. #define MM_VIEW_SHARE 1
  2834. typedef struct _MMVAD_FLAGS {
  2835. ULONG_PTR CommitCharge : COMMIT_SIZE; //limits system to 4k pages or bigger!
  2836. ULONG_PTR PhysicalMapping : 1; // Device\PhysicalMemory
  2837. ULONG_PTR ImageMap : 1;
  2838. ULONG_PTR UserPhysicalPages : 1; // AWE
  2839. ULONG_PTR NoChange : 1;
  2840. ULONG_PTR WriteWatch : 1;
  2841. ULONG_PTR Protection : 5;
  2842. ULONG_PTR LargePages : 1;
  2843. ULONG_PTR MemCommit: 1;
  2844. ULONG_PTR PrivateMemory : 1; //used to tell VAD from VAD_SHORT
  2845. } MMVAD_FLAGS;
  2846. typedef struct _MMVAD_FLAGS2 {
  2847. unsigned FileOffset : 24; // number of 64k units into file
  2848. unsigned SecNoChange : 1; // set if SEC_NOCHANGE specified
  2849. unsigned OneSecured : 1; // set if u3 field is a range
  2850. unsigned MultipleSecured : 1; // set if u3 field is a list head
  2851. unsigned ReadOnly : 1; // protected as ReadOnly
  2852. unsigned LongVad : 1; // set if VAD is a long VAD
  2853. unsigned ExtendableFile : 1;
  2854. unsigned Inherit : 1; //1 = ViewShare, 0 = ViewUnmap
  2855. unsigned CopyOnWrite : 1;
  2856. } MMVAD_FLAGS2;
  2857. typedef struct _MMADDRESS_LIST {
  2858. ULONG_PTR StartVpn;
  2859. ULONG_PTR EndVpn;
  2860. } MMADDRESS_LIST, *PMMADDRESS_LIST;
  2861. typedef struct _MMSECURE_ENTRY {
  2862. union {
  2863. ULONG_PTR LongFlags2;
  2864. MMVAD_FLAGS2 VadFlags2;
  2865. } u2;
  2866. ULONG_PTR StartVpn;
  2867. ULONG_PTR EndVpn;
  2868. LIST_ENTRY List;
  2869. } MMSECURE_ENTRY, *PMMSECURE_ENTRY;
  2870. typedef struct _ALIAS_VAD_INFO {
  2871. KAPC Apc;
  2872. ULONG NumberOfEntries;
  2873. ULONG MaximumEntries;
  2874. } ALIAS_VAD_INFO, *PALIAS_VAD_INFO;
  2875. typedef struct _ALIAS_VAD_INFO2 {
  2876. ULONG BaseAddress;
  2877. HANDLE SecureHandle;
  2878. } ALIAS_VAD_INFO2, *PALIAS_VAD_INFO2;
  2879. typedef struct _MMVAD {
  2880. union {
  2881. LONG_PTR Balance : 2;
  2882. struct _MMVAD *Parent;
  2883. } u1;
  2884. struct _MMVAD *LeftChild;
  2885. struct _MMVAD *RightChild;
  2886. ULONG_PTR StartingVpn;
  2887. ULONG_PTR EndingVpn;
  2888. union {
  2889. ULONG_PTR LongFlags;
  2890. MMVAD_FLAGS VadFlags;
  2891. } u;
  2892. PCONTROL_AREA ControlArea;
  2893. PMMPTE FirstPrototypePte;
  2894. PMMPTE LastContiguousPte;
  2895. union {
  2896. ULONG LongFlags2;
  2897. MMVAD_FLAGS2 VadFlags2;
  2898. } u2;
  2899. } MMVAD, *PMMVAD;
  2900. typedef struct _MMVAD_LONG {
  2901. union {
  2902. LONG_PTR Balance : 2;
  2903. struct _MMVAD *Parent;
  2904. } u1;
  2905. struct _MMVAD *LeftChild;
  2906. struct _MMVAD *RightChild;
  2907. ULONG_PTR StartingVpn;
  2908. ULONG_PTR EndingVpn;
  2909. union {
  2910. ULONG_PTR LongFlags;
  2911. MMVAD_FLAGS VadFlags;
  2912. } u;
  2913. PCONTROL_AREA ControlArea;
  2914. PMMPTE FirstPrototypePte;
  2915. PMMPTE LastContiguousPte;
  2916. union {
  2917. ULONG LongFlags2;
  2918. MMVAD_FLAGS2 VadFlags2;
  2919. } u2;
  2920. union {
  2921. LIST_ENTRY List;
  2922. MMADDRESS_LIST Secured;
  2923. } u3;
  2924. union {
  2925. PMMBANKED_SECTION Banked;
  2926. PMMEXTEND_INFO ExtendedInfo;
  2927. } u4;
  2928. #if defined(_MIALT4K_)
  2929. PALIAS_VAD_INFO AliasInformation;
  2930. #endif
  2931. } MMVAD_LONG, *PMMVAD_LONG;
  2932. typedef struct _MMVAD_SHORT {
  2933. union {
  2934. LONG_PTR Balance : 2;
  2935. struct _MMVAD *Parent;
  2936. } u1;
  2937. struct _MMVAD *LeftChild;
  2938. struct _MMVAD *RightChild;
  2939. ULONG_PTR StartingVpn;
  2940. ULONG_PTR EndingVpn;
  2941. union {
  2942. ULONG_PTR LongFlags;
  2943. MMVAD_FLAGS VadFlags;
  2944. } u;
  2945. } MMVAD_SHORT, *PMMVAD_SHORT;
  2946. #define MI_GET_PROTECTION_FROM_VAD(_Vad) ((ULONG)(_Vad)->u.VadFlags.Protection)
  2947. #define MI_PHYSICAL_VIEW_AWE 0x1 // AWE region
  2948. #define MI_PHYSICAL_VIEW_PHYS 0x2 // Device\PhysicalMemory region
  2949. #define MI_PHYSICAL_VIEW_LARGE 0x4 // Large page region
  2950. typedef struct _MI_PHYSICAL_VIEW {
  2951. union {
  2952. LONG_PTR Balance : 2;
  2953. struct _MMADDRESS_NODE *Parent;
  2954. } u1;
  2955. struct _MMADDRESS_NODE *LeftChild;
  2956. struct _MMADDRESS_NODE *RightChild;
  2957. ULONG_PTR StartingVpn; // Actually a virtual address, not a VPN
  2958. ULONG_PTR EndingVpn; // Actually a virtual address, not a VPN
  2959. PMMVAD Vad;
  2960. union {
  2961. ULONG_PTR LongFlags; // physical, AWE or largepage Vad identification
  2962. PRTL_BITMAP BitMap; // only if Vad->u.VadFlags.WriteWatch == 1
  2963. } u;
  2964. } MI_PHYSICAL_VIEW, *PMI_PHYSICAL_VIEW;
  2965. #define MI_PHYSICAL_VIEW_ROOT_KEY 'rpmM'
  2966. #define MI_PHYSICAL_VIEW_KEY 'vpmM'
  2967. #define MI_WRITEWATCH_VIEW_KEY 'wWmM'
  2968. //
  2969. // Stuff for support of Write Watch.
  2970. //
  2971. VOID
  2972. MiCaptureWriteWatchDirtyBit (
  2973. IN PEPROCESS Process,
  2974. IN PVOID VirtualAddress
  2975. );
  2976. //
  2977. // Stuff for support of AWE (Address Windowing Extensions).
  2978. //
  2979. typedef struct _AWEINFO {
  2980. PRTL_BITMAP VadPhysicalPagesBitMap;
  2981. ULONG_PTR VadPhysicalPages;
  2982. ULONG_PTR VadPhysicalPagesLimit;
  2983. //
  2984. // The PushLock is used to allow most of the NtMapUserPhysicalPages{Scatter}
  2985. // to execute in parallel as this is acquired shared for these calls.
  2986. // Exclusive acquisitions are used to protect maps against frees of the
  2987. // pages as well as to protect updates to the AweVadList. Collisions
  2988. // should be rare because the exclusive acquisitions should be rare.
  2989. //
  2990. PEX_PUSH_LOCK_CACHE_AWARE PushLock;
  2991. PMI_PHYSICAL_VIEW PhysicalViewHint[MAXIMUM_PROCESSORS];
  2992. MM_AVL_TABLE AweVadRoot;
  2993. } AWEINFO, *PAWEINFO;
  2994. VOID
  2995. MiAweViewInserter (
  2996. IN PEPROCESS Process,
  2997. IN PMI_PHYSICAL_VIEW PhysicalView
  2998. );
  2999. VOID
  3000. MiAweViewRemover (
  3001. IN PEPROCESS Process,
  3002. IN PMMVAD Vad
  3003. );
  3004. //
  3005. // Stuff for support of POSIX Fork.
  3006. //
  3007. typedef struct _MMCLONE_BLOCK {
  3008. MMPTE ProtoPte;
  3009. LONG CloneRefCount;
  3010. } MMCLONE_BLOCK, *PMMCLONE_BLOCK;
  3011. typedef struct _MMCLONE_HEADER {
  3012. ULONG NumberOfPtes;
  3013. LONG NumberOfProcessReferences;
  3014. PMMCLONE_BLOCK ClonePtes;
  3015. } MMCLONE_HEADER, *PMMCLONE_HEADER;
  3016. typedef struct _MMCLONE_DESCRIPTOR {
  3017. union {
  3018. LONG_PTR Balance : 2;
  3019. struct _MMADDRESS_NODE *Parent;
  3020. } u1;
  3021. struct _MMADDRESS_NODE *LeftChild;
  3022. struct _MMADDRESS_NODE *RightChild;
  3023. ULONG_PTR StartingVpn;
  3024. ULONG_PTR EndingVpn;
  3025. ULONG NumberOfPtes;
  3026. PMMCLONE_HEADER CloneHeader;
  3027. LONG NumberOfReferences;
  3028. LONG FinalNumberOfReferences;
  3029. SIZE_T PagedPoolQuotaCharge;
  3030. } MMCLONE_DESCRIPTOR, *PMMCLONE_DESCRIPTOR;
  3031. //
  3032. // The following macro allocates and initializes a bitmap from the
  3033. // specified pool of the specified size.
  3034. //
  3035. // VOID
  3036. // MiCreateBitMap (
  3037. // OUT PRTL_BITMAP *BitMapHeader,
  3038. // IN SIZE_T SizeOfBitMap,
  3039. // IN POOL_TYPE PoolType
  3040. // );
  3041. //
  3042. #define MiCreateBitMap(BMH,S,P) { \
  3043. ULONG _S; \
  3044. ASSERT ((ULONG64)(S) < _4gb); \
  3045. _S = sizeof(RTL_BITMAP) + (ULONG)((((S) + 31) / 32) * 4); \
  3046. *(BMH) = (PRTL_BITMAP)ExAllocatePoolWithTag( (P), _S, ' mM'); \
  3047. if (*(BMH)) { \
  3048. RtlInitializeBitMap( *(BMH), (PULONG)((*(BMH))+1), (ULONG)(S)); \
  3049. } \
  3050. }
  3051. #define MiRemoveBitMap(BMH) { \
  3052. ExFreePool(*(BMH)); \
  3053. *(BMH) = NULL; \
  3054. }
  3055. #define MI_INITIALIZE_ZERO_MDL(MDL) { \
  3056. MDL->Next = (PMDL) NULL; \
  3057. MDL->MdlFlags = 0; \
  3058. MDL->StartVa = NULL; \
  3059. MDL->ByteOffset = 0; \
  3060. MDL->ByteCount = 0; \
  3061. }
  3062. //
  3063. // Page File structures.
  3064. //
  3065. typedef struct _MMMOD_WRITER_LISTHEAD {
  3066. LIST_ENTRY ListHead;
  3067. KEVENT Event;
  3068. } MMMOD_WRITER_LISTHEAD, *PMMMOD_WRITER_LISTHEAD;
  3069. typedef struct _MMMOD_WRITER_MDL_ENTRY {
  3070. LIST_ENTRY Links;
  3071. LARGE_INTEGER WriteOffset;
  3072. union {
  3073. IO_STATUS_BLOCK IoStatus;
  3074. LARGE_INTEGER LastByte;
  3075. } u;
  3076. PIRP Irp;
  3077. ULONG_PTR LastPageToWrite;
  3078. PMMMOD_WRITER_LISTHEAD PagingListHead;
  3079. PLIST_ENTRY CurrentList;
  3080. struct _MMPAGING_FILE *PagingFile;
  3081. PFILE_OBJECT File;
  3082. PCONTROL_AREA ControlArea;
  3083. PERESOURCE FileResource;
  3084. LARGE_INTEGER IssueTime;
  3085. MDL Mdl;
  3086. PFN_NUMBER Page[1];
  3087. } MMMOD_WRITER_MDL_ENTRY, *PMMMOD_WRITER_MDL_ENTRY;
  3088. #define MM_PAGING_FILE_MDLS 2
  3089. typedef struct _MMPAGING_FILE {
  3090. PFN_NUMBER Size;
  3091. PFN_NUMBER MaximumSize;
  3092. PFN_NUMBER MinimumSize;
  3093. PFN_NUMBER FreeSpace;
  3094. PFN_NUMBER CurrentUsage;
  3095. PFN_NUMBER PeakUsage;
  3096. PFN_NUMBER HighestPage;
  3097. PFILE_OBJECT File;
  3098. PMMMOD_WRITER_MDL_ENTRY Entry[MM_PAGING_FILE_MDLS];
  3099. UNICODE_STRING PageFileName;
  3100. PRTL_BITMAP Bitmap;
  3101. struct {
  3102. ULONG PageFileNumber : 4;
  3103. ULONG ReferenceCount : 4; // really only need 1 bit for this.
  3104. ULONG BootPartition : 1;
  3105. ULONG Reserved : 23;
  3106. };
  3107. HANDLE FileHandle;
  3108. } MMPAGING_FILE, *PMMPAGING_FILE;
  3109. //
  3110. // System PTE structures.
  3111. //
  3112. typedef struct _MMFREE_POOL_ENTRY {
  3113. LIST_ENTRY List; // maintained free&chk, 1st entry only
  3114. PFN_NUMBER Size; // maintained free&chk, 1st entry only
  3115. ULONG Signature; // maintained chk only, all entries
  3116. struct _MMFREE_POOL_ENTRY *Owner; // maintained free&chk, all entries
  3117. } MMFREE_POOL_ENTRY, *PMMFREE_POOL_ENTRY;
  3118. typedef struct _MMLOCK_CONFLICT {
  3119. LIST_ENTRY List;
  3120. PETHREAD Thread;
  3121. } MMLOCK_CONFLICT, *PMMLOCK_CONFLICT;
  3122. //
  3123. // System view structures
  3124. //
  3125. typedef struct _MMVIEW {
  3126. ULONG_PTR Entry;
  3127. PCONTROL_AREA ControlArea;
  3128. } MMVIEW, *PMMVIEW;
  3129. //
  3130. // The MMSESSION structure represents kernel memory that is only valid on a
  3131. // per-session basis, thus the calling thread must be in the proper session
  3132. // to access this structure.
  3133. //
  3134. typedef struct _MMSESSION {
  3135. //
  3136. // Never refer to the SystemSpaceViewLock directly - always use the pointer
  3137. // following it or you will break support for multiple concurrent sessions.
  3138. //
  3139. KGUARDED_MUTEX SystemSpaceViewLock;
  3140. //
  3141. // This points to the mutex above and is needed because the MMSESSION
  3142. // is mapped in session space and the mutex needs to be globally
  3143. // visible for proper KeWaitForSingleObject & KeSetEvent operation.
  3144. //
  3145. PKGUARDED_MUTEX SystemSpaceViewLockPointer;
  3146. PCHAR SystemSpaceViewStart;
  3147. PMMVIEW SystemSpaceViewTable;
  3148. ULONG SystemSpaceHashSize;
  3149. ULONG SystemSpaceHashEntries;
  3150. ULONG SystemSpaceHashKey;
  3151. ULONG BitmapFailures;
  3152. PRTL_BITMAP SystemSpaceBitMap;
  3153. } MMSESSION, *PMMSESSION;
  3154. extern MMSESSION MmSession;
  3155. #define LOCK_SYSTEM_VIEW_SPACE(_Session) \
  3156. KeAcquireGuardedMutex (_Session->SystemSpaceViewLockPointer)
  3157. #define UNLOCK_SYSTEM_VIEW_SPACE(_Session) \
  3158. KeReleaseGuardedMutex (_Session->SystemSpaceViewLockPointer)
  3159. //
  3160. // List for flushing TBs singularly.
  3161. //
  3162. typedef struct _MMPTE_FLUSH_LIST {
  3163. ULONG Count;
  3164. PVOID FlushVa[MM_MAXIMUM_FLUSH_COUNT];
  3165. } MMPTE_FLUSH_LIST, *PMMPTE_FLUSH_LIST;
  3166. //
  3167. // List for flushing WSLEs and TBs singularly.
  3168. //
  3169. typedef struct _MMWSLE_FLUSH_LIST {
  3170. ULONG Count;
  3171. WSLE_NUMBER FlushIndex[MM_MAXIMUM_FLUSH_COUNT];
  3172. } MMWSLE_FLUSH_LIST, *PMMWSLE_FLUSH_LIST;
  3173. typedef struct _LOCK_TRACKER {
  3174. LIST_ENTRY ListEntry;
  3175. PMDL Mdl;
  3176. PVOID StartVa;
  3177. PFN_NUMBER Count;
  3178. ULONG Offset;
  3179. ULONG Length;
  3180. PFN_NUMBER Page;
  3181. PVOID CallingAddress;
  3182. PVOID CallersCaller;
  3183. ULONG Who;
  3184. PEPROCESS Process;
  3185. } LOCK_TRACKER, *PLOCK_TRACKER;
  3186. extern LOGICAL MmTrackLockedPages;
  3187. extern BOOLEAN MiTrackingAborted;
  3188. typedef struct _LOCK_HEADER {
  3189. LIST_ENTRY ListHead;
  3190. PFN_NUMBER Count;
  3191. KSPIN_LOCK Lock;
  3192. LOGICAL Valid;
  3193. } LOCK_HEADER, *PLOCK_HEADER;
  3194. extern LOGICAL MmSnapUnloads;
  3195. #define MI_UNLOADED_DRIVERS 50
  3196. extern ULONG MmLastUnloadedDriver;
  3197. extern PUNLOADED_DRIVERS MmUnloadedDrivers;
  3198. VOID
  3199. MiInitMachineDependent (
  3200. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  3201. );
  3202. VOID
  3203. MiAddHalIoMappings (
  3204. VOID
  3205. );
  3206. VOID
  3207. MiReportPhysicalMemory (
  3208. VOID
  3209. );
  3210. extern PFN_NUMBER MiNumberOfCompressionPages;
  3211. NTSTATUS
  3212. MiArmCompressionInterrupt (
  3213. VOID
  3214. );
  3215. VOID
  3216. MiBuildPagedPool (
  3217. VOID
  3218. );
  3219. VOID
  3220. MiInitializeNonPagedPool (
  3221. VOID
  3222. );
  3223. VOID
  3224. MiInitializePoolEvents (
  3225. VOID
  3226. );
  3227. VOID
  3228. MiInitializeNonPagedPoolThresholds (
  3229. VOID
  3230. );
  3231. LOGICAL
  3232. MiInitializeSystemSpaceMap (
  3233. PVOID Session OPTIONAL
  3234. );
  3235. VOID
  3236. MiFindInitializationCode (
  3237. OUT PVOID *StartVa,
  3238. OUT PVOID *EndVa
  3239. );
  3240. VOID
  3241. MiFreeInitializationCode (
  3242. IN PVOID StartVa,
  3243. IN PVOID EndVa
  3244. );
  3245. extern ULONG MiNonCachedCollisions;
  3246. //
  3247. // If /NOLOWMEM is used, this is set to the boundary PFN (pages below this
  3248. // value are not used whenever possible).
  3249. //
  3250. extern PFN_NUMBER MiNoLowMemory;
  3251. PVOID
  3252. MiAllocateLowMemory (
  3253. IN SIZE_T NumberOfBytes,
  3254. IN PFN_NUMBER LowestAcceptablePfn,
  3255. IN PFN_NUMBER HighestAcceptablePfn,
  3256. IN PFN_NUMBER BoundaryPfn,
  3257. IN PVOID CallingAddress,
  3258. IN MEMORY_CACHING_TYPE CacheType,
  3259. IN ULONG Tag
  3260. );
  3261. LOGICAL
  3262. MiFreeLowMemory (
  3263. IN PVOID BaseAddress,
  3264. IN ULONG Tag
  3265. );
  3266. //
  3267. // Move drivers out of the low 16mb that ntldr placed them at - this makes more
  3268. // memory below 16mb available for ISA-type drivers that cannot run without it.
  3269. //
  3270. extern LOGICAL MmMakeLowMemory;
  3271. VOID
  3272. MiRemoveLowPages (
  3273. IN ULONG RemovePhase
  3274. );
  3275. ULONG
  3276. MiSectionInitialization (
  3277. VOID
  3278. );
  3279. #define MI_MAX_DEREFERENCE_CHUNK (64 * 1024 / PAGE_SIZE)
  3280. typedef struct _MI_PFN_DEREFERENCE_CHUNK {
  3281. SINGLE_LIST_ENTRY ListEntry;
  3282. CSHORT Flags;
  3283. USHORT NumberOfPages;
  3284. PFN_NUMBER Pfns[MI_MAX_DEREFERENCE_CHUNK];
  3285. } MI_PFN_DEREFERENCE_CHUNK, *PMI_PFN_DEREFERENCE_CHUNK;
  3286. extern SLIST_HEADER MmPfnDereferenceSListHead;
  3287. extern PSLIST_ENTRY MmPfnDeferredList;
  3288. #define MI_DEFER_PFN_HELD 0x1
  3289. #define MI_DEFER_DRAIN_LOCAL_ONLY 0x2
  3290. VOID
  3291. MiDeferredUnlockPages (
  3292. ULONG Flags
  3293. );
  3294. LOGICAL
  3295. MiFreeAllExpansionNonPagedPool (
  3296. VOID
  3297. );
  3298. VOID
  3299. MiDecrementReferenceCountForAwePage (
  3300. IN PMMPFN Pfn1,
  3301. IN LOGICAL PfnHeld
  3302. );
  3303. VOID
  3304. FASTCALL
  3305. MiDecrementReferenceCount (
  3306. IN PMMPFN Pfn1,
  3307. IN PFN_NUMBER PageFrameIndex
  3308. );
  3309. //++
  3310. //VOID
  3311. //MiDecrementReferenceCountInline (
  3312. // IN PMMPFN PFN
  3313. // IN PFN_NUMBER FRAME
  3314. // );
  3315. //
  3316. // Routine Description:
  3317. //
  3318. // MiDecrementReferenceCountInline decrements the reference count inline,
  3319. // only calling MiDecrementReferenceCount if the count would go to zero
  3320. // which would cause the page to be released.
  3321. //
  3322. // Arguments:
  3323. //
  3324. // PFN - Supplies the PFN to decrement.
  3325. //
  3326. // FRAME - Supplies the frame matching the above PFN.
  3327. //
  3328. // Return Value:
  3329. //
  3330. // None.
  3331. //
  3332. // Environment:
  3333. //
  3334. // PFN lock held.
  3335. //
  3336. //--
  3337. #define MiDecrementReferenceCountInline(PFN, FRAME) \
  3338. MM_PFN_LOCK_ASSERT(); \
  3339. ASSERT (MI_PFN_ELEMENT(FRAME) == (PFN)); \
  3340. ASSERT ((FRAME) <= MmHighestPhysicalPage); \
  3341. ASSERT ((PFN)->u3.e2.ReferenceCount != 0); \
  3342. if ((PFN)->u3.e2.ReferenceCount != 1) { \
  3343. (PFN)->u3.e2.ReferenceCount -= 1; \
  3344. } \
  3345. else { \
  3346. MiDecrementReferenceCount (PFN, FRAME); \
  3347. }
  3348. VOID
  3349. FASTCALL
  3350. MiDecrementShareCount (
  3351. IN PMMPFN Pfn1,
  3352. IN PFN_NUMBER PageFrameIndex
  3353. );
  3354. //++
  3355. //VOID
  3356. //MiDecrementShareCountInline (
  3357. // IN PMMPFN PFN,
  3358. // IN PFN_NUMBER FRAME
  3359. // );
  3360. //
  3361. // Routine Description:
  3362. //
  3363. // MiDecrementShareCountInline decrements the share count inline,
  3364. // only calling MiDecrementShareCount if the count would go to zero
  3365. // which would cause the page to be released.
  3366. //
  3367. // Arguments:
  3368. //
  3369. // PFN - Supplies the PFN to decrement.
  3370. //
  3371. // FRAME - Supplies the frame matching the above PFN.
  3372. //
  3373. // Return Value:
  3374. //
  3375. // None.
  3376. //
  3377. // Environment:
  3378. //
  3379. // PFN lock held.
  3380. //
  3381. //--
  3382. #define MiDecrementShareCountInline(PFN, FRAME) \
  3383. MM_PFN_LOCK_ASSERT(); \
  3384. ASSERT (((FRAME) <= MmHighestPhysicalPage) && ((FRAME) > 0)); \
  3385. ASSERT (MI_PFN_ELEMENT(FRAME) == (PFN)); \
  3386. ASSERT ((PFN)->u2.ShareCount != 0); \
  3387. if ((PFN)->u3.e1.PageLocation != ActiveAndValid && (PFN)->u3.e1.PageLocation != StandbyPageList) { \
  3388. KeBugCheckEx (PFN_LIST_CORRUPT, 0x99, FRAME, (PFN)->u3.e1.PageLocation, 0); \
  3389. } \
  3390. if ((PFN)->u2.ShareCount != 1) { \
  3391. (PFN)->u2.ShareCount -= 1; \
  3392. PERFINFO_DECREFCNT((PFN), PERF_SOFT_TRIM, PERFINFO_LOG_TYPE_DECSHARCNT); \
  3393. ASSERT ((PFN)->u2.ShareCount < 0xF000000); \
  3394. } \
  3395. else { \
  3396. MiDecrementShareCount (PFN, FRAME); \
  3397. }
  3398. //
  3399. // Routines which operate on the Page Frame Database Lists
  3400. //
  3401. VOID
  3402. FASTCALL
  3403. MiInsertPageInList (
  3404. IN PMMPFNLIST ListHead,
  3405. IN PFN_NUMBER PageFrameIndex
  3406. );
  3407. VOID
  3408. FASTCALL
  3409. MiInsertPageInFreeList (
  3410. IN PFN_NUMBER PageFrameIndex
  3411. );
  3412. VOID
  3413. FASTCALL
  3414. MiInsertStandbyListAtFront (
  3415. IN PFN_NUMBER PageFrameIndex
  3416. );
  3417. PFN_NUMBER
  3418. FASTCALL
  3419. MiRemovePageFromList (
  3420. IN PMMPFNLIST ListHead
  3421. );
  3422. VOID
  3423. FASTCALL
  3424. MiUnlinkPageFromList (
  3425. IN PMMPFN Pfn
  3426. );
  3427. VOID
  3428. MiUnlinkFreeOrZeroedPage (
  3429. IN PMMPFN Pfn
  3430. );
  3431. VOID
  3432. FASTCALL
  3433. MiInsertFrontModifiedNoWrite (
  3434. IN PFN_NUMBER PageFrameIndex
  3435. );
  3436. //
  3437. // These are the thresholds for handing out an available page.
  3438. //
  3439. #define MM_LOW_LIMIT 2
  3440. #define MM_MEDIUM_LIMIT 32
  3441. #define MM_HIGH_LIMIT 128
  3442. //
  3443. // These are thresholds for enabling various optimizations.
  3444. //
  3445. #define MM_TIGHT_LIMIT 256
  3446. #define MM_PLENTY_FREE_LIMIT 1024
  3447. #define MM_VERY_HIGH_LIMIT 10000
  3448. #define MM_ENORMOUS_LIMIT 20000
  3449. ULONG
  3450. FASTCALL
  3451. MiEnsureAvailablePageOrWait (
  3452. IN PEPROCESS Process,
  3453. IN PVOID VirtualAddress,
  3454. IN KIRQL OldIrql
  3455. );
  3456. PFN_NUMBER
  3457. MiAllocatePfn (
  3458. IN PMMPTE PointerPte,
  3459. IN ULONG Protection
  3460. );
  3461. PFN_NUMBER
  3462. FASTCALL
  3463. MiRemoveAnyPage (
  3464. IN ULONG PageColor
  3465. );
  3466. PFN_NUMBER
  3467. FASTCALL
  3468. MiRemoveZeroPage (
  3469. IN ULONG PageColor
  3470. );
  3471. typedef struct _COLORED_PAGE_INFO {
  3472. union {
  3473. PFN_NUMBER PagesLeftToScan;
  3474. #if defined(MI_MULTINODE)
  3475. KAFFINITY Affinity;
  3476. #endif
  3477. };
  3478. PFN_COUNT PagesQueued;
  3479. SCHAR BasePriority;
  3480. PMMPFN PfnAllocation;
  3481. KEVENT Event;
  3482. } COLORED_PAGE_INFO, *PCOLORED_PAGE_INFO;
  3483. VOID
  3484. MiZeroInParallel (
  3485. IN PCOLORED_PAGE_INFO ColoredPageInfoBase
  3486. );
  3487. VOID
  3488. MiStartZeroPageWorkers (
  3489. VOID
  3490. );
  3491. VOID
  3492. MiPurgeTransitionList (
  3493. VOID
  3494. );
  3495. typedef struct _MM_LDW_WORK_CONTEXT {
  3496. WORK_QUEUE_ITEM WorkItem;
  3497. PFILE_OBJECT FileObject;
  3498. } MM_LDW_WORK_CONTEXT, *PMM_LDW_WORK_CONTEXT;
  3499. VOID
  3500. MiLdwPopupWorker (
  3501. IN PVOID Context
  3502. );
  3503. LOGICAL
  3504. MiDereferenceLastChanceLdw (
  3505. IN PMM_LDW_WORK_CONTEXT LdwContext
  3506. );
  3507. #define MI_LARGE_PAGE_DRIVER_BUFFER_LENGTH 512
  3508. extern WCHAR MmLargePageDriverBuffer[];
  3509. extern ULONG MmLargePageDriverBufferLength;
  3510. VOID
  3511. MiInitializeDriverLargePageList (
  3512. VOID
  3513. );
  3514. VOID
  3515. MiInitializeLargePageSupport (
  3516. VOID
  3517. );
  3518. NTSTATUS
  3519. MiAllocateLargePages (
  3520. IN PVOID StartingAddress,
  3521. IN PVOID EndingAddress
  3522. );
  3523. PFN_NUMBER
  3524. MiFindLargePageMemory (
  3525. IN PCOLORED_PAGE_INFO ColoredPageInfo,
  3526. IN PFN_NUMBER SizeInPages,
  3527. OUT PPFN_NUMBER OutZeroCount
  3528. );
  3529. VOID
  3530. MiFreeLargePageMemory (
  3531. IN PFN_NUMBER PageFrameIndex,
  3532. IN PFN_NUMBER SizeInPages
  3533. );
  3534. VOID
  3535. MiFreeLargePages (
  3536. IN PVOID StartingAddress,
  3537. IN PVOID EndingAddress
  3538. );
  3539. PVOID
  3540. MiMapWithLargePages (
  3541. IN PFN_NUMBER PageFrameIndex,
  3542. IN PFN_NUMBER NumberOfPages,
  3543. IN ULONG Protection,
  3544. IN MEMORY_CACHING_TYPE CacheType
  3545. );
  3546. VOID
  3547. MiUnmapLargePages (
  3548. IN PVOID BaseAddress,
  3549. IN SIZE_T NumberOfBytes
  3550. );
  3551. LOGICAL
  3552. MiMustFrameBeCached (
  3553. IN PFN_NUMBER PageFrameIndex
  3554. );
  3555. VOID
  3556. MiSyncCachedRanges (
  3557. VOID
  3558. );
  3559. LOGICAL
  3560. MiAddCachedRange (
  3561. IN PFN_NUMBER PageFrameIndex,
  3562. IN PFN_NUMBER LastPageFrameIndex
  3563. );
  3564. VOID
  3565. MiRemoveCachedRange (
  3566. IN PFN_NUMBER PageFrameIndex,
  3567. IN PFN_NUMBER LastPageFrameIndex
  3568. );
  3569. #define MI_PAGE_FRAME_INDEX_MUST_BE_CACHED(PageFrameIndex) \
  3570. MiMustFrameBeCached(PageFrameIndex)
  3571. VOID
  3572. MiFreeContiguousPages (
  3573. IN PFN_NUMBER PageFrameIndex,
  3574. IN PFN_NUMBER SizeInPages
  3575. );
  3576. PFN_NUMBER
  3577. MiFindContiguousPages (
  3578. IN PFN_NUMBER LowestPfn,
  3579. IN PFN_NUMBER HighestPfn,
  3580. IN PFN_NUMBER BoundaryPfn,
  3581. IN PFN_NUMBER SizeInPages,
  3582. IN MEMORY_CACHING_TYPE CacheType
  3583. );
  3584. PVOID
  3585. MiFindContiguousMemory (
  3586. IN PFN_NUMBER LowestPfn,
  3587. IN PFN_NUMBER HighestPfn,
  3588. IN PFN_NUMBER BoundaryPfn,
  3589. IN PFN_NUMBER SizeInPages,
  3590. IN MEMORY_CACHING_TYPE CacheType,
  3591. IN PVOID CallingAddress
  3592. );
  3593. PVOID
  3594. MiCheckForContiguousMemory (
  3595. IN PVOID BaseAddress,
  3596. IN PFN_NUMBER BaseAddressPages,
  3597. IN PFN_NUMBER SizeInPages,
  3598. IN PFN_NUMBER LowestPfn,
  3599. IN PFN_NUMBER HighestPfn,
  3600. IN PFN_NUMBER BoundaryPfn,
  3601. IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
  3602. );
  3603. //
  3604. // Routines which operate on the page frame database entry.
  3605. //
  3606. VOID
  3607. MiInitializePfn (
  3608. IN PFN_NUMBER PageFrameIndex,
  3609. IN PMMPTE PointerPte,
  3610. IN ULONG ModifiedState
  3611. );
  3612. VOID
  3613. MiInitializePfnForOtherProcess (
  3614. IN PFN_NUMBER PageFrameIndex,
  3615. IN PMMPTE PointerPte,
  3616. IN PFN_NUMBER ContainingPageFrame
  3617. );
  3618. VOID
  3619. MiInitializeCopyOnWritePfn (
  3620. IN PFN_NUMBER PageFrameIndex,
  3621. IN PMMPTE PointerPte,
  3622. IN WSLE_NUMBER WorkingSetIndex,
  3623. IN PVOID SessionSpace
  3624. );
  3625. VOID
  3626. MiInitializeTransitionPfn (
  3627. IN PFN_NUMBER PageFrameIndex,
  3628. IN PMMPTE PointerPte
  3629. );
  3630. extern SLIST_HEADER MmInPageSupportSListHead;
  3631. VOID
  3632. MiFreeInPageSupportBlock (
  3633. IN PMMINPAGE_SUPPORT Support
  3634. );
  3635. PMMINPAGE_SUPPORT
  3636. MiGetInPageSupportBlock (
  3637. IN KIRQL OldIrql,
  3638. IN PNTSTATUS Status
  3639. );
  3640. //
  3641. // Routines which require a physical page to be mapped into hyperspace
  3642. // within the current process.
  3643. //
  3644. VOID
  3645. FASTCALL
  3646. MiZeroPhysicalPage (
  3647. IN PFN_NUMBER PageFrameIndex,
  3648. IN ULONG Color
  3649. );
  3650. VOID
  3651. FASTCALL
  3652. MiRestoreTransitionPte (
  3653. IN PMMPFN Pfn1
  3654. );
  3655. PSUBSECTION
  3656. MiGetSubsectionAndProtoFromPte (
  3657. IN PMMPTE PointerPte,
  3658. IN PMMPTE *ProtoPte
  3659. );
  3660. PVOID
  3661. MiMapPageInHyperSpace (
  3662. IN PEPROCESS Process,
  3663. IN PFN_NUMBER PageFrameIndex,
  3664. OUT PKIRQL OldIrql
  3665. );
  3666. PVOID
  3667. MiMapPageInHyperSpaceAtDpc (
  3668. IN PEPROCESS Process,
  3669. IN PFN_NUMBER PageFrameIndex
  3670. );
  3671. VOID
  3672. MiUnmapPagesInZeroSpace (
  3673. IN PVOID VirtualAddress,
  3674. IN PFN_COUNT NumberOfPages
  3675. );
  3676. PVOID
  3677. MiMapImageHeaderInHyperSpace (
  3678. IN PFN_NUMBER PageFrameIndex
  3679. );
  3680. VOID
  3681. MiUnmapImageHeaderInHyperSpace (
  3682. VOID
  3683. );
  3684. PFN_NUMBER
  3685. MiGetPageForHeader (
  3686. LOGICAL ZeroPage
  3687. );
  3688. VOID
  3689. MiRemoveImageHeaderPage (
  3690. IN PFN_NUMBER PageFrameNumber
  3691. );
  3692. PVOID
  3693. MiMapPagesToZeroInHyperSpace (
  3694. IN PMMPFN PfnAllocation,
  3695. IN PFN_COUNT NumberOfPages
  3696. );
  3697. //
  3698. // Routines to obtain and release system PTEs.
  3699. //
  3700. PMMPTE
  3701. MiReserveSystemPtes (
  3702. IN ULONG NumberOfPtes,
  3703. IN MMSYSTEM_PTE_POOL_TYPE SystemPteType
  3704. );
  3705. PMMPTE
  3706. MiReserveAlignedSystemPtes (
  3707. IN ULONG NumberOfPtes,
  3708. IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType,
  3709. IN ULONG Alignment
  3710. );
  3711. VOID
  3712. MiReleaseSystemPtes (
  3713. IN PMMPTE StartingPte,
  3714. IN ULONG NumberOfPtes,
  3715. IN MMSYSTEM_PTE_POOL_TYPE SystemPteType
  3716. );
  3717. VOID
  3718. MiReleaseSplitSystemPtes (
  3719. IN PMMPTE StartingPte,
  3720. IN ULONG NumberOfPtes,
  3721. IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
  3722. );
  3723. VOID
  3724. MiIncrementSystemPtes (
  3725. IN ULONG NumberOfPtes
  3726. );
  3727. VOID
  3728. MiIssueNoPtesBugcheck (
  3729. IN ULONG NumberOfPtes,
  3730. IN MMSYSTEM_PTE_POOL_TYPE SystemPteType
  3731. );
  3732. VOID
  3733. MiInitializeSystemPtes (
  3734. IN PMMPTE StartingPte,
  3735. IN PFN_NUMBER NumberOfPtes,
  3736. IN MMSYSTEM_PTE_POOL_TYPE SystemPteType
  3737. );
  3738. NTSTATUS
  3739. MiAddMappedPtes (
  3740. IN PMMPTE FirstPte,
  3741. IN PFN_NUMBER NumberOfPtes,
  3742. IN PCONTROL_AREA ControlArea
  3743. );
  3744. VOID
  3745. MiInitializeIoTrackers (
  3746. VOID
  3747. );
  3748. PVOID
  3749. MiMapSinglePage (
  3750. IN PVOID VirtualAddress OPTIONAL,
  3751. IN PFN_NUMBER PageFrameIndex,
  3752. IN MEMORY_CACHING_TYPE CacheType,
  3753. IN MM_PAGE_PRIORITY Priority
  3754. );
  3755. VOID
  3756. MiUnmapSinglePage (
  3757. IN PVOID BaseAddress
  3758. );
  3759. typedef struct _MM_PTE_MAPPING {
  3760. LIST_ENTRY ListEntry;
  3761. PVOID SystemVa;
  3762. PVOID SystemEndVa;
  3763. ULONG Protection;
  3764. } MM_PTE_MAPPING, *PMM_PTE_MAPPING;
  3765. extern LIST_ENTRY MmProtectedPteList;
  3766. extern KSPIN_LOCK MmProtectedPteLock;
  3767. LOGICAL
  3768. MiCheckSystemPteProtection (
  3769. IN ULONG_PTR StoreInstruction,
  3770. IN PVOID VirtualAddress
  3771. );
  3772. //
  3773. // Access Fault routines.
  3774. //
  3775. #define STATUS_ISSUE_PAGING_IO (0xC0033333)
  3776. #define MM_NOIRQL (HIGH_LEVEL + 2)
  3777. NTSTATUS
  3778. MiDispatchFault (
  3779. IN ULONG_PTR FaultStatus,
  3780. IN PVOID VirtualAdress,
  3781. IN PMMPTE PointerPte,
  3782. IN PMMPTE PointerProtoPte,
  3783. IN LOGICAL RecheckAccess,
  3784. IN PEPROCESS Process,
  3785. IN PMMVAD Vad,
  3786. OUT PLOGICAL ApcNeeded
  3787. );
  3788. NTSTATUS
  3789. MiResolveDemandZeroFault (
  3790. IN PVOID VirtualAddress,
  3791. IN PMMPTE PointerPte,
  3792. IN PEPROCESS Process,
  3793. IN KIRQL OldIrql
  3794. );
  3795. BOOLEAN
  3796. MiIsAddressValid (
  3797. IN PVOID VirtualAddress,
  3798. IN LOGICAL UseForceIfPossible
  3799. );
  3800. VOID
  3801. MiAllowWorkingSetExpansion (
  3802. IN PMMSUPPORT WsInfo
  3803. );
  3804. WSLE_NUMBER
  3805. MiAddValidPageToWorkingSet (
  3806. IN PVOID VirtualAddress,
  3807. IN PMMPTE PointerPte,
  3808. IN PMMPFN Pfn1,
  3809. IN ULONG WsleMask
  3810. );
  3811. VOID
  3812. MiTrimPte (
  3813. IN PVOID VirtualAddress,
  3814. IN PMMPTE ReadPte,
  3815. IN PMMPFN Pfn1,
  3816. IN PEPROCESS CurrentProcess,
  3817. IN MMPTE NewPteContents
  3818. );
  3819. NTSTATUS
  3820. MiWaitForInPageComplete (
  3821. IN PMMPFN Pfn,
  3822. IN PMMPTE PointerPte,
  3823. IN PVOID FaultingAddress,
  3824. IN PMMPTE PointerPteContents,
  3825. IN PMMINPAGE_SUPPORT InPageSupport,
  3826. IN PEPROCESS CurrentProcess
  3827. );
  3828. LOGICAL
  3829. FASTCALL
  3830. MiCopyOnWrite (
  3831. IN PVOID FaultingAddress,
  3832. IN PMMPTE PointerPte
  3833. );
  3834. VOID
  3835. MiSetDirtyBit (
  3836. IN PVOID FaultingAddress,
  3837. IN PMMPTE PointerPte,
  3838. IN ULONG PfnHeld
  3839. );
  3840. VOID
  3841. MiSetModifyBit (
  3842. IN PMMPFN Pfn
  3843. );
  3844. PMMPTE
  3845. MiFindActualFaultingPte (
  3846. IN PVOID FaultingAddress
  3847. );
  3848. VOID
  3849. MiInitializeReadInProgressSinglePfn (
  3850. IN PFN_NUMBER PageFrameIndex,
  3851. IN PMMPTE BasePte,
  3852. IN PKEVENT Event,
  3853. IN WSLE_NUMBER WorkingSetIndex
  3854. );
  3855. VOID
  3856. MiInitializeReadInProgressPfn (
  3857. IN PMDL Mdl,
  3858. IN PMMPTE BasePte,
  3859. IN PKEVENT Event,
  3860. IN WSLE_NUMBER WorkingSetIndex
  3861. );
  3862. NTSTATUS
  3863. MiAccessCheck (
  3864. IN PMMPTE PointerPte,
  3865. IN ULONG_PTR WriteOperation,
  3866. IN KPROCESSOR_MODE PreviousMode,
  3867. IN ULONG Protection,
  3868. IN BOOLEAN CallerHoldsPfnLock
  3869. );
  3870. NTSTATUS
  3871. FASTCALL
  3872. MiCheckForUserStackOverflow (
  3873. IN PVOID FaultingAddress
  3874. );
  3875. PMMPTE
  3876. MiCheckVirtualAddress (
  3877. IN PVOID VirtualAddress,
  3878. OUT PULONG ProtectCode,
  3879. OUT PMMVAD *VadOut
  3880. );
  3881. NTSTATUS
  3882. FASTCALL
  3883. MiCheckPdeForPagedPool (
  3884. IN PVOID VirtualAddress
  3885. );
  3886. #if defined (_WIN64)
  3887. #define MI_IS_WOW64_PROCESS(PROCESS) (PROCESS->Wow64Process)
  3888. #else
  3889. #define MI_IS_WOW64_PROCESS(PROCESS) NULL
  3890. #endif
  3891. #if DBG || defined (_MI_DEBUG_ALTPTE)
  3892. #define MI_BREAK_ON_AV(VirtualAddress, Id) \
  3893. if (MmDebug & MM_DBG_STOP_ON_ACCVIO) { \
  3894. DbgPrint ("MM:access violation - %p %u\n", VirtualAddress, Id); \
  3895. DbgBreakPoint (); \
  3896. } \
  3897. if (MmDebug & MM_DBG_STOP_ON_WOW64_ACCVIO) { \
  3898. if (MI_IS_WOW64_PROCESS(PsGetCurrentProcess())) { \
  3899. DbgPrint ("MM:wow64 access violation - %p %u\n", VirtualAddress, Id); \
  3900. DbgBreakPoint (); \
  3901. } \
  3902. }
  3903. #else
  3904. #define MI_BREAK_ON_AV(VirtualAddress, Id)
  3905. #endif
  3906. //
  3907. // Routines which operate on an address tree.
  3908. //
  3909. PMMADDRESS_NODE
  3910. FASTCALL
  3911. MiGetNextNode (
  3912. IN PMMADDRESS_NODE Node
  3913. );
  3914. PMMADDRESS_NODE
  3915. FASTCALL
  3916. MiGetPreviousNode (
  3917. IN PMMADDRESS_NODE Node
  3918. );
  3919. PMMADDRESS_NODE
  3920. FASTCALL
  3921. MiGetFirstNode (
  3922. IN PMM_AVL_TABLE Root
  3923. );
  3924. PMMADDRESS_NODE
  3925. MiGetLastNode (
  3926. IN PMM_AVL_TABLE Root
  3927. );
  3928. VOID
  3929. FASTCALL
  3930. MiInsertNode (
  3931. IN PMMADDRESS_NODE Node,
  3932. IN PMM_AVL_TABLE Root
  3933. );
  3934. VOID
  3935. FASTCALL
  3936. MiRemoveNode (
  3937. IN PMMADDRESS_NODE Node,
  3938. IN PMM_AVL_TABLE Root
  3939. );
  3940. PMMADDRESS_NODE
  3941. FASTCALL
  3942. MiLocateAddressInTree (
  3943. IN ULONG_PTR Vpn,
  3944. IN PMM_AVL_TABLE Root
  3945. );
  3946. PMMADDRESS_NODE
  3947. MiCheckForConflictingNode (
  3948. IN ULONG_PTR StartVpn,
  3949. IN ULONG_PTR EndVpn,
  3950. IN PMM_AVL_TABLE Root
  3951. );
  3952. NTSTATUS
  3953. MiFindEmptyAddressRangeInTree (
  3954. IN SIZE_T SizeOfRange,
  3955. IN ULONG_PTR Alignment,
  3956. IN PMM_AVL_TABLE Root,
  3957. OUT PMMADDRESS_NODE *PreviousVad,
  3958. OUT PVOID *Base
  3959. );
  3960. NTSTATUS
  3961. MiFindEmptyAddressRangeDownTree (
  3962. IN SIZE_T SizeOfRange,
  3963. IN PVOID HighestAddressToEndAt,
  3964. IN ULONG_PTR Alignment,
  3965. IN PMM_AVL_TABLE Root,
  3966. OUT PVOID *Base
  3967. );
  3968. NTSTATUS
  3969. MiFindEmptyAddressRangeDownBasedTree (
  3970. IN SIZE_T SizeOfRange,
  3971. IN PVOID HighestAddressToEndAt,
  3972. IN ULONG_PTR Alignment,
  3973. IN PMM_AVL_TABLE Root,
  3974. OUT PVOID *Base
  3975. );
  3976. PVOID
  3977. MiEnumerateGenericTableWithoutSplayingAvl (
  3978. IN PMM_AVL_TABLE Table,
  3979. IN PVOID *RestartKey
  3980. );
  3981. VOID
  3982. NodeTreeWalk (
  3983. PMMADDRESS_NODE Start
  3984. );
  3985. TABLE_SEARCH_RESULT
  3986. MiFindNodeOrParent (
  3987. IN PMM_AVL_TABLE Table,
  3988. IN ULONG_PTR StartingVpn,
  3989. OUT PMMADDRESS_NODE *NodeOrParent
  3990. );
  3991. //
  3992. // Routines which operate on the tree of virtual address descriptors.
  3993. //
  3994. NTSTATUS
  3995. MiInsertVad (
  3996. IN PMMVAD Vad
  3997. );
  3998. VOID
  3999. MiRemoveVad (
  4000. IN PMMVAD Vad
  4001. );
  4002. PMMVAD
  4003. FASTCALL
  4004. MiLocateAddress (
  4005. IN PVOID VirtualAddress
  4006. );
  4007. NTSTATUS
  4008. MiFindEmptyAddressRange (
  4009. IN SIZE_T SizeOfRange,
  4010. IN ULONG_PTR Alignment,
  4011. IN ULONG QuickCheck,
  4012. IN PVOID *Base
  4013. );
  4014. //
  4015. // Routines which operate on the clone tree structure.
  4016. //
  4017. NTSTATUS
  4018. MiCloneProcessAddressSpace (
  4019. IN PEPROCESS ProcessToClone,
  4020. IN PEPROCESS ProcessToInitialize
  4021. );
  4022. ULONG
  4023. MiDecrementCloneBlockReference (
  4024. IN PMMCLONE_DESCRIPTOR CloneDescriptor,
  4025. IN PMMCLONE_BLOCK CloneBlock,
  4026. IN PEPROCESS CurrentProcess,
  4027. IN KIRQL OldIrql
  4028. );
  4029. LOGICAL
  4030. MiWaitForForkToComplete (
  4031. IN PEPROCESS CurrentProcess
  4032. );
  4033. //
  4034. // Routines which operate on the working set list.
  4035. //
  4036. WSLE_NUMBER
  4037. MiAllocateWsle (
  4038. IN PMMSUPPORT WsInfo,
  4039. IN PMMPTE PointerPte,
  4040. IN PMMPFN Pfn1,
  4041. IN ULONG_PTR WsleMask
  4042. );
  4043. VOID
  4044. MiReleaseWsle (
  4045. IN WSLE_NUMBER WorkingSetIndex,
  4046. IN PMMSUPPORT WsInfo
  4047. );
  4048. VOID
  4049. MiInitializeWorkingSetList (
  4050. IN PEPROCESS CurrentProcess
  4051. );
  4052. VOID
  4053. MiGrowWsleHash (
  4054. IN PMMSUPPORT WsInfo
  4055. );
  4056. WSLE_NUMBER
  4057. MiTrimWorkingSet (
  4058. IN WSLE_NUMBER Reduction,
  4059. IN PMMSUPPORT WsInfo,
  4060. IN ULONG TrimAge
  4061. );
  4062. #if defined(_AMD64_)
  4063. #define MM_PROCESS_COMMIT_CHARGE 6
  4064. #elif defined(_IA64_)
  4065. #define MM_PROCESS_COMMIT_CHARGE 5
  4066. #elif defined (_X86PAE_)
  4067. #define MM_PROCESS_COMMIT_CHARGE 8
  4068. #else
  4069. #define MM_PROCESS_COMMIT_CHARGE 4
  4070. #endif
  4071. #define MI_SYSTEM_GLOBAL 0
  4072. #define MI_USER_LOCAL 1
  4073. #define MI_SESSION_LOCAL 2
  4074. LOGICAL
  4075. MiTrimAllSystemPagableMemory (
  4076. IN ULONG MemoryType,
  4077. IN LOGICAL PurgeTransition
  4078. );
  4079. VOID
  4080. MiRemoveWorkingSetPages (
  4081. IN PMMSUPPORT WsInfo
  4082. );
  4083. VOID
  4084. MiAgeAndEstimateAvailableInWorkingSet (
  4085. IN PMMSUPPORT VmSupport,
  4086. IN LOGICAL DoAging,
  4087. IN PWSLE_NUMBER WslesScanned,
  4088. IN OUT PPFN_NUMBER TotalClaim,
  4089. IN OUT PPFN_NUMBER TotalEstimatedAvailable
  4090. );
  4091. VOID
  4092. FASTCALL
  4093. MiInsertWsleHash (
  4094. IN WSLE_NUMBER Entry,
  4095. IN PMMSUPPORT WsInfo
  4096. );
  4097. VOID
  4098. FASTCALL
  4099. MiRemoveWsle (
  4100. IN WSLE_NUMBER Entry,
  4101. IN PMMWSL WorkingSetList
  4102. );
  4103. WSLE_NUMBER
  4104. FASTCALL
  4105. MiLocateWsle (
  4106. IN PVOID VirtualAddress,
  4107. IN PMMWSL WorkingSetList,
  4108. IN WSLE_NUMBER WsPfnIndex
  4109. );
  4110. ULONG
  4111. MiFreeWsle (
  4112. IN WSLE_NUMBER WorkingSetIndex,
  4113. IN PMMSUPPORT WsInfo,
  4114. IN PMMPTE PointerPte
  4115. );
  4116. WSLE_NUMBER
  4117. MiFreeWsleList (
  4118. IN PMMSUPPORT WsInfo,
  4119. IN PMMWSLE_FLUSH_LIST WsleFlushList
  4120. );
  4121. VOID
  4122. MiSwapWslEntries (
  4123. IN WSLE_NUMBER SwapEntry,
  4124. IN WSLE_NUMBER Entry,
  4125. IN PMMSUPPORT WsInfo,
  4126. IN LOGICAL EntryNotInHash
  4127. );
  4128. VOID
  4129. MiRemoveWsleFromFreeList (
  4130. IN WSLE_NUMBER Entry,
  4131. IN PMMWSLE Wsle,
  4132. IN PMMWSL WorkingSetList
  4133. );
  4134. ULONG
  4135. MiRemovePageFromWorkingSet (
  4136. IN PMMPTE PointerPte,
  4137. IN PMMPFN Pfn1,
  4138. IN PMMSUPPORT WsInfo
  4139. );
  4140. PFN_NUMBER
  4141. MiDeleteSystemPagableVm (
  4142. IN PMMPTE PointerPte,
  4143. IN PFN_NUMBER NumberOfPtes,
  4144. IN MMPTE NewPteValue,
  4145. IN LOGICAL SessionAllocation,
  4146. OUT PPFN_NUMBER ResidentPages OPTIONAL
  4147. );
  4148. VOID
  4149. MiLockCode (
  4150. IN PMMPTE FirstPte,
  4151. IN PMMPTE LastPte,
  4152. IN ULONG LockType
  4153. );
  4154. PKLDR_DATA_TABLE_ENTRY
  4155. MiLookupDataTableEntry (
  4156. IN PVOID AddressWithinSection,
  4157. IN ULONG ResourceHeld
  4158. );
  4159. //
  4160. // Routines which perform working set management.
  4161. //
  4162. VOID
  4163. MiObtainFreePages (
  4164. VOID
  4165. );
  4166. VOID
  4167. MiModifiedPageWriter (
  4168. IN PVOID StartContext
  4169. );
  4170. VOID
  4171. MiMappedPageWriter (
  4172. IN PVOID StartContext
  4173. );
  4174. LOGICAL
  4175. MiIssuePageExtendRequest (
  4176. IN PMMPAGE_FILE_EXPANSION PageExtend
  4177. );
  4178. VOID
  4179. MiIssuePageExtendRequestNoWait (
  4180. IN PFN_NUMBER SizeInPages
  4181. );
  4182. SIZE_T
  4183. MiExtendPagingFiles (
  4184. IN PMMPAGE_FILE_EXPANSION PageExpand
  4185. );
  4186. VOID
  4187. MiContractPagingFiles (
  4188. VOID
  4189. );
  4190. VOID
  4191. MiAttemptPageFileReduction (
  4192. VOID
  4193. );
  4194. LOGICAL
  4195. MiCancelWriteOfMappedPfn (
  4196. IN PFN_NUMBER PageToStop,
  4197. IN KIRQL OldIrql
  4198. );
  4199. //
  4200. // Routines to delete address space.
  4201. //
  4202. VOID
  4203. MiDeletePteRange (
  4204. IN PMMSUPPORT WsInfo,
  4205. IN PMMPTE PointerPte,
  4206. IN PMMPTE LastPte,
  4207. IN LOGICAL AddressSpaceDeletion
  4208. );
  4209. VOID
  4210. MiDeleteVirtualAddresses (
  4211. IN PUCHAR StartingAddress,
  4212. IN PUCHAR EndingAddress,
  4213. IN PMMVAD Vad
  4214. );
  4215. ULONG
  4216. MiDeletePte (
  4217. IN PMMPTE PointerPte,
  4218. IN PVOID VirtualAddress,
  4219. IN ULONG AddressSpaceDeletion,
  4220. IN PEPROCESS CurrentProcess,
  4221. IN PMMPTE PrototypePte,
  4222. IN PMMPTE_FLUSH_LIST PteFlushList OPTIONAL,
  4223. IN KIRQL OldIrql
  4224. );
  4225. VOID
  4226. MiDeleteValidSystemPte (
  4227. IN PMMPTE PointerPte,
  4228. IN PVOID VirtualAddress,
  4229. IN PMMSUPPORT WsInfo,
  4230. IN PMMPTE_FLUSH_LIST PteFlushList OPTIONAL
  4231. );
  4232. VOID
  4233. MiDeletePageTablesForPhysicalRange (
  4234. IN PVOID StartingAddress,
  4235. IN PVOID EndingAddress
  4236. );
  4237. VOID
  4238. MiFlushPteList (
  4239. IN PMMPTE_FLUSH_LIST PteFlushList,
  4240. IN ULONG AllProcessors
  4241. );
  4242. ULONG
  4243. FASTCALL
  4244. MiReleasePageFileSpace (
  4245. IN MMPTE PteContents
  4246. );
  4247. VOID
  4248. FASTCALL
  4249. MiUpdateModifiedWriterMdls (
  4250. IN ULONG PageFileNumber
  4251. );
  4252. PVOID
  4253. MiAllocateAweInfo (
  4254. VOID
  4255. );
  4256. VOID
  4257. MiRemoveUserPhysicalPagesVad (
  4258. IN PMMVAD_SHORT FoundVad
  4259. );
  4260. VOID
  4261. MiCleanPhysicalProcessPages (
  4262. IN PEPROCESS Process
  4263. );
  4264. VOID
  4265. MiInsertPhysicalVadRoot (
  4266. IN PEPROCESS Process,
  4267. IN PMM_AVL_TABLE PhysicalVadRoot
  4268. );
  4269. VOID
  4270. MiPhysicalViewInserter (
  4271. IN PEPROCESS Process,
  4272. IN PMI_PHYSICAL_VIEW PhysicalView
  4273. );
  4274. VOID
  4275. MiPhysicalViewRemover (
  4276. IN PEPROCESS Process,
  4277. IN PMMVAD Vad
  4278. );
  4279. VOID
  4280. MiPhysicalViewAdjuster (
  4281. IN PEPROCESS Process,
  4282. IN PMMVAD OldVad,
  4283. IN PMMVAD NewVad
  4284. );
  4285. //
  4286. // MM_SYSTEM_PAGE_COLOR - MmSystemPageColor
  4287. //
  4288. // This variable is updated frequently, on MP systems we keep
  4289. // a separate system color per processor to avoid cache line
  4290. // thrashing.
  4291. //
  4292. #if defined(NT_UP)
  4293. #define MI_SYSTEM_PAGE_COLOR MmSystemPageColor
  4294. #else
  4295. #define MI_SYSTEM_PAGE_COLOR (KeGetCurrentPrcb()->PageColor)
  4296. #endif
  4297. #if defined(MI_MULTINODE)
  4298. extern PKNODE KeNodeBlock[];
  4299. #define MI_NODE_FROM_COLOR(c) \
  4300. (KeNodeBlock[(c) >> MmSecondaryColorNodeShift])
  4301. #define MI_GET_COLOR_FROM_LIST_ENTRY(index,pfn) \
  4302. ((ULONG)(((pfn)->u3.e1.PageColor << MmSecondaryColorNodeShift) | \
  4303. MI_GET_SECONDARY_COLOR((index),(pfn))))
  4304. #define MI_ADJUST_COLOR_FOR_NODE(c,n) ((c) | (n)->Color)
  4305. #define MI_CURRENT_NODE_COLOR (KeGetCurrentNode()->MmShiftedColor)
  4306. #define MiRemoveZeroPageIfAny(COLOR) \
  4307. KeNumberNodes > 1 ? (KeGetCurrentNode()->FreeCount[ZeroedPageList] != 0) ? MiRemoveZeroPage(COLOR) : 0 : \
  4308. (MmFreePagesByColor[ZeroedPageList][COLOR].Flink != MM_EMPTY_LIST) ? \
  4309. MiRemoveZeroPage(COLOR) : 0
  4310. #define MI_GET_PAGE_COLOR_NODE(n) \
  4311. (((MI_SYSTEM_PAGE_COLOR++) & MmSecondaryColorMask) | \
  4312. KeNodeBlock[n]->MmShiftedColor)
  4313. #else
  4314. #define MI_NODE_FROM_COLOR(c)
  4315. #define MI_GET_COLOR_FROM_LIST_ENTRY(index,pfn) \
  4316. ((ULONG)MI_GET_SECONDARY_COLOR((index),(pfn)))
  4317. #define MI_ADJUST_COLOR_FOR_NODE(c,n) (c)
  4318. #define MI_CURRENT_NODE_COLOR 0
  4319. #define MiRemoveZeroPageIfAny(COLOR) \
  4320. (MmFreePagesByColor[ZeroedPageList][COLOR].Flink != MM_EMPTY_LIST) ? \
  4321. MiRemoveZeroPage(COLOR) : 0
  4322. #define MI_GET_PAGE_COLOR_NODE(n) \
  4323. ((MI_SYSTEM_PAGE_COLOR++) & MmSecondaryColorMask)
  4324. #endif
  4325. FORCEINLINE
  4326. PFN_NUMBER
  4327. MiRemoveZeroPageMayReleaseLocks (
  4328. IN ULONG Color,
  4329. IN KIRQL OldIrql
  4330. )
  4331. /*++
  4332. Routine Description:
  4333. This routine returns a zeroed page.
  4334. It may release and reacquire the PFN lock to do so, as well as mapping
  4335. the page in hyperspace to perform the actual zeroing if necessary.
  4336. Environment:
  4337. Kernel mode. PFN lock held, hyperspace lock NOT held.
  4338. --*/
  4339. {
  4340. PFN_NUMBER PageFrameIndex;
  4341. PageFrameIndex = MiRemoveZeroPageIfAny (Color);
  4342. if (PageFrameIndex == 0) {
  4343. PageFrameIndex = MiRemoveAnyPage (Color);
  4344. UNLOCK_PFN (OldIrql);
  4345. MiZeroPhysicalPage (PageFrameIndex, Color);
  4346. LOCK_PFN (OldIrql);
  4347. }
  4348. return PageFrameIndex;
  4349. }
  4350. //
  4351. // General support routines.
  4352. //
  4353. #if (_MI_PAGING_LEVELS <= 3)
  4354. //++
  4355. //PMMPTE
  4356. //MiGetPxeAddress (
  4357. // IN PVOID va
  4358. // );
  4359. //
  4360. // Routine Description:
  4361. //
  4362. // MiGetPxeAddress returns the address of the extended page directory parent
  4363. // entry which maps the given virtual address. This is one level above the
  4364. // page parent directory.
  4365. //
  4366. // Arguments
  4367. //
  4368. // Va - Supplies the virtual address to locate the PXE for.
  4369. //
  4370. // Return Value:
  4371. //
  4372. // The address of the PXE.
  4373. //
  4374. //--
  4375. #define MiGetPxeAddress(va) ((PMMPTE)0)
  4376. //++
  4377. //LOGICAL
  4378. //MiIsPteOnPxeBoundary (
  4379. // IN PVOID PTE
  4380. // );
  4381. //
  4382. // Routine Description:
  4383. //
  4384. // MiIsPteOnPxeBoundary returns TRUE if the PTE is
  4385. // on an extended page directory parent entry boundary.
  4386. //
  4387. // Arguments
  4388. //
  4389. // PTE - Supplies the PTE to check.
  4390. //
  4391. // Return Value:
  4392. //
  4393. // TRUE if on a boundary, FALSE if not.
  4394. //
  4395. //--
  4396. #define MiIsPteOnPxeBoundary(PTE) (FALSE)
  4397. #endif
  4398. #if (_MI_PAGING_LEVELS <= 2)
  4399. //++
  4400. //PMMPTE
  4401. //MiGetPpeAddress (
  4402. // IN PVOID va
  4403. // );
  4404. //
  4405. // Routine Description:
  4406. //
  4407. // MiGetPpeAddress returns the address of the page directory parent entry
  4408. // which maps the given virtual address. This is one level above the
  4409. // page directory.
  4410. //
  4411. // Arguments
  4412. //
  4413. // Va - Supplies the virtual address to locate the PPE for.
  4414. //
  4415. // Return Value:
  4416. //
  4417. // The address of the PPE.
  4418. //
  4419. //--
  4420. #define MiGetPpeAddress(va) ((PMMPTE)0)
  4421. //++
  4422. //LOGICAL
  4423. //MiIsPteOnPpeBoundary (
  4424. // IN PVOID VA
  4425. // );
  4426. //
  4427. // Routine Description:
  4428. //
  4429. // MiIsPteOnPpeBoundary returns TRUE if the PTE is
  4430. // on a page directory parent entry boundary.
  4431. //
  4432. // Arguments
  4433. //
  4434. // VA - Supplies the virtual address to check.
  4435. //
  4436. // Return Value:
  4437. //
  4438. // TRUE if on a boundary, FALSE if not.
  4439. //
  4440. //--
  4441. #define MiIsPteOnPpeBoundary(PTE) (FALSE)
  4442. #endif
  4443. ULONG
  4444. MiDoesPdeExistAndMakeValid (
  4445. IN PMMPTE PointerPde,
  4446. IN PEPROCESS TargetProcess,
  4447. IN KIRQL OldIrql,
  4448. OUT PULONG Waited
  4449. );
  4450. #if (_MI_PAGING_LEVELS >= 3)
  4451. #define MiDoesPpeExistAndMakeValid(PPE, PROCESS, PFNLOCKIRQL, WAITED) \
  4452. MiDoesPdeExistAndMakeValid(PPE, PROCESS, PFNLOCKIRQL, WAITED)
  4453. #else
  4454. #define MiDoesPpeExistAndMakeValid(PPE, PROCESS, PFNLOCKIRQL, WAITED) 1
  4455. #endif
  4456. #if (_MI_PAGING_LEVELS >= 4)
  4457. #define MiDoesPxeExistAndMakeValid(PXE, PROCESS, PFNLOCKIRQL, WAITED) \
  4458. MiDoesPdeExistAndMakeValid(PXE, PROCESS, PFNLOCKIRQL, WAITED)
  4459. #else
  4460. #define MiDoesPxeExistAndMakeValid(PXE, PROCESS, PFNLOCKIRQL, WAITED) 1
  4461. #endif
  4462. VOID
  4463. MiMakePdeExistAndMakeValid (
  4464. IN PMMPTE PointerPde,
  4465. IN PEPROCESS TargetProcess,
  4466. IN KIRQL OldIrql
  4467. );
  4468. ULONG
  4469. FASTCALL
  4470. MiMakeSystemAddressValid (
  4471. IN PVOID VirtualAddress,
  4472. IN PEPROCESS CurrentProcess
  4473. );
  4474. ULONG
  4475. FASTCALL
  4476. MiMakeSystemAddressValidPfnWs (
  4477. IN PVOID VirtualAddress,
  4478. IN PEPROCESS CurrentProcess OPTIONAL,
  4479. IN KIRQL OldIrql
  4480. );
  4481. ULONG
  4482. FASTCALL
  4483. MiMakeSystemAddressValidPfnSystemWs (
  4484. IN PVOID VirtualAddress,
  4485. IN KIRQL OldIrql
  4486. );
  4487. ULONG
  4488. FASTCALL
  4489. MiMakeSystemAddressValidPfn (
  4490. IN PVOID VirtualAddress,
  4491. IN KIRQL OldIrql
  4492. );
  4493. VOID
  4494. FASTCALL
  4495. MiLockPagedAddress (
  4496. IN PVOID VirtualAddress
  4497. );
  4498. VOID
  4499. FASTCALL
  4500. MiUnlockPagedAddress (
  4501. IN PVOID VirtualAddress,
  4502. IN ULONG PfnLockHeld
  4503. );
  4504. ULONG
  4505. FASTCALL
  4506. MiIsPteDecommittedPage (
  4507. IN PMMPTE PointerPte
  4508. );
  4509. ULONG
  4510. FASTCALL
  4511. MiIsProtectionCompatible (
  4512. IN ULONG OldProtect,
  4513. IN ULONG NewProtect
  4514. );
  4515. ULONG
  4516. FASTCALL
  4517. MiIsPteProtectionCompatible (
  4518. IN ULONG OldPteProtection,
  4519. IN ULONG NewProtect
  4520. );
  4521. ULONG
  4522. FASTCALL
  4523. MiMakeProtectionMask (
  4524. IN ULONG Protect
  4525. );
  4526. ULONG
  4527. MiIsEntireRangeCommitted (
  4528. IN PVOID StartingAddress,
  4529. IN PVOID EndingAddress,
  4530. IN PMMVAD Vad,
  4531. IN PEPROCESS Process
  4532. );
  4533. ULONG
  4534. MiIsEntireRangeDecommitted (
  4535. IN PVOID StartingAddress,
  4536. IN PVOID EndingAddress,
  4537. IN PMMVAD Vad,
  4538. IN PEPROCESS Process
  4539. );
  4540. LOGICAL
  4541. MiCheckProtoPtePageState (
  4542. IN PMMPTE PrototypePte,
  4543. IN KIRQL OldIrql,
  4544. OUT PLOGICAL DroppedPfnLock
  4545. );
  4546. //++
  4547. //PMMPTE
  4548. //MiGetProtoPteAddress (
  4549. // IN PMMPTE VAD,
  4550. // IN PVOID VA
  4551. // );
  4552. //
  4553. // Routine Description:
  4554. //
  4555. // MiGetProtoPteAddress returns a pointer to the prototype PTE which
  4556. // is mapped by the given virtual address descriptor and address within
  4557. // the virtual address descriptor.
  4558. //
  4559. // Arguments
  4560. //
  4561. // VAD - Supplies a pointer to the virtual address descriptor that contains
  4562. // the VA.
  4563. //
  4564. // VPN - Supplies the virtual page number.
  4565. //
  4566. // Return Value:
  4567. //
  4568. // A pointer to the proto PTE which corresponds to the VA.
  4569. //
  4570. //--
  4571. #define MiGetProtoPteAddress(VAD,VPN) \
  4572. ((((((VPN) - (VAD)->StartingVpn) << PTE_SHIFT) + \
  4573. (ULONG_PTR)(VAD)->FirstPrototypePte) <= (ULONG_PTR)(VAD)->LastContiguousPte) ? \
  4574. ((PMMPTE)(((((VPN) - (VAD)->StartingVpn) << PTE_SHIFT) + \
  4575. (ULONG_PTR)(VAD)->FirstPrototypePte))) : \
  4576. MiGetProtoPteAddressExtended ((VAD),(VPN)))
  4577. PMMPTE
  4578. FASTCALL
  4579. MiGetProtoPteAddressExtended (
  4580. IN PMMVAD Vad,
  4581. IN ULONG_PTR Vpn
  4582. );
  4583. PSUBSECTION
  4584. FASTCALL
  4585. MiLocateSubsection (
  4586. IN PMMVAD Vad,
  4587. IN ULONG_PTR Vpn
  4588. );
  4589. VOID
  4590. MiInitializeSystemCache (
  4591. IN ULONG MinimumWorkingSet,
  4592. IN ULONG MaximumWorkingSet
  4593. );
  4594. VOID
  4595. MiAdjustWorkingSetManagerParameters(
  4596. IN LOGICAL WorkStation
  4597. );
  4598. #if defined (_MI_COMPRESSION)
  4599. VOID
  4600. MiNotifyMemoryEvents (
  4601. VOID
  4602. );
  4603. #endif
  4604. extern PFN_NUMBER MmLowMemoryThreshold;
  4605. extern PFN_NUMBER MmHighMemoryThreshold;
  4606. extern PFN_NUMBER MiLowPagedPoolThreshold;
  4607. extern PFN_NUMBER MiHighPagedPoolThreshold;
  4608. extern PFN_NUMBER MiLowNonPagedPoolThreshold;
  4609. extern PFN_NUMBER MiHighNonPagedPoolThreshold;
  4610. extern PKEVENT MiLowPagedPoolEvent;
  4611. extern PKEVENT MiHighPagedPoolEvent;
  4612. extern PKEVENT MiLowNonPagedPoolEvent;
  4613. extern PKEVENT MiHighNonPagedPoolEvent;
  4614. //
  4615. // Section support
  4616. //
  4617. VOID
  4618. FASTCALL
  4619. MiInsertBasedSection (
  4620. IN PSECTION Section
  4621. );
  4622. NTSTATUS
  4623. MiMapViewOfPhysicalSection (
  4624. IN PCONTROL_AREA ControlArea,
  4625. IN PEPROCESS Process,
  4626. IN PVOID *CapturedBase,
  4627. IN PLARGE_INTEGER SectionOffset,
  4628. IN PSIZE_T CapturedViewSize,
  4629. IN ULONG ProtectionMask,
  4630. IN ULONG_PTR ZeroBits,
  4631. IN ULONG AllocationType,
  4632. IN LOGICAL WriteCombined
  4633. );
  4634. NTSTATUS
  4635. MiMapViewOfDataSection (
  4636. IN PCONTROL_AREA ControlArea,
  4637. IN PEPROCESS Process,
  4638. IN PVOID *CapturedBase,
  4639. IN PLARGE_INTEGER SectionOffset,
  4640. IN PSIZE_T CapturedViewSize,
  4641. IN PSECTION Section,
  4642. IN SECTION_INHERIT InheritDisposition,
  4643. IN ULONG ProtectionMask,
  4644. IN SIZE_T CommitSize,
  4645. IN ULONG_PTR ZeroBits,
  4646. IN ULONG AllocationType
  4647. );
  4648. NTSTATUS
  4649. MiUnmapViewOfSection (
  4650. IN PEPROCESS Process,
  4651. IN PVOID BaseAddress,
  4652. IN LOGICAL AddressSpaceMutexHeld
  4653. );
  4654. VOID
  4655. MiRemoveImageSectionObject(
  4656. IN PFILE_OBJECT File,
  4657. IN PCONTROL_AREA ControlArea
  4658. );
  4659. VOID
  4660. MiAddSystemPtes(
  4661. IN PMMPTE StartingPte,
  4662. IN ULONG NumberOfPtes,
  4663. IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
  4664. );
  4665. VOID
  4666. MiRemoveMappedView (
  4667. IN PEPROCESS CurrentProcess,
  4668. IN PMMVAD Vad
  4669. );
  4670. VOID
  4671. MiSegmentDelete (
  4672. PSEGMENT Segment
  4673. );
  4674. VOID
  4675. MiSectionDelete (
  4676. IN PVOID Object
  4677. );
  4678. VOID
  4679. MiDereferenceSegmentThread (
  4680. IN PVOID StartContext
  4681. );
  4682. NTSTATUS
  4683. MiCreateImageFileMap (
  4684. IN PFILE_OBJECT File,
  4685. OUT PSEGMENT *Segment
  4686. );
  4687. NTSTATUS
  4688. MiCreateDataFileMap (
  4689. IN PFILE_OBJECT File,
  4690. OUT PSEGMENT *Segment,
  4691. IN PUINT64 MaximumSize,
  4692. IN ULONG SectionPageProtection,
  4693. IN ULONG AllocationAttributes,
  4694. IN ULONG IgnoreFileSizing
  4695. );
  4696. NTSTATUS
  4697. MiCreatePagingFileMap (
  4698. OUT PSEGMENT *Segment,
  4699. IN PUINT64 MaximumSize,
  4700. IN ULONG ProtectionMask,
  4701. IN ULONG AllocationAttributes
  4702. );
  4703. VOID
  4704. MiPurgeSubsectionInternal (
  4705. IN PSUBSECTION Subsection,
  4706. IN ULONG PteOffset
  4707. );
  4708. VOID
  4709. MiPurgeImageSection (
  4710. IN PCONTROL_AREA ControlArea,
  4711. IN PEPROCESS Process OPTIONAL,
  4712. IN KIRQL OldIrql
  4713. );
  4714. VOID
  4715. MiCleanSection (
  4716. IN PCONTROL_AREA ControlArea,
  4717. IN LOGICAL DirtyDataPagesOk
  4718. );
  4719. VOID
  4720. MiDereferenceControlArea (
  4721. IN PCONTROL_AREA ControlArea
  4722. );
  4723. VOID
  4724. MiCheckControlArea (
  4725. IN PCONTROL_AREA ControlArea,
  4726. IN PEPROCESS CurrentProcess,
  4727. IN KIRQL PreviousIrql
  4728. );
  4729. NTSTATUS
  4730. MiCheckPurgeAndUpMapCount (
  4731. IN PCONTROL_AREA ControlArea,
  4732. IN LOGICAL FailIfSystemViews
  4733. );
  4734. VOID
  4735. MiCheckForControlAreaDeletion (
  4736. IN PCONTROL_AREA ControlArea
  4737. );
  4738. LOGICAL
  4739. MiCheckControlAreaStatus (
  4740. IN SECTION_CHECK_TYPE SectionCheckType,
  4741. IN PSECTION_OBJECT_POINTERS SectionObjectPointers,
  4742. IN ULONG DelayClose,
  4743. OUT PCONTROL_AREA *ControlArea,
  4744. OUT PKIRQL OldIrql
  4745. );
  4746. extern SLIST_HEADER MmEventCountSListHead;
  4747. PEVENT_COUNTER
  4748. MiGetEventCounter (
  4749. VOID
  4750. );
  4751. VOID
  4752. MiFreeEventCounter (
  4753. IN PEVENT_COUNTER Support
  4754. );
  4755. ULONG
  4756. MiCanFileBeTruncatedInternal (
  4757. IN PSECTION_OBJECT_POINTERS SectionPointer,
  4758. IN PLARGE_INTEGER NewFileSize OPTIONAL,
  4759. IN LOGICAL BlockNewViews,
  4760. OUT PKIRQL PreviousIrql
  4761. );
  4762. #define STATUS_MAPPED_WRITER_COLLISION (0xC0033333)
  4763. NTSTATUS
  4764. MiFlushSectionInternal (
  4765. IN PMMPTE StartingPte,
  4766. IN PMMPTE FinalPte,
  4767. IN PSUBSECTION FirstSubsection,
  4768. IN PSUBSECTION LastSubsection,
  4769. IN ULONG Synchronize,
  4770. IN LOGICAL WriteInProgressOk,
  4771. OUT PIO_STATUS_BLOCK IoStatus
  4772. );
  4773. //
  4774. // protection stuff...
  4775. //
  4776. NTSTATUS
  4777. MiProtectVirtualMemory (
  4778. IN PEPROCESS Process,
  4779. IN PVOID *CapturedBase,
  4780. IN PSIZE_T CapturedRegionSize,
  4781. IN ULONG Protect,
  4782. IN PULONG LastProtect
  4783. );
  4784. ULONG
  4785. MiGetPageProtection (
  4786. IN PMMPTE PointerPte,
  4787. IN PEPROCESS Process,
  4788. IN LOGICAL PteCapturedToLocalStack
  4789. );
  4790. NTSTATUS
  4791. MiSetProtectionOnSection (
  4792. IN PEPROCESS Process,
  4793. IN PMMVAD Vad,
  4794. IN PVOID StartingAddress,
  4795. IN PVOID EndingAddress,
  4796. IN ULONG NewProtect,
  4797. OUT PULONG CapturedOldProtect,
  4798. IN ULONG DontCharge,
  4799. OUT PULONG Locked
  4800. );
  4801. NTSTATUS
  4802. MiCheckSecuredVad (
  4803. IN PMMVAD Vad,
  4804. IN PVOID Base,
  4805. IN ULONG_PTR Size,
  4806. IN ULONG ProtectionMask
  4807. );
  4808. HANDLE
  4809. MiSecureVirtualMemory (
  4810. IN PVOID Address,
  4811. IN SIZE_T Size,
  4812. IN ULONG ProbeMode,
  4813. IN LOGICAL AddressSpaceMutexHeld
  4814. );
  4815. VOID
  4816. MiUnsecureVirtualMemory (
  4817. IN HANDLE SecureHandle,
  4818. IN LOGICAL AddressSpaceMutexHeld
  4819. );
  4820. ULONG
  4821. MiChangeNoAccessForkPte (
  4822. IN PMMPTE PointerPte,
  4823. IN ULONG ProtectionMask
  4824. );
  4825. //
  4826. // Routines for charging quota and commitment.
  4827. //
  4828. VOID
  4829. MiTrimSegmentCache (
  4830. VOID
  4831. );
  4832. VOID
  4833. MiInitializeCommitment (
  4834. VOID
  4835. );
  4836. LOGICAL
  4837. FASTCALL
  4838. MiChargeCommitment (
  4839. IN SIZE_T QuotaCharge,
  4840. IN PEPROCESS Process OPTIONAL
  4841. );
  4842. LOGICAL
  4843. FASTCALL
  4844. MiChargeCommitmentCantExpand (
  4845. IN SIZE_T QuotaCharge,
  4846. IN ULONG MustSucceed
  4847. );
  4848. LOGICAL
  4849. FASTCALL
  4850. MiChargeTemporaryCommitmentForReduction (
  4851. IN SIZE_T QuotaCharge
  4852. );
  4853. #if defined (_MI_DEBUG_COMMIT_LEAKS)
  4854. VOID
  4855. FASTCALL
  4856. MiReturnCommitment (
  4857. IN SIZE_T QuotaCharge
  4858. );
  4859. #else
  4860. #define MiReturnCommitment(_QuotaCharge) \
  4861. ASSERT ((SSIZE_T)(_QuotaCharge) >= 0); \
  4862. ASSERT (MmTotalCommittedPages >= (_QuotaCharge)); \
  4863. InterlockedExchangeAddSizeT (&MmTotalCommittedPages, 0-((SIZE_T)(_QuotaCharge))); \
  4864. MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_NORMAL, (_QuotaCharge));
  4865. #endif
  4866. VOID
  4867. MiCauseOverCommitPopup (
  4868. VOID
  4869. );
  4870. extern SIZE_T MmTotalCommitLimitMaximum;
  4871. SIZE_T
  4872. MiCalculatePageCommitment (
  4873. IN PVOID StartingAddress,
  4874. IN PVOID EndingAddress,
  4875. IN PMMVAD Vad,
  4876. IN PEPROCESS Process
  4877. );
  4878. VOID
  4879. MiReturnPageTablePageCommitment (
  4880. IN PVOID StartingAddress,
  4881. IN PVOID EndingAddress,
  4882. IN PEPROCESS CurrentProcess,
  4883. IN PMMVAD PreviousVad,
  4884. IN PMMVAD NextVad
  4885. );
  4886. VOID
  4887. MiFlushAllPages (
  4888. VOID
  4889. );
  4890. VOID
  4891. MiModifiedPageWriterTimerDispatch (
  4892. IN PKDPC Dpc,
  4893. IN PVOID DeferredContext,
  4894. IN PVOID SystemArgument1,
  4895. IN PVOID SystemArgument2
  4896. );
  4897. LONGLONG
  4898. MiStartingOffset(
  4899. IN PSUBSECTION Subsection,
  4900. IN PMMPTE PteAddress
  4901. );
  4902. LARGE_INTEGER
  4903. MiEndingOffset(
  4904. IN PSUBSECTION Subsection
  4905. );
  4906. VOID
  4907. MiReloadBootLoadedDrivers (
  4908. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  4909. );
  4910. VOID
  4911. MiSetSystemCodeProtection (
  4912. IN PMMPTE FirstPte,
  4913. IN PMMPTE LastPte,
  4914. IN ULONG ProtectionMask
  4915. );
  4916. VOID
  4917. MiWriteProtectSystemImage (
  4918. IN PVOID DllBase
  4919. );
  4920. VOID
  4921. MiSetIATProtect (
  4922. IN PVOID DllBase,
  4923. IN ULONG Protection
  4924. );
  4925. VOID
  4926. MiMakeEntireImageCopyOnWrite (
  4927. IN PSUBSECTION Subsection
  4928. );
  4929. LOGICAL
  4930. MiInitializeLoadedModuleList (
  4931. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  4932. );
  4933. #define UNICODE_TAB 0x0009
  4934. #define UNICODE_LF 0x000A
  4935. #define UNICODE_CR 0x000D
  4936. #define UNICODE_SPACE 0x0020
  4937. #define UNICODE_CJK_SPACE 0x3000
  4938. #define UNICODE_WHITESPACE(_ch) (((_ch) == UNICODE_TAB) || \
  4939. ((_ch) == UNICODE_LF) || \
  4940. ((_ch) == UNICODE_CR) || \
  4941. ((_ch) == UNICODE_SPACE) || \
  4942. ((_ch) == UNICODE_CJK_SPACE) || \
  4943. ((_ch) == UNICODE_NULL))
  4944. extern ULONG MmSpecialPoolTag;
  4945. extern PVOID MmSpecialPoolStart;
  4946. extern PVOID MmSpecialPoolEnd;
  4947. extern PVOID MmSessionSpecialPoolStart;
  4948. extern PVOID MmSessionSpecialPoolEnd;
  4949. LOGICAL
  4950. MiInitializeSpecialPool (
  4951. IN POOL_TYPE PoolType
  4952. );
  4953. LOGICAL
  4954. MiIsSpecialPoolAddressNonPaged (
  4955. IN PVOID VirtualAddress
  4956. );
  4957. #if defined (_WIN64)
  4958. LOGICAL
  4959. MiInitializeSessionSpecialPool (
  4960. VOID
  4961. );
  4962. VOID
  4963. MiDeleteSessionSpecialPool (
  4964. VOID
  4965. );
  4966. #endif
  4967. #if defined (_X86_)
  4968. LOGICAL
  4969. MiRecoverSpecialPtes (
  4970. IN ULONG NumberOfPtes
  4971. );
  4972. #endif
  4973. VOID
  4974. MiEnableRandomSpecialPool (
  4975. IN LOGICAL Enable
  4976. );
  4977. LOGICAL
  4978. MiTriageSystem (
  4979. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  4980. );
  4981. LOGICAL
  4982. MiTriageAddDrivers (
  4983. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  4984. );
  4985. LOGICAL
  4986. MiTriageVerifyDriver (
  4987. IN PKLDR_DATA_TABLE_ENTRY DataTableEntry
  4988. );
  4989. extern ULONG MmTriageActionTaken;
  4990. #if defined (_WIN64)
  4991. #define MM_SPECIAL_POOL_PTES ((1024 * 1024) / sizeof (MMPTE))
  4992. #else
  4993. #define MM_SPECIAL_POOL_PTES (24 * PTE_PER_PAGE)
  4994. #endif
  4995. #define MI_SUSPECT_DRIVER_BUFFER_LENGTH 512
  4996. extern WCHAR MmVerifyDriverBuffer[];
  4997. extern ULONG MmVerifyDriverBufferLength;
  4998. extern ULONG MmVerifyDriverLevel;
  4999. extern LOGICAL MmSnapUnloads;
  5000. extern LOGICAL MmProtectFreedNonPagedPool;
  5001. extern ULONG MmEnforceWriteProtection;
  5002. extern LOGICAL MmTrackLockedPages;
  5003. extern ULONG MmTrackPtes;
  5004. #define VI_POOL_FREELIST_END ((ULONG_PTR)-1)
  5005. #define VI_POOL_PAGE_HEADER_SIGNATURE 0x21321345
  5006. typedef struct _VI_POOL_PAGE_HEADER {
  5007. PSLIST_ENTRY NextPage;
  5008. PVOID VerifierEntry;
  5009. ULONG_PTR Signature;
  5010. } VI_POOL_PAGE_HEADER, *PVI_POOL_PAGE_HEADER;
  5011. typedef struct _VI_POOL_ENTRY_INUSE {
  5012. PVOID VirtualAddress;
  5013. PVOID CallingAddress;
  5014. SIZE_T NumberOfBytes;
  5015. ULONG_PTR Tag;
  5016. } VI_POOL_ENTRY_INUSE, *PVI_POOL_ENTRY_INUSE;
  5017. typedef struct _VI_POOL_ENTRY {
  5018. union {
  5019. VI_POOL_PAGE_HEADER PageHeader;
  5020. VI_POOL_ENTRY_INUSE InUse;
  5021. PSLIST_ENTRY NextFree;
  5022. };
  5023. } VI_POOL_ENTRY, *PVI_POOL_ENTRY;
  5024. #define MI_VERIFIER_ENTRY_SIGNATURE 0x98761940
  5025. typedef struct _MI_VERIFIER_DRIVER_ENTRY {
  5026. LIST_ENTRY Links;
  5027. ULONG Loads;
  5028. ULONG Unloads;
  5029. UNICODE_STRING BaseName;
  5030. PVOID StartAddress;
  5031. PVOID EndAddress;
  5032. #define VI_VERIFYING_DIRECTLY 0x1
  5033. #define VI_VERIFYING_INVERSELY 0x2
  5034. #define VI_DISABLE_VERIFICATION 0x4
  5035. ULONG Flags;
  5036. ULONG_PTR Signature;
  5037. SLIST_HEADER PoolPageHeaders;
  5038. SLIST_HEADER PoolTrackers;
  5039. ULONG CurrentPagedPoolAllocations;
  5040. ULONG CurrentNonPagedPoolAllocations;
  5041. ULONG PeakPagedPoolAllocations;
  5042. ULONG PeakNonPagedPoolAllocations;
  5043. SIZE_T PagedBytes;
  5044. SIZE_T NonPagedBytes;
  5045. SIZE_T PeakPagedBytes;
  5046. SIZE_T PeakNonPagedBytes;
  5047. } MI_VERIFIER_DRIVER_ENTRY, *PMI_VERIFIER_DRIVER_ENTRY;
  5048. typedef struct _MI_VERIFIER_POOL_HEADER {
  5049. PVI_POOL_ENTRY VerifierPoolEntry;
  5050. } MI_VERIFIER_POOL_HEADER, *PMI_VERIFIER_POOL_HEADER;
  5051. typedef struct _MM_DRIVER_VERIFIER_DATA {
  5052. ULONG Level;
  5053. ULONG RaiseIrqls;
  5054. ULONG AcquireSpinLocks;
  5055. ULONG SynchronizeExecutions;
  5056. ULONG AllocationsAttempted;
  5057. ULONG AllocationsSucceeded;
  5058. ULONG AllocationsSucceededSpecialPool;
  5059. ULONG AllocationsWithNoTag;
  5060. ULONG TrimRequests;
  5061. ULONG Trims;
  5062. ULONG AllocationsFailed;
  5063. ULONG AllocationsFailedDeliberately;
  5064. ULONG Loads;
  5065. ULONG Unloads;
  5066. ULONG UnTrackedPool;
  5067. ULONG UserTrims;
  5068. ULONG CurrentPagedPoolAllocations;
  5069. ULONG CurrentNonPagedPoolAllocations;
  5070. ULONG PeakPagedPoolAllocations;
  5071. ULONG PeakNonPagedPoolAllocations;
  5072. SIZE_T PagedBytes;
  5073. SIZE_T NonPagedBytes;
  5074. SIZE_T PeakPagedBytes;
  5075. SIZE_T PeakNonPagedBytes;
  5076. ULONG BurstAllocationsFailedDeliberately;
  5077. ULONG SessionTrims;
  5078. ULONG Reserved[2];
  5079. } MM_DRIVER_VERIFIER_DATA, *PMM_DRIVER_VERIFIER_DATA;
  5080. VOID
  5081. MiInitializeDriverVerifierList (
  5082. VOID
  5083. );
  5084. LOGICAL
  5085. MiInitializeVerifyingComponents (
  5086. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  5087. );
  5088. LOGICAL
  5089. MiApplyDriverVerifier (
  5090. IN PKLDR_DATA_TABLE_ENTRY,
  5091. IN PMI_VERIFIER_DRIVER_ENTRY Verifier
  5092. );
  5093. VOID
  5094. MiReApplyVerifierToLoadedModules(
  5095. IN PLIST_ENTRY ModuleListHead
  5096. );
  5097. VOID
  5098. MiVerifyingDriverUnloading (
  5099. IN PKLDR_DATA_TABLE_ENTRY DataTableEntry
  5100. );
  5101. VOID
  5102. MiVerifierCheckThunks (
  5103. IN PKLDR_DATA_TABLE_ENTRY DataTableEntry
  5104. );
  5105. extern ULONG MiActiveVerifierThunks;
  5106. extern LIST_ENTRY MiSuspectDriverList;
  5107. extern ULONG MiVerifierThunksAdded;
  5108. VOID
  5109. MiEnableKernelVerifier (
  5110. VOID
  5111. );
  5112. extern LOGICAL KernelVerifier;
  5113. extern MM_DRIVER_VERIFIER_DATA MmVerifierData;
  5114. #define MI_FREED_SPECIAL_POOL_SIGNATURE 0x98764321
  5115. #define MI_STACK_BYTES 1024
  5116. typedef struct _MI_FREED_SPECIAL_POOL {
  5117. POOL_HEADER OverlaidPoolHeader;
  5118. MI_VERIFIER_POOL_HEADER OverlaidVerifierPoolHeader;
  5119. ULONG Signature;
  5120. ULONG TickCount;
  5121. ULONG NumberOfBytesRequested;
  5122. ULONG Pagable;
  5123. PVOID VirtualAddress;
  5124. PVOID StackPointer;
  5125. ULONG StackBytes;
  5126. PETHREAD Thread;
  5127. UCHAR StackData[MI_STACK_BYTES];
  5128. } MI_FREED_SPECIAL_POOL, *PMI_FREED_SPECIAL_POOL;
  5129. #define MM_DBG_COMMIT_NONPAGED_POOL_EXPANSION 0
  5130. #define MM_DBG_COMMIT_PAGED_POOL_PAGETABLE 1
  5131. #define MM_DBG_COMMIT_PAGED_POOL_PAGES 2
  5132. #define MM_DBG_COMMIT_SESSION_POOL_PAGE_TABLES 3
  5133. #define MM_DBG_COMMIT_ALLOCVM1 4
  5134. #define MM_DBG_COMMIT_ALLOCVM_SEGMENT 5
  5135. #define MM_DBG_COMMIT_IMAGE 6
  5136. #define MM_DBG_COMMIT_PAGEFILE_BACKED_SHMEM 7
  5137. #define MM_DBG_COMMIT_INDEPENDENT_PAGES 8
  5138. #define MM_DBG_COMMIT_CONTIGUOUS_PAGES 9
  5139. #define MM_DBG_COMMIT_MDL_PAGES 0xA
  5140. #define MM_DBG_COMMIT_NONCACHED_PAGES 0xB
  5141. #define MM_DBG_COMMIT_MAPVIEW_DATA 0xC
  5142. #define MM_DBG_COMMIT_FILL_SYSTEM_DIRECTORY 0xD
  5143. #define MM_DBG_COMMIT_EXTRA_SYSTEM_PTES 0xE
  5144. #define MM_DBG_COMMIT_DRIVER_PAGING_AT_INIT 0xF
  5145. #define MM_DBG_COMMIT_PAGEFILE_FULL 0x10
  5146. #define MM_DBG_COMMIT_PROCESS_CREATE 0x11
  5147. #define MM_DBG_COMMIT_KERNEL_STACK_CREATE 0x12
  5148. #define MM_DBG_COMMIT_SET_PROTECTION 0x13
  5149. #define MM_DBG_COMMIT_SESSION_CREATE 0x14
  5150. #define MM_DBG_COMMIT_SESSION_IMAGE_PAGES 0x15
  5151. #define MM_DBG_COMMIT_SESSION_PAGETABLE_PAGES 0x16
  5152. #define MM_DBG_COMMIT_SESSION_SHARED_IMAGE 0x17
  5153. #define MM_DBG_COMMIT_DRIVER_PAGES 0x18
  5154. #define MM_DBG_COMMIT_INSERT_VAD 0x19
  5155. #define MM_DBG_COMMIT_SESSION_WS_INIT 0x1A
  5156. #define MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_PAGES 0x1B
  5157. #define MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_HASHPAGES 0x1C
  5158. #define MM_DBG_COMMIT_SPECIAL_POOL_PAGES 0x1D
  5159. #define MM_DBG_COMMIT_SPECIAL_POOL_MAPPING_PAGES 0x1E
  5160. #define MM_DBG_COMMIT_SMALL 0x1F
  5161. #define MM_DBG_COMMIT_EXTRA_WS_PAGES 0x20
  5162. #define MM_DBG_COMMIT_EXTRA_INITIAL_SESSION_WS_PAGES 0x21
  5163. #define MM_DBG_COMMIT_ALLOCVM_PROCESS 0x22
  5164. #define MM_DBG_COMMIT_INSERT_VAD_PT 0x23
  5165. #define MM_DBG_COMMIT_ALLOCVM_PROCESS2 0x24
  5166. #define MM_DBG_COMMIT_CHARGE_NORMAL 0x25
  5167. #define MM_DBG_COMMIT_CHARGE_CAUSE_POPUP 0x26
  5168. #define MM_DBG_COMMIT_CHARGE_CANT_EXPAND 0x27
  5169. #define MM_DBG_COMMIT_LARGE_VA_PAGES 0x28
  5170. #define MM_DBG_COMMIT_LOAD_SYSTEM_IMAGE_TEMP 0x29
  5171. #define MM_DBG_COMMIT_RETURN_NONPAGED_POOL_EXPANSION 0x40
  5172. #define MM_DBG_COMMIT_RETURN_PAGED_POOL_PAGES 0x41
  5173. #define MM_DBG_COMMIT_RETURN_SESSION_DATAPAGE 0x42
  5174. #define MM_DBG_COMMIT_RETURN_ALLOCVM_SEGMENT 0x43
  5175. #define MM_DBG_COMMIT_RETURN_ALLOCVM2 0x44
  5176. #define MM_DBG_COMMIT_RETURN_IMAGE_NO_LARGE_CA 0x46
  5177. #define MM_DBG_COMMIT_RETURN_PTE_RANGE 0x47
  5178. #define MM_DBG_COMMIT_RETURN_NTFREEVM1 0x48
  5179. #define MM_DBG_COMMIT_RETURN_NTFREEVM2 0x49
  5180. #define MM_DBG_COMMIT_RETURN_INDEPENDENT_PAGES 0x4A
  5181. #define MM_DBG_COMMIT_RETURN_AWE_EXCESS 0x4B
  5182. #define MM_DBG_COMMIT_RETURN_MDL_PAGES 0x4C
  5183. #define MM_DBG_COMMIT_RETURN_NONCACHED_PAGES 0x4D
  5184. #define MM_DBG_COMMIT_RETURN_SESSION_CREATE_FAILURE 0x4E
  5185. #define MM_DBG_COMMIT_RETURN_PAGETABLES 0x4F
  5186. #define MM_DBG_COMMIT_RETURN_PROTECTION 0x50
  5187. #define MM_DBG_COMMIT_RETURN_SEGMENT_DELETE1 0x51
  5188. #define MM_DBG_COMMIT_RETURN_SEGMENT_DELETE2 0x52
  5189. #define MM_DBG_COMMIT_RETURN_PAGEFILE_FULL 0x53
  5190. #define MM_DBG_COMMIT_RETURN_SESSION_DEREFERENCE 0x54
  5191. #define MM_DBG_COMMIT_RETURN_VAD 0x55
  5192. #define MM_DBG_COMMIT_RETURN_PROCESS_CREATE_FAILURE1 0x56
  5193. #define MM_DBG_COMMIT_RETURN_PROCESS_DELETE 0x57
  5194. #define MM_DBG_COMMIT_RETURN_PROCESS_CLEAN_PAGETABLES 0x58
  5195. #define MM_DBG_COMMIT_RETURN_KERNEL_STACK_DELETE 0x59
  5196. #define MM_DBG_COMMIT_RETURN_SESSION_DRIVER_LOAD_FAILURE1 0x5A
  5197. #define MM_DBG_COMMIT_RETURN_DRIVER_INIT_CODE 0x5B
  5198. #define MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD 0x5C
  5199. #define MM_DBG_COMMIT_RETURN_DRIVER_UNLOAD1 0x5D
  5200. #define MM_DBG_COMMIT_RETURN_NORMAL 0x5E
  5201. #define MM_DBG_COMMIT_RETURN_PF_FULL_EXTEND 0x5F
  5202. #define MM_DBG_COMMIT_RETURN_EXTENDED 0x60
  5203. #define MM_DBG_COMMIT_RETURN_SEGMENT_DELETE3 0x61
  5204. #define MM_DBG_COMMIT_CHARGE_LARGE_PAGES 0x62
  5205. #define MM_DBG_COMMIT_RETURN_LARGE_PAGES 0x63
  5206. #if 0
  5207. #define MM_COMMIT_COUNTER_MAX 0x80
  5208. #define MM_TRACK_COMMIT(_index, bump) \
  5209. if (_index >= MM_COMMIT_COUNTER_MAX) { \
  5210. DbgPrint("Mm: Invalid commit counter %d %d\n", _index, MM_COMMIT_COUNTER_MAX); \
  5211. DbgBreakPoint(); \
  5212. } \
  5213. else { \
  5214. InterlockedExchangeAddSizeT (&MmTrackCommit[_index], bump); \
  5215. }
  5216. #define MM_TRACK_COMMIT_REDUCTION(_index, bump) \
  5217. if (_index >= MM_COMMIT_COUNTER_MAX) { \
  5218. DbgPrint("Mm: Invalid commit counter %d %d\n", _index, MM_COMMIT_COUNTER_MAX); \
  5219. DbgBreakPoint(); \
  5220. } \
  5221. else { \
  5222. InterlockedExchangeAddSizeT (&MmTrackCommit[_index], 0 - (bump)); \
  5223. }
  5224. extern SIZE_T MmTrackCommit[MM_COMMIT_COUNTER_MAX];
  5225. #define MI_INCREMENT_TOTAL_PROCESS_COMMIT(_charge) InterlockedExchangeAddSizeT (&MmTotalProcessCommit, (_charge));
  5226. #else
  5227. #define MM_TRACK_COMMIT(_index, bump)
  5228. #define MM_TRACK_COMMIT_REDUCTION(_index, bump)
  5229. #define MI_INCREMENT_TOTAL_PROCESS_COMMIT(_charge)
  5230. #endif
  5231. //
  5232. // Types of resident available page charges.
  5233. //
  5234. #define MM_RESAVAIL_ALLOCATE_ZERO_PAGE_CLUSTERS 0
  5235. #define MM_RESAVAIL_ALLOCATE_PAGETABLES_FOR_PAGED_POOL 1
  5236. #define MM_RESAVAIL_ALLOCATE_GROW_BSTORE 2
  5237. #define MM_RESAVAIL_ALLOCATE_CONTIGUOUS 3
  5238. #define MM_RESAVAIL_FREE_OUTPAGE_BSTORE 4
  5239. #define MM_RESAVAIL_FREE_PAGE_DRIVER 5
  5240. #define MM_RESAVAIL_ALLOCATE_CREATE_PROCESS 6
  5241. #define MM_RESAVAIL_FREE_DELETE_PROCESS 7
  5242. #define MM_RESAVAIL_FREE_CLEAN_PROCESS2 8
  5243. #define MM_RESAVAIL_ALLOCATE_CREATE_STACK 9
  5244. #define MM_RESAVAIL_FREE_DELETE_STACK 10
  5245. #define MM_RESAVAIL_ALLOCATE_GROW_STACK 11
  5246. #define MM_RESAVAIL_FREE_OUTPAGE_STACK 12
  5247. #define MM_RESAVAIL_FREE_LOAD_SYSTEM_IMAGE_EXCESS 13
  5248. #define MM_RESAVAIL_ALLOCATE_LOAD_SYSTEM_IMAGE 14
  5249. #define MM_RESAVAIL_FREE_LOAD_SYSTEM_IMAGE1 15
  5250. #define MM_RESAVAIL_FREE_LOAD_SYSTEM_IMAGE2 16
  5251. #define MM_RESAVAIL_FREE_LOAD_SYSTEM_IMAGE3 17
  5252. #define MM_RESAVAIL_FREE_DRIVER_INITIALIZATION 18
  5253. #define MM_RESAVAIL_FREE_SET_DRIVER_PAGING 19
  5254. #define MM_RESAVAIL_FREE_CONTIGUOUS2 20
  5255. #define MM_RESAVAIL_FREE_UNLOAD_SYSTEM_IMAGE1 21
  5256. #define MM_RESAVAIL_FREE_UNLOAD_SYSTEM_IMAGE 22
  5257. #define MM_RESAVAIL_FREE_EXPANSION_NONPAGED_POOL 23
  5258. #define MM_RESAVAIL_ALLOCATE_EXPANSION_NONPAGED_POOL 24
  5259. #define MM_RESAVAIL_ALLOCATE_LOCK_CODE1 25
  5260. #define MM_RESAVAIL_ALLOCATE_LOCK_CODE3 26
  5261. #define MM_RESAVAIL_ALLOCATEORFREE_WS_ADJUST 27
  5262. #define MM_RESAVAIL_ALLOCATE_INDEPENDENT 28
  5263. #define MM_RESAVAIL_ALLOCATE_LOCK_CODE2 29
  5264. #define MM_RESAVAIL_FREE_INDEPENDENT 30
  5265. #define MM_RESAVAIL_ALLOCATE_NONPAGED_SPECIAL_POOL 31
  5266. #define MM_RESAVAIL_FREE_CONTIGUOUS 32
  5267. #define MM_RESAVAIL_ALLOCATE_SPECIAL_POOL_EXPANSION 33
  5268. #define MM_RESAVAIL_ALLOCATE_FOR_MDL 34
  5269. #define MM_RESAVAIL_FREE_FROM_MDL 35
  5270. #define MM_RESAVAIL_FREE_AWE 36
  5271. #define MM_RESAVAIL_FREE_NONPAGED_SPECIAL_POOL 37
  5272. #define MM_RESAVAIL_FREE_FOR_MDL_EXCESS 38
  5273. #define MM_RESAVAIL_ALLOCATE_HOTADD_PFNDB 39
  5274. #define MM_RESAVAIL_ALLOCATE_CREATE_SESSION 40
  5275. #define MM_RESAVAIL_FREE_CLEAN_PROCESS1 41
  5276. #define MM_RESAVAIL_ALLOCATE_SINGLE_PFN 42
  5277. #define MM_RESAVAIL_ALLOCATEORFREE_WS_ADJUST1 43
  5278. #define MM_RESAVAIL_ALLOCATE_SESSION_PAGE_TABLES 44
  5279. #define MM_RESAVAIL_ALLOCATE_SESSION_IMAGE 45
  5280. #define MM_RESAVAIL_ALLOCATE_BUILDMDL 46
  5281. #define MM_RESAVAIL_FREE_BUILDMDL_EXCESS 47
  5282. #define MM_RESAVAIL_ALLOCATE_ADD_WS_PAGE 48
  5283. #define MM_RESAVAIL_FREE_CREATE_SESSION 49
  5284. #define MM_RESAVAIL_ALLOCATE_INIT_SESSION_WS 50
  5285. #define MM_RESAVAIL_FREE_SESSION_PAGE_TABLE 51
  5286. #define MM_RESAVAIL_FREE_DEREFERENCE_SESSION 52
  5287. #define MM_RESAVAIL_FREE_DEREFERENCE_SESSION_PAGES 53
  5288. #define MM_RESAVAIL_ALLOCATEORFREE_WS_ADJUST2 54
  5289. #define MM_RESAVAIL_ALLOCATEORFREE_WS_ADJUST3 55
  5290. #define MM_RESAVAIL_FREE_DEREFERENCE_SESSION_WS 56
  5291. #define MM_RESAVAIL_FREE_LOAD_SESSION_IMAGE1 57
  5292. #define MM_RESAVAIL_ALLOCATE_USER_PAGE_TABLE 58
  5293. #define MM_RESAVAIL_FREE_USER_PAGE_TABLE 59
  5294. #define MM_RESAVAIL_FREE_HOTADD_MEMORY 60
  5295. #define MM_RESAVAIL_ALLOCATE_HOTREMOVE_MEMORY 61
  5296. #define MM_RESAVAIL_FREE_HOTREMOVE_MEMORY1 62
  5297. #define MM_RESAVAIL_FREE_HOTREMOVE_FAILED 63
  5298. #define MM_RESAVAIL_FREE_HOTADD_ECC 64
  5299. #define MM_RESAVAIL_ALLOCATE_COMPRESSION 65
  5300. #define MM_RESAVAIL_FREE_COMPRESSION 66
  5301. #define MM_RESAVAIL_ALLOCATE_LARGE_PAGES 67
  5302. #define MM_RESAVAIL_FREE_LARGE_PAGES 68
  5303. #define MM_RESAVAIL_ALLOCATE_LOAD_SYSTEM_IMAGE_TEMP 69
  5304. #define MM_RESAVAIL_ALLOCATE_WSLE_HASH 70
  5305. #define MM_RESAVAIL_FREE_WSLE_HASH 71
  5306. #define MM_RESAVAIL_FREE_CLEAN_PROCESS_WS 72
  5307. #define MM_RESAVAIL_FREE_SESSION_PAGE_TABLES_EXCESS 73
  5308. #define MM_BUMP_COUNTER_MAX 74
  5309. extern SIZE_T MmResTrack[MM_BUMP_COUNTER_MAX];
  5310. #define MI_INCREMENT_RESIDENT_AVAILABLE(bump, _index) \
  5311. InterlockedExchangeAddSizeT (&MmResidentAvailablePages, (SIZE_T)(bump)); \
  5312. ASSERT (_index < MM_BUMP_COUNTER_MAX); \
  5313. InterlockedExchangeAddSizeT (&MmResTrack[_index], (SIZE_T)(bump));
  5314. #define MI_DECREMENT_RESIDENT_AVAILABLE(bump, _index) \
  5315. InterlockedExchangeAddSizeT (&MmResidentAvailablePages, 0-(SIZE_T)(bump)); \
  5316. ASSERT (_index < MM_BUMP_COUNTER_MAX); \
  5317. InterlockedExchangeAddSizeT (&MmResTrack[_index], (SIZE_T)(bump));
  5318. //++
  5319. //PFN_NUMBER
  5320. //MI_NONPAGABLE_MEMORY_AVAILABLE(
  5321. // VOID
  5322. // );
  5323. //
  5324. // Routine Description:
  5325. //
  5326. // This routine lets callers know how many pages can be charged against
  5327. // the resident available, factoring in earlier Mm promises that
  5328. // may not have been redeemed at this point (ie: nonpaged pool expansion,
  5329. // etc, that must be honored at a later point if requested).
  5330. //
  5331. // Arguments
  5332. //
  5333. // None.
  5334. //
  5335. // Return Value:
  5336. //
  5337. // The number of currently available pages in the resident available.
  5338. //
  5339. // N.B. This is a signed quantity and can be negative.
  5340. //
  5341. //--
  5342. #define MI_NONPAGABLE_MEMORY_AVAILABLE() \
  5343. ((SPFN_NUMBER) \
  5344. (MmResidentAvailablePages - \
  5345. MmSystemLockPagesCount))
  5346. extern ULONG MmLargePageMinimum;
  5347. //
  5348. // hack stuff for testing.
  5349. //
  5350. VOID
  5351. MiDumpValidAddresses (
  5352. VOID
  5353. );
  5354. VOID
  5355. MiDumpPfn ( VOID );
  5356. VOID
  5357. MiDumpWsl ( VOID );
  5358. VOID
  5359. MiFormatPte (
  5360. IN PMMPTE PointerPte
  5361. );
  5362. VOID
  5363. MiCheckPfn ( VOID );
  5364. VOID
  5365. MiCheckPte ( VOID );
  5366. VOID
  5367. MiFormatPfn (
  5368. IN PMMPFN PointerPfn
  5369. );
  5370. extern const MMPTE ZeroPte;
  5371. extern const MMPTE ZeroKernelPte;
  5372. extern const MMPTE ValidKernelPteLocal;
  5373. extern MMPTE ValidKernelPte;
  5374. extern MMPTE ValidKernelPde;
  5375. extern const MMPTE ValidKernelPdeLocal;
  5376. extern const MMPTE ValidUserPte;
  5377. extern const MMPTE ValidPtePte;
  5378. extern const MMPTE ValidPdePde;
  5379. extern MMPTE DemandZeroPde;
  5380. extern const MMPTE DemandZeroPte;
  5381. extern MMPTE KernelPrototypePte;
  5382. extern const MMPTE TransitionPde;
  5383. extern MMPTE PrototypePte;
  5384. extern const MMPTE NoAccessPte;
  5385. extern ULONG_PTR MmSubsectionBase;
  5386. extern ULONG_PTR MmSubsectionTopPage;
  5387. extern ULONG ExpMultiUserTS;
  5388. //
  5389. // Virtual alignment for PTEs (machine specific) minimum value is
  5390. // 4k maximum value is 64k. The maximum value can be raised by
  5391. // changing the MM_PROTO_PTE_ALIGNMENT constant and adding more
  5392. // reserved mapping PTEs in hyperspace.
  5393. //
  5394. //
  5395. // Total number of physical pages on the system.
  5396. //
  5397. extern PFN_COUNT MmNumberOfPhysicalPages;
  5398. //
  5399. // Highest possible physical page number in the system.
  5400. //
  5401. extern PFN_NUMBER MmHighestPossiblePhysicalPage;
  5402. #if defined (_WIN64)
  5403. #define MI_DTC_MAX_PAGES ((PFN_NUMBER)(((ULONG64)512 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5404. #define MI_DTC_BOOTED_3GB_MAX_PAGES MI_DTC_MAX_PAGES
  5405. #define MI_ADS_MAX_PAGES ((PFN_NUMBER)(((ULONG64)64 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5406. #define MI_DEFAULT_MAX_PAGES ((PFN_NUMBER)(((ULONG64)16 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5407. #else
  5408. #define MI_DTC_MAX_PAGES ((PFN_NUMBER)(((ULONG64)128 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5409. #define MI_DTC_BOOTED_3GB_MAX_PAGES ((PFN_NUMBER)(((ULONG64)16 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5410. #define MI_ADS_MAX_PAGES ((PFN_NUMBER)(((ULONG64)32 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5411. #define MI_DEFAULT_MAX_PAGES ((PFN_NUMBER)(((ULONG64)4 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5412. #endif
  5413. #define MI_BLADE_MAX_PAGES ((PFN_NUMBER)(((ULONG64)2 * 1024 * 1024 * 1024) >> PAGE_SHIFT))
  5414. extern RTL_BITMAP MiPfnBitMap;
  5415. FORCEINLINE
  5416. LOGICAL
  5417. MI_IS_PFN (
  5418. IN PFN_NUMBER PageFrameIndex
  5419. )
  5420. /*++
  5421. Routine Description:
  5422. Check if a given address is backed by RAM or IO space.
  5423. Arguments:
  5424. PageFrameIndex - Supplies a page frame number to check.
  5425. Return Value:
  5426. TRUE - If the address is backed by RAM.
  5427. FALSE - If the address is IO mapped memory.
  5428. Environment:
  5429. Kernel mode. PFN lock or dynamic memory mutex may be held.
  5430. --*/
  5431. {
  5432. if (PageFrameIndex > MmHighestPossiblePhysicalPage) {
  5433. return FALSE;
  5434. }
  5435. return MI_CHECK_BIT (MiPfnBitMap.Buffer, PageFrameIndex);
  5436. }
  5437. //
  5438. // Total number of available pages on the system. This
  5439. // is the sum of the pages on the zeroed, free and standby lists.
  5440. //
  5441. extern PFN_NUMBER MmAvailablePages;
  5442. //
  5443. // Total number physical pages which would be usable if every process
  5444. // was at it's minimum working set size. This value is initialized
  5445. // at system initialization to MmAvailablePages - MM_FLUID_PHYSICAL_PAGES.
  5446. // Everytime a thread is created, the kernel stack is subtracted from
  5447. // this and every time a process is created, the minimum working set
  5448. // is subtracted from this. If the value would become negative, the
  5449. // operation (create process/kernel stack/ adjust working set) fails.
  5450. // The PFN LOCK must be owned to manipulate this value.
  5451. //
  5452. extern SPFN_NUMBER MmResidentAvailablePages;
  5453. //
  5454. // The total number of pages which would be removed from working sets
  5455. // if every working set was at its minimum.
  5456. //
  5457. extern PFN_NUMBER MmPagesAboveWsMinimum;
  5458. //
  5459. // If memory is becoming short and MmPagesAboveWsMinimum is
  5460. // greater than MmPagesAboveWsThreshold, trim working sets.
  5461. //
  5462. extern PFN_NUMBER MmPlentyFreePages;
  5463. extern PFN_NUMBER MmPagesAboveWsThreshold;
  5464. extern LONG MiDelayPageFaults;
  5465. extern PMMPFN MmPfnDatabase;
  5466. extern MMPFNLIST MmZeroedPageListHead;
  5467. extern MMPFNLIST MmFreePageListHead;
  5468. extern MMPFNLIST MmStandbyPageListHead;
  5469. extern MMPFNLIST MmRomPageListHead;
  5470. extern MMPFNLIST MmModifiedPageListHead;
  5471. extern MMPFNLIST MmModifiedNoWritePageListHead;
  5472. extern MMPFNLIST MmBadPageListHead;
  5473. extern PMMPFNLIST MmPageLocationList[NUMBER_OF_PAGE_LISTS];
  5474. extern MMPFNLIST MmModifiedPageListByColor[MM_MAXIMUM_NUMBER_OF_COLORS];
  5475. //
  5476. // Mask for isolating secondary color from physical page number.
  5477. //
  5478. extern ULONG MmSecondaryColorMask;
  5479. //
  5480. // Mask for isolating node color from combined node and secondary
  5481. // color.
  5482. //
  5483. extern ULONG MmSecondaryColorNodeMask;
  5484. //
  5485. // Width of MmSecondaryColorMask in bits. In multi node systems,
  5486. // the node number is combined with the secondary color to make up
  5487. // the page color.
  5488. //
  5489. extern UCHAR MmSecondaryColorNodeShift;
  5490. //
  5491. // Events for available pages, set means pages are available.
  5492. //
  5493. extern KEVENT MmAvailablePagesEvent;
  5494. extern KEVENT MmAvailablePagesEventMedium;
  5495. extern KEVENT MmAvailablePagesEventHigh;
  5496. //
  5497. // Event for the zeroing page thread.
  5498. //
  5499. extern KEVENT MmZeroingPageEvent;
  5500. //
  5501. // Boolean to indicate if the zeroing page thread is currently
  5502. // active. This is set to true when the zeroing page event is
  5503. // set and set to false when the zeroing page thread is done
  5504. // zeroing all the pages on the free list.
  5505. //
  5506. extern BOOLEAN MmZeroingPageThreadActive;
  5507. //
  5508. // Minimum number of free pages before zeroing page thread starts.
  5509. //
  5510. extern PFN_NUMBER MmMinimumFreePagesToZero;
  5511. //
  5512. // Global event to synchronize mapped writing with cleaning segments.
  5513. //
  5514. extern KEVENT MmMappedFileIoComplete;
  5515. //
  5516. // Hyper space items.
  5517. //
  5518. extern PMMPTE MmFirstReservedMappingPte;
  5519. extern PMMPTE MmLastReservedMappingPte;
  5520. //
  5521. // System space sizes - MmNonPagedSystemStart to MM_NON_PAGED_SYSTEM_END
  5522. // defines the ranges of PDEs which must be copied into a new process's
  5523. // address space.
  5524. //
  5525. extern PVOID MmNonPagedSystemStart;
  5526. extern PCHAR MmSystemSpaceViewStart;
  5527. extern LOGICAL MmProtectFreedNonPagedPool;
  5528. //
  5529. // Pool sizes.
  5530. //
  5531. extern SIZE_T MmSizeOfNonPagedPoolInBytes;
  5532. extern SIZE_T MmMinimumNonPagedPoolSize;
  5533. extern SIZE_T MmDefaultMaximumNonPagedPool;
  5534. extern ULONG MmMaximumNonPagedPoolPercent;
  5535. extern ULONG MmMinAdditionNonPagedPoolPerMb;
  5536. extern ULONG MmMaxAdditionNonPagedPoolPerMb;
  5537. extern SIZE_T MmSizeOfPagedPoolInBytes;
  5538. extern PFN_NUMBER MmSizeOfPagedPoolInPages;
  5539. extern SIZE_T MmMaximumNonPagedPoolInBytes;
  5540. extern PFN_NUMBER MmMaximumNonPagedPoolInPages;
  5541. extern PFN_NUMBER MmAllocatedNonPagedPool;
  5542. extern PVOID MmNonPagedPoolExpansionStart;
  5543. extern ULONG MmExpandedPoolBitPosition;
  5544. extern PFN_NUMBER MmNumberOfFreeNonPagedPool;
  5545. extern PFN_NUMBER MmNumberOfSystemPtes;
  5546. extern ULONG MiRequestedSystemPtes;
  5547. extern PMMPTE MmSystemPagePtes;
  5548. extern ULONG MmSystemPageDirectory[];
  5549. extern SIZE_T MmHeapSegmentReserve;
  5550. extern SIZE_T MmHeapSegmentCommit;
  5551. extern SIZE_T MmHeapDeCommitTotalFreeThreshold;
  5552. extern SIZE_T MmHeapDeCommitFreeBlockThreshold;
  5553. #define MI_MAX_FREE_LIST_HEADS 4
  5554. extern LIST_ENTRY MmNonPagedPoolFreeListHead[MI_MAX_FREE_LIST_HEADS];
  5555. //
  5556. // Counter for flushes of the entire TB.
  5557. //
  5558. extern ULONG MmFlushCounter;
  5559. //
  5560. // Pool start and end.
  5561. //
  5562. extern PVOID MmNonPagedPoolStart;
  5563. extern PVOID MmNonPagedPoolEnd;
  5564. extern PVOID MmPagedPoolStart;
  5565. extern PVOID MmPagedPoolEnd;
  5566. //
  5567. // Pool bit maps and other related structures.
  5568. //
  5569. typedef struct _MM_PAGED_POOL_INFO {
  5570. PRTL_BITMAP PagedPoolAllocationMap;
  5571. PRTL_BITMAP EndOfPagedPoolBitmap;
  5572. PMMPTE FirstPteForPagedPool;
  5573. PMMPTE LastPteForPagedPool;
  5574. PMMPTE NextPdeForPagedPoolExpansion;
  5575. ULONG PagedPoolHint;
  5576. SIZE_T PagedPoolCommit;
  5577. SIZE_T AllocatedPagedPool;
  5578. } MM_PAGED_POOL_INFO, *PMM_PAGED_POOL_INFO;
  5579. extern MM_PAGED_POOL_INFO MmPagedPoolInfo;
  5580. extern PVOID MmPageAlignedPoolBase[2];
  5581. extern PRTL_BITMAP VerifierLargePagedPoolMap;
  5582. //
  5583. // MmFirstFreeSystemPte contains the offset from the
  5584. // Nonpaged system base to the first free system PTE.
  5585. // Note, that an offset of zero indicates an empty list.
  5586. //
  5587. extern MMPTE MmFirstFreeSystemPte[MaximumPtePoolTypes];
  5588. extern ULONG_PTR MiSystemViewStart;
  5589. //
  5590. // System cache sizes.
  5591. //
  5592. extern PMMWSL MmSystemCacheWorkingSetList;
  5593. extern PMMWSLE MmSystemCacheWsle;
  5594. extern PVOID MmSystemCacheStart;
  5595. extern PVOID MmSystemCacheEnd;
  5596. extern PFN_NUMBER MmSystemCacheWsMinimum;
  5597. extern PFN_NUMBER MmSystemCacheWsMaximum;
  5598. //
  5599. // Virtual alignment for PTEs (machine specific) minimum value is
  5600. // 0 (no alignment) maximum value is 64k. The maximum value can be raised by
  5601. // changing the MM_PROTO_PTE_ALIGNMENT constant and adding more
  5602. // reserved mapping PTEs in hyperspace.
  5603. //
  5604. extern ULONG MmAliasAlignment;
  5605. //
  5606. // Mask to AND with virtual address to get an offset to go
  5607. // with the alignment. This value is page aligned.
  5608. //
  5609. extern ULONG MmAliasAlignmentOffset;
  5610. //
  5611. // Mask to and with PTEs to determine if the alias mapping is compatible.
  5612. // This value is usually (MmAliasAlignment - 1)
  5613. //
  5614. extern ULONG MmAliasAlignmentMask;
  5615. //
  5616. // Cells to track unused thread kernel stacks to avoid TB flushes
  5617. // every time a thread terminates.
  5618. //
  5619. extern ULONG MmMaximumDeadKernelStacks;
  5620. extern SLIST_HEADER MmDeadStackSListHead;
  5621. //
  5622. // MmSystemPteBase contains the address of 1 PTE before
  5623. // the first free system PTE (zero indicates an empty list).
  5624. // The value of this field does not change once set.
  5625. //
  5626. extern PMMPTE MmSystemPteBase;
  5627. //
  5628. // Root of system space virtual address descriptors. These define
  5629. // the pagable portion of the system.
  5630. //
  5631. extern PMMVAD MmVirtualAddressDescriptorRoot;
  5632. extern MM_AVL_TABLE MmSectionBasedRoot;
  5633. extern PVOID MmHighSectionBase;
  5634. //
  5635. // Section commit mutex.
  5636. //
  5637. extern KGUARDED_MUTEX MmSectionCommitMutex;
  5638. //
  5639. // Section base address mutex.
  5640. //
  5641. extern KGUARDED_MUTEX MmSectionBasedMutex;
  5642. //
  5643. // Resource for section extension.
  5644. //
  5645. extern ERESOURCE MmSectionExtendResource;
  5646. extern ERESOURCE MmSectionExtendSetResource;
  5647. //
  5648. // Inpage cluster sizes for executable pages (set based on memory size).
  5649. //
  5650. extern ULONG MmDataClusterSize;
  5651. extern ULONG MmCodeClusterSize;
  5652. //
  5653. // Pagefile creation mutex.
  5654. //
  5655. extern KGUARDED_MUTEX MmPageFileCreationLock;
  5656. //
  5657. // Event to set when first paging file is created.
  5658. //
  5659. extern PKEVENT MmPagingFileCreated;
  5660. //
  5661. // Paging file debug information.
  5662. //
  5663. extern ULONG_PTR MmPagingFileDebug[];
  5664. //
  5665. // Fast mutex which guards the working set list for the system shared
  5666. // address space (paged pool, system cache, pagable drivers).
  5667. //
  5668. extern FAST_MUTEX MmSystemWsLock;
  5669. //
  5670. // Spin lock for allowing working set expansion.
  5671. //
  5672. extern KSPIN_LOCK MmExpansionLock;
  5673. //
  5674. // To prevent optimizations.
  5675. //
  5676. extern MMPTE GlobalPte;
  5677. //
  5678. // Page color for system working set.
  5679. //
  5680. extern ULONG MmSystemPageColor;
  5681. extern ULONG MmSecondaryColors;
  5682. extern ULONG MmProcessColorSeed;
  5683. //
  5684. // Set from ntos\config\CMDAT3.C Used by customers to disable paging
  5685. // of executive on machines with lots of memory. Worth a few TPS on a
  5686. // data base server.
  5687. //
  5688. #define MM_SYSTEM_CODE_LOCKED_DOWN 0x1
  5689. #define MM_PAGED_POOL_LOCKED_DOWN 0x2
  5690. extern ULONG MmDisablePagingExecutive;
  5691. //
  5692. // For debugging.
  5693. #if DBG
  5694. extern ULONG MmDebug;
  5695. #endif
  5696. //
  5697. // Unused segment management
  5698. //
  5699. extern MMDEREFERENCE_SEGMENT_HEADER MmDereferenceSegmentHeader;
  5700. extern LIST_ENTRY MmUnusedSegmentList;
  5701. extern LIST_ENTRY MmUnusedSubsectionList;
  5702. extern KEVENT MmUnusedSegmentCleanup;
  5703. extern ULONG MmConsumedPoolPercentage;
  5704. extern ULONG MmUnusedSegmentCount;
  5705. extern ULONG MmUnusedSubsectionCount;
  5706. extern ULONG MmUnusedSubsectionCountPeak;
  5707. extern SIZE_T MiUnusedSubsectionPagedPool;
  5708. extern SIZE_T MiUnusedSubsectionPagedPoolPeak;
  5709. #define MI_UNUSED_SUBSECTIONS_COUNT_INSERT(_MappedSubsection) \
  5710. MmUnusedSubsectionCount += 1; \
  5711. if (MmUnusedSubsectionCount > MmUnusedSubsectionCountPeak) { \
  5712. MmUnusedSubsectionCountPeak = MmUnusedSubsectionCount; \
  5713. } \
  5714. MiUnusedSubsectionPagedPool += EX_REAL_POOL_USAGE((_MappedSubsection->PtesInSubsection + _MappedSubsection->UnusedPtes) * sizeof (MMPTE)); \
  5715. if (MiUnusedSubsectionPagedPool > MiUnusedSubsectionPagedPoolPeak) { \
  5716. MiUnusedSubsectionPagedPoolPeak = MiUnusedSubsectionPagedPool; \
  5717. } \
  5718. #define MI_UNUSED_SUBSECTIONS_COUNT_REMOVE(_MappedSubsection) \
  5719. MmUnusedSubsectionCount -= 1; \
  5720. MiUnusedSubsectionPagedPool -= EX_REAL_POOL_USAGE((_MappedSubsection->PtesInSubsection + _MappedSubsection->UnusedPtes) * sizeof (MMPTE));
  5721. #define MI_FILESYSTEM_NONPAGED_POOL_CHARGE 150
  5722. #define MI_FILESYSTEM_PAGED_POOL_CHARGE 1024
  5723. //++
  5724. //LOGICAL
  5725. //MI_UNUSED_SEGMENTS_SURPLUS (
  5726. // IN PVOID va
  5727. // );
  5728. //
  5729. // Routine Description:
  5730. //
  5731. // This routine determines whether a surplus of unused
  5732. // segments exist. If so, the caller can initiate a trim to free pool.
  5733. //
  5734. // Arguments
  5735. //
  5736. // None.
  5737. //
  5738. // Return Value:
  5739. //
  5740. // TRUE if unused segment trimming should be initiated, FALSE if not.
  5741. //
  5742. //--
  5743. #define MI_UNUSED_SEGMENTS_SURPLUS() \
  5744. (((ULONG)((MmPagedPoolInfo.AllocatedPagedPool * 100) / (MmSizeOfPagedPoolInBytes >> PAGE_SHIFT)) > MmConsumedPoolPercentage) || \
  5745. ((ULONG)((MmAllocatedNonPagedPool * 100) / MmMaximumNonPagedPoolInPages) > MmConsumedPoolPercentage))
  5746. VOID
  5747. MiConvertStaticSubsections (
  5748. IN PCONTROL_AREA ControlArea
  5749. );
  5750. //++
  5751. //VOID
  5752. //MI_INSERT_UNUSED_SEGMENT (
  5753. // IN PCONTROL_AREA _ControlArea
  5754. // );
  5755. //
  5756. // Routine Description:
  5757. //
  5758. // This routine inserts a control area into the unused segment list,
  5759. // also managing the associated pool charges.
  5760. //
  5761. // Arguments
  5762. //
  5763. // _ControlArea - Supplies the control area to obtain the pool charges from.
  5764. //
  5765. // Return Value:
  5766. //
  5767. // None.
  5768. //
  5769. //--
  5770. #define MI_INSERT_UNUSED_SEGMENT(_ControlArea) \
  5771. { \
  5772. MM_PFN_LOCK_ASSERT(); \
  5773. if ((_ControlArea->u.Flags.Image == 0) && \
  5774. (_ControlArea->FilePointer != NULL) && \
  5775. (_ControlArea->u.Flags.PhysicalMemory == 0)) { \
  5776. MiConvertStaticSubsections(_ControlArea); \
  5777. } \
  5778. InsertTailList (&MmUnusedSegmentList, &_ControlArea->DereferenceList); \
  5779. MmUnusedSegmentCount += 1; \
  5780. }
  5781. //++
  5782. //VOID
  5783. //MI_UNUSED_SEGMENTS_REMOVE_CHARGE (
  5784. // IN PCONTROL_AREA _ControlArea
  5785. // );
  5786. //
  5787. // Routine Description:
  5788. //
  5789. // This routine manages pool charges during removals of segments from
  5790. // the unused segment list.
  5791. //
  5792. // Arguments
  5793. //
  5794. // _ControlArea - Supplies the control area to obtain the pool charges from.
  5795. //
  5796. // Return Value:
  5797. //
  5798. // None.
  5799. //
  5800. //--
  5801. #define MI_UNUSED_SEGMENTS_REMOVE_CHARGE(_ControlArea) \
  5802. { \
  5803. MM_PFN_LOCK_ASSERT(); \
  5804. MmUnusedSegmentCount -= 1; \
  5805. }
  5806. //
  5807. // List heads
  5808. //
  5809. extern MMWORKING_SET_EXPANSION_HEAD MmWorkingSetExpansionHead;
  5810. extern MMPAGE_FILE_EXPANSION MmAttemptForCantExtend;
  5811. //
  5812. // Paging files
  5813. //
  5814. extern MMMOD_WRITER_LISTHEAD MmPagingFileHeader;
  5815. extern MMMOD_WRITER_LISTHEAD MmMappedFileHeader;
  5816. extern PMMPAGING_FILE MmPagingFile[MAX_PAGE_FILES];
  5817. extern LIST_ENTRY MmFreePagingSpaceLow;
  5818. extern ULONG MmNumberOfActiveMdlEntries;
  5819. extern ULONG MmNumberOfPagingFiles;
  5820. extern KEVENT MmModifiedPageWriterEvent;
  5821. extern KEVENT MmCollidedFlushEvent;
  5822. extern KEVENT MmCollidedLockEvent;
  5823. // #define _MI_DEBUG_DATA 1 // Uncomment this for data logging
  5824. #if defined (_MI_DEBUG_DATA)
  5825. #define MI_DATA_BACKTRACE_LENGTH 8
  5826. typedef struct _MI_DATA_TRACES {
  5827. PETHREAD Thread;
  5828. PMMPFN Pfn;
  5829. PMMPTE PointerPte;
  5830. MMPFN PfnData;
  5831. ULONG CallerId;
  5832. ULONG DataInThePage[2];
  5833. PVOID StackTrace [MI_DATA_BACKTRACE_LENGTH];
  5834. } MI_DATA_TRACES, *PMI_DATA_TRACES;
  5835. extern LONG MiDataIndex;
  5836. extern ULONG MiTrackData;
  5837. extern PMI_DATA_TRACES MiDataTraces;
  5838. VOID
  5839. FORCEINLINE
  5840. MiSnapData (
  5841. IN PMMPFN Pfn,
  5842. IN PMMPTE PointerPte,
  5843. IN ULONG CallerId
  5844. )
  5845. {
  5846. KIRQL OldIrql;
  5847. PVOID Va;
  5848. PMI_DATA_TRACES Information;
  5849. ULONG Index;
  5850. ULONG Hash;
  5851. PEPROCESS CurrentProcess;
  5852. if (MiDataTraces == NULL) {
  5853. return;
  5854. }
  5855. Index = InterlockedIncrement (&MiDataIndex);
  5856. Index &= (MiTrackData - 1);
  5857. Information = &MiDataTraces[Index];
  5858. Information->Thread = PsGetCurrentThread ();
  5859. Information->Pfn = Pfn;
  5860. Information->PointerPte = PointerPte;
  5861. Information->PfnData = *Pfn;
  5862. Information->CallerId = CallerId;
  5863. CurrentProcess = PsGetCurrentProcess ();
  5864. Va = MiMapPageInHyperSpace (CurrentProcess, MI_PFN_ELEMENT_TO_INDEX (Pfn), &OldIrql);
  5865. RtlCopyMemory (&Information->DataInThePage[0],
  5866. Va,
  5867. sizeof (Information->DataInThePage));
  5868. MiUnmapPageInHyperSpace (CurrentProcess, Va, OldIrql);
  5869. RtlZeroMemory (&Information->StackTrace[0], MI_DATA_BACKTRACE_LENGTH * sizeof(PVOID)); \
  5870. #if defined (_WIN64)
  5871. if (KeAreAllApcsDisabled () == TRUE) {
  5872. Information->StackTrace[1] = (PVOID) _ReturnAddress ();
  5873. Information->StackTrace[0] = MiGetInstructionPointer ();
  5874. }
  5875. else
  5876. #endif
  5877. RtlCaptureStackBackTrace (0, MI_DATA_BACKTRACE_LENGTH, Information->StackTrace, &Hash);
  5878. }
  5879. #define MI_SNAP_DATA(_Pfn, _Pte, _CallerId) MiSnapData(_Pfn, _Pte, _CallerId)
  5880. #else
  5881. #define MI_SNAP_DATA(_Pfn, _Pte, _CallerId)
  5882. #endif
  5883. //
  5884. // Modified page writer.
  5885. //
  5886. VOID
  5887. FORCEINLINE
  5888. MiReleaseConfirmedPageFileSpace (
  5889. IN MMPTE PteContents
  5890. )
  5891. /*++
  5892. Routine Description:
  5893. This routine frees the paging file allocated to the specified PTE.
  5894. Arguments:
  5895. PteContents - Supplies the PTE which is in page file format.
  5896. Return Value:
  5897. Returns TRUE if any paging file space was deallocated.
  5898. Environment:
  5899. Kernel mode, APCs disabled, PFN lock held.
  5900. --*/
  5901. {
  5902. ULONG FreeBit;
  5903. ULONG PageFileNumber;
  5904. PMMPAGING_FILE PageFile;
  5905. MM_PFN_LOCK_ASSERT();
  5906. ASSERT (PteContents.u.Soft.Prototype == 0);
  5907. FreeBit = GET_PAGING_FILE_OFFSET (PteContents);
  5908. ASSERT ((FreeBit != 0) && (FreeBit != MI_PTE_LOOKUP_NEEDED));
  5909. PageFileNumber = GET_PAGING_FILE_NUMBER (PteContents);
  5910. PageFile = MmPagingFile[PageFileNumber];
  5911. ASSERT (RtlCheckBit( PageFile->Bitmap, FreeBit) == 1);
  5912. #if DBG
  5913. if ((FreeBit < 8192) && (PageFileNumber == 0)) {
  5914. ASSERT ((MmPagingFileDebug[FreeBit] & 1) != 0);
  5915. MmPagingFileDebug[FreeBit] ^= 1;
  5916. }
  5917. #endif
  5918. MI_CLEAR_BIT (PageFile->Bitmap->Buffer, FreeBit);
  5919. PageFile->FreeSpace += 1;
  5920. PageFile->CurrentUsage -= 1;
  5921. //
  5922. // Check to see if we should move some MDL entries for the
  5923. // modified page writer now that more free space is available.
  5924. //
  5925. if ((MmNumberOfActiveMdlEntries == 0) ||
  5926. (PageFile->FreeSpace == MM_USABLE_PAGES_FREE)) {
  5927. MiUpdateModifiedWriterMdls (PageFileNumber);
  5928. }
  5929. }
  5930. extern PFN_NUMBER MmMinimumFreePages;
  5931. extern PFN_NUMBER MmFreeGoal;
  5932. extern PFN_NUMBER MmModifiedPageMaximum;
  5933. extern ULONG MmModifiedWriteClusterSize;
  5934. extern ULONG MmMinimumFreeDiskSpace;
  5935. extern ULONG MmPageFileExtension;
  5936. extern ULONG MmMinimumPageFileReduction;
  5937. extern LARGE_INTEGER MiModifiedPageLife;
  5938. extern BOOLEAN MiTimerPending;
  5939. extern KEVENT MiMappedPagesTooOldEvent;
  5940. extern KDPC MiModifiedPageWriterTimerDpc;
  5941. extern KTIMER MiModifiedPageWriterTimer;
  5942. //
  5943. // System process working set sizes.
  5944. //
  5945. extern PFN_NUMBER MmSystemProcessWorkingSetMin;
  5946. extern PFN_NUMBER MmSystemProcessWorkingSetMax;
  5947. extern PFN_NUMBER MmMinimumWorkingSetSize;
  5948. //
  5949. // Support for debugger's mapping physical memory.
  5950. //
  5951. extern PMMPTE MmDebugPte;
  5952. extern PMMPTE MmCrashDumpPte;
  5953. extern ULONG MiOverCommitCallCount;
  5954. //
  5955. // Event tracing routines
  5956. //
  5957. extern PPAGE_FAULT_NOTIFY_ROUTINE MmPageFaultNotifyRoutine;
  5958. extern SIZE_T MmSystemViewSize;
  5959. VOID
  5960. FASTCALL
  5961. MiIdentifyPfn (
  5962. IN PMMPFN Pfn1,
  5963. OUT PMMPFN_IDENTITY PfnIdentity
  5964. );
  5965. #if defined (_WIN64)
  5966. #define InterlockedExchangeAddSizeT(a, b) InterlockedExchangeAdd64((PLONGLONG)a, b)
  5967. #else
  5968. #define InterlockedExchangeAddSizeT(a, b) InterlockedExchangeAdd((PLONG)(a), b)
  5969. #endif
  5970. //
  5971. // This is a special value loaded into an EPROCESS pointer to indicate that
  5972. // the action underway is for a Hydra session, not really the current process.
  5973. // Any value could have been used here that is not a valid system pointer
  5974. // or NULL - 1 was chosen because it simplifies checks for both NULL &
  5975. // HydraProcess by comparing for greater than HydraProcess.
  5976. //
  5977. #define HYDRA_PROCESS ((PEPROCESS)1)
  5978. #define PREFETCH_PROCESS ((PEPROCESS)2)
  5979. #define MI_SESSION_SPACE_STRUCT_SIZE MM_ALLOCATION_GRANULARITY
  5980. #if defined (_WIN64)
  5981. /*++
  5982. Virtual memory layout of session space when loaded down from
  5983. 0x2000.0002.0000.0000 (IA64) or FFFF.F980.0000.0000 (AMD64) :
  5984. Note that the sizes of mapped views, paged pool & images are registry tunable.
  5985. +------------------------------------+
  5986. 2000.0002.0000.0000 | |
  5987. | win32k.sys & video drivers |
  5988. | (16MB) |
  5989. | |
  5990. +------------------------------------+
  5991. 2000.0001.FF00.0000 | |
  5992. | MM_SESSION_SPACE & Session WSLs |
  5993. | (16MB) |
  5994. | |
  5995. 2000.0001.FEFF.0000 +------------------------------------+
  5996. | |
  5997. | ... |
  5998. | |
  5999. +------------------------------------+
  6000. 2000.0001.FE80.0000 | |
  6001. | Mapped Views for this session |
  6002. | (104MB) |
  6003. | |
  6004. +------------------------------------+
  6005. 2000.0001.F800.0000 | |
  6006. | Paged Pool for this session |
  6007. | (64MB) |
  6008. | |
  6009. 2000.0001.F400.0000 +------------------------------------+
  6010. | Special Pool for this session |
  6011. | (64MB) |
  6012. | |
  6013. 2000.0000.0000.0000 +------------------------------------+
  6014. --*/
  6015. #define MI_SESSION_SPACE_WS_SIZE ((ULONG_PTR)(16*1024*1024) - MI_SESSION_SPACE_STRUCT_SIZE)
  6016. #define MI_SESSION_DEFAULT_IMAGE_SIZE ((ULONG_PTR)(16*1024*1024))
  6017. #define MI_SESSION_DEFAULT_VIEW_SIZE ((ULONG_PTR)(104*1024*1024))
  6018. #define MI_SESSION_DEFAULT_POOL_SIZE ((ULONG_PTR)(64*1024*1024))
  6019. #define MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE (MM_VA_MAPPED_BY_PPE)
  6020. #else
  6021. /*++
  6022. Virtual memory layout of session space when loaded down from 0xC0000000.
  6023. Note that the sizes of mapped views, paged pool and images are registry
  6024. tunable on 32-bit systems (if NOT booted /3GB, as 3GB has very limited
  6025. address space).
  6026. +------------------------------------+
  6027. C0000000 | |
  6028. | win32k.sys, video drivers and any |
  6029. | rebased NT4 printer drivers. |
  6030. | |
  6031. | (8MB) |
  6032. | |
  6033. +------------------------------------+
  6034. BF800000 | |
  6035. | MM_SESSION_SPACE & Session WSLs |
  6036. | (4MB) |
  6037. | |
  6038. +------------------------------------+
  6039. BF400000 | |
  6040. | Mapped views for this session |
  6041. | (20MB by default, but is |
  6042. | registry configurable) |
  6043. | |
  6044. +------------------------------------+
  6045. BE000000 | |
  6046. | Paged pool for this session |
  6047. | (16MB by default, but is |
  6048. | registry configurable) |
  6049. | |
  6050. BD000000 +------------------------------------+
  6051. --*/
  6052. #define MI_SESSION_SPACE_WS_SIZE (4*1024*1024 - MI_SESSION_SPACE_STRUCT_SIZE)
  6053. #define MI_SESSION_DEFAULT_IMAGE_SIZE (8*1024*1024)
  6054. #define MI_SESSION_DEFAULT_VIEW_SIZE (20*1024*1024)
  6055. #define MI_SESSION_DEFAULT_POOL_SIZE (16*1024*1024)
  6056. #define MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE \
  6057. (MM_SYSTEM_CACHE_END_EXTRA - MM_KSEG2_BASE)
  6058. #endif
  6059. #define MI_SESSION_SPACE_DEFAULT_TOTAL_SIZE \
  6060. (MI_SESSION_DEFAULT_IMAGE_SIZE + \
  6061. MI_SESSION_SPACE_STRUCT_SIZE + \
  6062. MI_SESSION_SPACE_WS_SIZE + \
  6063. MI_SESSION_DEFAULT_VIEW_SIZE + \
  6064. MI_SESSION_DEFAULT_POOL_SIZE)
  6065. extern ULONG_PTR MmSessionBase;
  6066. extern PMMPTE MiSessionBasePte;
  6067. extern PMMPTE MiSessionLastPte;
  6068. extern ULONG_PTR MiSessionSpaceWs;
  6069. extern ULONG_PTR MiSessionViewStart;
  6070. extern SIZE_T MmSessionViewSize;
  6071. extern ULONG_PTR MiSessionImageStart;
  6072. extern ULONG_PTR MiSessionImageEnd;
  6073. extern SIZE_T MmSessionImageSize;
  6074. extern PMMPTE MiSessionImagePteStart;
  6075. extern PMMPTE MiSessionImagePteEnd;
  6076. extern ULONG_PTR MiSessionPoolStart;
  6077. extern ULONG_PTR MiSessionPoolEnd;
  6078. extern SIZE_T MmSessionPoolSize;
  6079. extern ULONG_PTR MiSessionSpaceEnd;
  6080. extern ULONG MiSessionSpacePageTables;
  6081. //
  6082. // The number of page table pages required to map all of session space.
  6083. //
  6084. #define MI_SESSION_SPACE_MAXIMUM_PAGE_TABLES \
  6085. (MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE / MM_VA_MAPPED_BY_PDE)
  6086. extern SIZE_T MmSessionSize; // size of the entire session space.
  6087. //
  6088. // Macros to determine if a given address lies in the specified session range.
  6089. //
  6090. #define MI_IS_SESSION_IMAGE_ADDRESS(VirtualAddress) \
  6091. ((PVOID)(VirtualAddress) >= (PVOID)MiSessionImageStart && (PVOID)(VirtualAddress) < (PVOID)(MiSessionImageEnd))
  6092. #define MI_IS_SESSION_POOL_ADDRESS(VirtualAddress) \
  6093. ((PVOID)(VirtualAddress) >= (PVOID)MiSessionPoolStart && (PVOID)(VirtualAddress) < (PVOID)MiSessionPoolEnd)
  6094. #define MI_IS_SESSION_ADDRESS(_VirtualAddress) \
  6095. ((PVOID)(_VirtualAddress) >= (PVOID)MmSessionBase && (PVOID)(_VirtualAddress) < (PVOID)(MiSessionSpaceEnd))
  6096. #define MI_IS_SESSION_PTE(_Pte) \
  6097. ((PMMPTE)(_Pte) >= MiSessionBasePte && (PMMPTE)(_Pte) < MiSessionLastPte)
  6098. #define MI_IS_SESSION_IMAGE_PTE(_Pte) \
  6099. ((PMMPTE)(_Pte) >= MiSessionImagePteStart && (PMMPTE)(_Pte) < MiSessionImagePteEnd)
  6100. #define SESSION_GLOBAL(_Session) (_Session->GlobalVirtualAddress)
  6101. #define MM_DBG_SESSION_INITIAL_PAGETABLE_ALLOC 0
  6102. #define MM_DBG_SESSION_INITIAL_PAGETABLE_FREE_RACE 1
  6103. #define MM_DBG_SESSION_INITIAL_PAGE_ALLOC 2
  6104. #define MM_DBG_SESSION_INITIAL_PAGE_FREE_FAIL1 3
  6105. #define MM_DBG_SESSION_INITIAL_PAGETABLE_FREE_FAIL1 4
  6106. #define MM_DBG_SESSION_WS_PAGE_FREE 5
  6107. #define MM_DBG_SESSION_PAGETABLE_ALLOC 6
  6108. #define MM_DBG_SESSION_SYSMAPPED_PAGES_ALLOC 7
  6109. #define MM_DBG_SESSION_WS_PAGETABLE_ALLOC 8
  6110. #define MM_DBG_SESSION_PAGEDPOOL_PAGETABLE_ALLOC 9
  6111. #define MM_DBG_SESSION_PAGEDPOOL_PAGETABLE_FREE_FAIL1 10
  6112. #define MM_DBG_SESSION_WS_PAGE_ALLOC 11
  6113. #define MM_DBG_SESSION_WS_PAGE_ALLOC_GROWTH 12
  6114. #define MM_DBG_SESSION_INITIAL_PAGE_FREE 13
  6115. #define MM_DBG_SESSION_PAGETABLE_FREE 14
  6116. #define MM_DBG_SESSION_PAGEDPOOL_PAGETABLE_ALLOC1 15
  6117. #define MM_DBG_SESSION_DRIVER_PAGES_LOCKED 16
  6118. #define MM_DBG_SESSION_DRIVER_PAGES_UNLOCKED 17
  6119. #define MM_DBG_SESSION_WS_HASHPAGE_ALLOC 18
  6120. #define MM_DBG_SESSION_SYSMAPPED_PAGES_COMMITTED 19
  6121. #define MM_DBG_SESSION_COMMIT_PAGEDPOOL_PAGES 30
  6122. #define MM_DBG_SESSION_COMMIT_DELETE_VM_RETURN 31
  6123. #define MM_DBG_SESSION_COMMIT_POOL_FREED 32
  6124. #define MM_DBG_SESSION_COMMIT_IMAGE_UNLOAD 33
  6125. #define MM_DBG_SESSION_COMMIT_IMAGELOAD_FAILED1 34
  6126. #define MM_DBG_SESSION_COMMIT_IMAGELOAD_FAILED2 35
  6127. #define MM_DBG_SESSION_COMMIT_IMAGELOAD_NOACCESS 36
  6128. #define MM_DBG_SESSION_NP_LOCK_CODE1 38
  6129. #define MM_DBG_SESSION_NP_LOCK_CODE2 39
  6130. #define MM_DBG_SESSION_NP_SESSION_CREATE 40
  6131. #define MM_DBG_SESSION_NP_PAGETABLE_ALLOC 41
  6132. #define MM_DBG_SESSION_NP_POOL_CREATE 42
  6133. #define MM_DBG_SESSION_NP_COMMIT_IMAGE 43
  6134. #define MM_DBG_SESSION_NP_COMMIT_IMAGE_PT 44
  6135. #define MM_DBG_SESSION_NP_INIT_WS 45
  6136. #define MM_DBG_SESSION_NP_WS_GROW 46
  6137. #define MM_DBG_SESSION_NP_HASH_GROW 47
  6138. #define MM_DBG_SESSION_NP_PAGE_DRIVER 48
  6139. #define MM_DBG_SESSION_NP_POOL_CREATE_FAILED 49
  6140. #define MM_DBG_SESSION_NP_WS_PAGE_FREE 50
  6141. #define MM_DBG_SESSION_NP_SESSION_DESTROY 51
  6142. #define MM_DBG_SESSION_NP_SESSION_PTDESTROY 52
  6143. #define MM_DBG_SESSION_NP_DELVA 53
  6144. #define MM_DBG_SESSION_NP_HASH_SHRINK 54
  6145. #define MM_DBG_SESSION_WS_HASHPAGE_FREE 55
  6146. #if DBG
  6147. #define MM_SESS_COUNTER_MAX 56
  6148. #define MM_BUMP_SESS_COUNTER(_index, bump) \
  6149. if (_index >= MM_SESS_COUNTER_MAX) { \
  6150. DbgPrint("Mm: Invalid bump counter %d %d\n", _index, MM_SESS_COUNTER_MAX); \
  6151. DbgBreakPoint(); \
  6152. } \
  6153. MmSessionSpace->Debug[_index] += (bump);
  6154. typedef struct _MM_SESSION_MEMORY_COUNTERS {
  6155. SIZE_T NonPagablePages;
  6156. SIZE_T CommittedPages;
  6157. } MM_SESSION_MEMORY_COUNTERS, *PMM_SESSION_MEMORY_COUNTERS;
  6158. #define MM_SESS_MEMORY_COUNTER_MAX 8
  6159. #define MM_SNAP_SESS_MEMORY_COUNTERS(_index) \
  6160. if (_index >= MM_SESS_MEMORY_COUNTER_MAX) { \
  6161. DbgPrint("Mm: Invalid session mem counter %d %d\n", _index, MM_SESS_MEMORY_COUNTER_MAX); \
  6162. DbgBreakPoint(); \
  6163. } \
  6164. else { \
  6165. MmSessionSpace->Debug2[_index].NonPagablePages = MmSessionSpace->NonPagablePages; \
  6166. MmSessionSpace->Debug2[_index].CommittedPages = MmSessionSpace->CommittedPages; \
  6167. }
  6168. #else
  6169. #define MM_BUMP_SESS_COUNTER(_index, bump)
  6170. #define MM_SNAP_SESS_MEMORY_COUNTERS(_index)
  6171. #endif
  6172. #define MM_SESSION_FAILURE_NO_IDS 0
  6173. #define MM_SESSION_FAILURE_NO_COMMIT 1
  6174. #define MM_SESSION_FAILURE_NO_RESIDENT 2
  6175. #define MM_SESSION_FAILURE_RACE_DETECTED 3
  6176. #define MM_SESSION_FAILURE_NO_SYSPTES 4
  6177. #define MM_SESSION_FAILURE_NO_PAGED_POOL 5
  6178. #define MM_SESSION_FAILURE_NO_NONPAGED_POOL 6
  6179. #define MM_SESSION_FAILURE_NO_IMAGE_VA_SPACE 7
  6180. #define MM_SESSION_FAILURE_NO_SESSION_PAGED_POOL 8
  6181. #define MM_SESSION_FAILURE_NO_AVAILABLE 9
  6182. #define MM_SESSION_FAILURE_IMAGE_ZOMBIE 10
  6183. #define MM_SESSION_FAILURE_CAUSES 11
  6184. ULONG MmSessionFailureCauses[MM_SESSION_FAILURE_CAUSES];
  6185. #define MM_BUMP_SESSION_FAILURES(_index) MmSessionFailureCauses[_index] += 1;
  6186. typedef struct _MM_SESSION_SPACE_FLAGS {
  6187. ULONG Initialized : 1;
  6188. ULONG DeletePending : 1;
  6189. ULONG Filler : 30;
  6190. } MM_SESSION_SPACE_FLAGS;
  6191. //
  6192. // The value of SESSION_POOL_SMALL_LISTS is very carefully chosen for each
  6193. // architecture to avoid spilling over into an additional session data page.
  6194. //
  6195. #if defined(_AMD64_)
  6196. #define SESSION_POOL_SMALL_LISTS 21
  6197. #elif defined(_IA64_)
  6198. #define SESSION_POOL_SMALL_LISTS 53
  6199. #elif defined(_X86_)
  6200. #define SESSION_POOL_SMALL_LISTS 26
  6201. #else
  6202. #error "no target architecture"
  6203. #endif
  6204. //
  6205. // The session space data structure - allocated per session and only visible at
  6206. // MM_SESSION_SPACE_BASE when in the context of a process from the session.
  6207. // This virtual address space is rotated at context switch time when switching
  6208. // from a process in session A to a process in session B. This rotation is
  6209. // useful for things like providing paged pool per session so many sessions
  6210. // won't exhaust the VA space which backs the system global pool.
  6211. //
  6212. // A kernel PTE is also allocated to double map this page so that global
  6213. // pointers can be maintained to provide system access from any process context.
  6214. // This is needed for things like mutexes and WSL chains.
  6215. //
  6216. typedef struct _MM_SESSION_SPACE {
  6217. //
  6218. // This is a pointer in global system address space, used to make various
  6219. // fields that can be referenced from any process visible from any process
  6220. // context. This is for things like mutexes, WSL chains, etc.
  6221. //
  6222. struct _MM_SESSION_SPACE *GlobalVirtualAddress;
  6223. ULONG ReferenceCount;
  6224. union {
  6225. ULONG LongFlags;
  6226. MM_SESSION_SPACE_FLAGS Flags;
  6227. } u;
  6228. ULONG SessionId;
  6229. //
  6230. // This is the list of the processes in this group that have
  6231. // session space entries.
  6232. //
  6233. LIST_ENTRY ProcessList;
  6234. LARGE_INTEGER LastProcessSwappedOutTime;
  6235. //
  6236. // All the page tables for session space use this as their parent.
  6237. // Note that it's not really a page directory - it's really a page
  6238. // table page itself (the one used to map this very structure).
  6239. //
  6240. // This provides a reference to something that won't go away and
  6241. // is relevant regardless of which process within the session is current.
  6242. //
  6243. PFN_NUMBER SessionPageDirectoryIndex;
  6244. //
  6245. // This is the count of non paged allocations to support this session
  6246. // space. This includes the session structure page table and data pages,
  6247. // WSL page table and data pages, session pool page table pages and session
  6248. // image page table pages. These are all charged against
  6249. // MmResidentAvailable.
  6250. //
  6251. SIZE_T NonPagablePages;
  6252. //
  6253. // This is the count of pages in this session that have been charged against
  6254. // the systemwide commit. This includes all the NonPagablePages plus the
  6255. // data pages they typically map.
  6256. //
  6257. SIZE_T CommittedPages;
  6258. //
  6259. // Start of session paged pool virtual space.
  6260. //
  6261. PVOID PagedPoolStart;
  6262. //
  6263. // Current end of pool virtual space. Can be extended to the
  6264. // end of the session space.
  6265. //
  6266. PVOID PagedPoolEnd;
  6267. //
  6268. // PTE pointers for pool.
  6269. //
  6270. PMMPTE PagedPoolBasePde;
  6271. ULONG Color;
  6272. ULONG ProcessOutSwapCount;
  6273. ULONG SessionPoolAllocationFailures[4];
  6274. //
  6275. // This is the list of system images currently valid in
  6276. // this session space. This information is in addition
  6277. // to the module global information in PsLoadedModuleList.
  6278. //
  6279. LIST_ENTRY ImageList;
  6280. LCID LocaleId;
  6281. //
  6282. // The count of "known attachers and the associated event.
  6283. //
  6284. ULONG AttachCount;
  6285. KEVENT AttachEvent;
  6286. PEPROCESS LastProcess;
  6287. //
  6288. // This is generally decremented in process delete (not clean) so that
  6289. // the session data page and mapping PTE can finally be freed when this
  6290. // reaches zero. smss is the only process that decrements it in other
  6291. // places as smss never exits.
  6292. //
  6293. LONG ProcessReferenceToSession;
  6294. //
  6295. // This chain is in global system addresses (not session VAs) and can
  6296. // be walked from any system context, ie: for WSL trimming.
  6297. //
  6298. LIST_ENTRY WsListEntry;
  6299. //
  6300. // Session lookasides for fast pool allocation/freeing.
  6301. //
  6302. GENERAL_LOOKASIDE Lookaside[SESSION_POOL_SMALL_LISTS];
  6303. //
  6304. // Support for mapping system views into session space. Each desktop
  6305. // allocates a 3MB heap and the global system view space is only 48M
  6306. // total. This would limit us to only 20-30 users - rotating the
  6307. // system view space with each session removes this limitation.
  6308. //
  6309. MMSESSION Session;
  6310. //
  6311. // Session space paged pool support.
  6312. //
  6313. KGUARDED_MUTEX PagedPoolMutex;
  6314. MM_PAGED_POOL_INFO PagedPoolInfo;
  6315. //
  6316. // Working set information.
  6317. //
  6318. MMSUPPORT Vm;
  6319. PMMWSLE Wsle;
  6320. PDRIVER_UNLOAD Win32KDriverUnload;
  6321. //
  6322. // Pool descriptor for less than 1 page allocations.
  6323. //
  6324. POOL_DESCRIPTOR PagedPool;
  6325. #if (_MI_PAGING_LEVELS >= 3)
  6326. //
  6327. // The page directory that maps session space is saved here so
  6328. // trimmers can attach.
  6329. //
  6330. MMPTE PageDirectory;
  6331. #else
  6332. //
  6333. // The second level page tables that map session space are shared
  6334. // by all processes in the session.
  6335. //
  6336. PMMPTE PageTables;
  6337. #endif
  6338. #if defined (_WIN64)
  6339. //
  6340. // NT64 has enough virtual address space to support per-session special
  6341. // pool.
  6342. //
  6343. PMMPTE SpecialPoolFirstPte;
  6344. PMMPTE SpecialPoolLastPte;
  6345. PMMPTE NextPdeForSpecialPoolExpansion;
  6346. PMMPTE LastPdeForSpecialPoolExpansion;
  6347. PFN_NUMBER SpecialPagesInUse;
  6348. #endif
  6349. #if defined(_IA64_)
  6350. REGION_MAP_INFO SessionMapInfo;
  6351. PFN_NUMBER PageDirectoryParentPage;
  6352. #endif
  6353. LONG ImageLoadingCount;
  6354. #if DBG
  6355. ULONG Debug[MM_SESS_COUNTER_MAX];
  6356. MM_SESSION_MEMORY_COUNTERS Debug2[MM_SESS_MEMORY_COUNTER_MAX];
  6357. #endif
  6358. } MM_SESSION_SPACE, *PMM_SESSION_SPACE;
  6359. extern PMM_SESSION_SPACE MmSessionSpace;
  6360. extern ULONG MiSessionCount;
  6361. //
  6362. // This flushes just the non-global TB entries.
  6363. //
  6364. #define MI_FLUSH_SESSION_TB() KeFlushProcessTb (TRUE);
  6365. //
  6366. // The default number of pages for the session working set minimum & maximum.
  6367. //
  6368. #define MI_SESSION_SPACE_WORKING_SET_MINIMUM 20
  6369. #define MI_SESSION_SPACE_WORKING_SET_MAXIMUM 384
  6370. NTSTATUS
  6371. MiSessionInsertImage (
  6372. IN PVOID BaseAddress
  6373. );
  6374. NTSTATUS
  6375. MiSessionCommitPageTables (
  6376. PVOID StartVa,
  6377. PVOID EndVa
  6378. );
  6379. NTSTATUS
  6380. MiInitializeAndChargePfn (
  6381. OUT PPFN_NUMBER PageFrameIndex,
  6382. IN PMMPTE PointerPde,
  6383. IN PFN_NUMBER ContainingPageFrame,
  6384. IN LOGICAL SessionAllocation
  6385. );
  6386. VOID
  6387. MiSessionPageTableRelease (
  6388. IN PFN_NUMBER PageFrameIndex
  6389. );
  6390. NTSTATUS
  6391. MiInitializeSessionPool (
  6392. VOID
  6393. );
  6394. VOID
  6395. MiCheckSessionPoolAllocations (
  6396. VOID
  6397. );
  6398. VOID
  6399. MiFreeSessionPoolBitMaps (
  6400. VOID
  6401. );
  6402. VOID
  6403. MiDetachSession (
  6404. VOID
  6405. );
  6406. VOID
  6407. MiAttachSession (
  6408. IN PMM_SESSION_SPACE SessionGlobal
  6409. );
  6410. VOID
  6411. MiReleaseProcessReferenceToSessionDataPage (
  6412. PMM_SESSION_SPACE SessionGlobal
  6413. );
  6414. extern PMMPTE MiHighestUserPte;
  6415. extern PMMPTE MiHighestUserPde;
  6416. #if (_MI_PAGING_LEVELS >= 4)
  6417. extern PMMPTE MiHighestUserPpe;
  6418. extern PMMPTE MiHighestUserPxe;
  6419. #endif
  6420. NTSTATUS
  6421. MiEmptyWorkingSet (
  6422. IN PMMSUPPORT WsInfo,
  6423. IN LOGICAL NeedLock
  6424. );
  6425. //++
  6426. //ULONG
  6427. //MiGetPdeSessionIndex (
  6428. // IN PVOID va
  6429. // );
  6430. //
  6431. // Routine Description:
  6432. //
  6433. // MiGetPdeSessionIndex returns the session structure index for the PDE
  6434. // will (or does) map the given virtual address.
  6435. //
  6436. // Arguments
  6437. //
  6438. // Va - Supplies the virtual address to locate the PDE index for.
  6439. //
  6440. // Return Value:
  6441. //
  6442. // The index of the PDE entry.
  6443. //
  6444. //--
  6445. #define MiGetPdeSessionIndex(va) ((ULONG)(((ULONG_PTR)(va) - (ULONG_PTR)MmSessionBase) >> PDI_SHIFT))
  6446. //
  6447. // Session space contains the image loader and tracker, virtual
  6448. // address allocator, paged pool allocator, system view image mappings,
  6449. // and working set for kernel mode virtual addresses that are instanced
  6450. // for groups of processes in a Session process group. This
  6451. // process group is identified by a SessionId.
  6452. //
  6453. // Each Session process group's loaded kernel modules, paged pool
  6454. // allocations, working set, and mapped system views are separate from
  6455. // other Session process groups, even though they have the same
  6456. // virtual addresses.
  6457. //
  6458. // This is to support the Hydra multi-user Windows NT system by
  6459. // replicating WIN32K.SYS, and its complement of video and printer drivers,
  6460. // desktop heaps, memory allocations, etc.
  6461. //
  6462. //
  6463. // Structure linked into a session space structure to describe
  6464. // which system images in PsLoadedModuleTable and
  6465. // SESSION_DRIVER_GLOBAL_LOAD_ADDRESS's
  6466. // have been allocated for the current session space.
  6467. //
  6468. // The reference count tracks the number of loads of this image within
  6469. // this session.
  6470. //
  6471. typedef struct _SESSION_GLOBAL_SUBSECTION_INFO {
  6472. ULONG_PTR PteIndex;
  6473. ULONG PteCount;
  6474. ULONG Protection;
  6475. } SESSION_GLOBAL_SUBSECTION_INFO, *PSESSION_GLOBAL_SUBSECTION_INFO;
  6476. typedef struct _IMAGE_ENTRY_IN_SESSION {
  6477. LIST_ENTRY Link;
  6478. PVOID Address;
  6479. PVOID LastAddress;
  6480. ULONG ImageCountInThisSession;
  6481. LOGICAL ImageLoading; // Mods to this field protected by system load mutant
  6482. PMMPTE PrototypePtes;
  6483. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  6484. PSESSION_GLOBAL_SUBSECTION_INFO GlobalSubs;
  6485. } IMAGE_ENTRY_IN_SESSION, *PIMAGE_ENTRY_IN_SESSION;
  6486. extern LIST_ENTRY MiSessionWsList;
  6487. NTSTATUS
  6488. FASTCALL
  6489. MiCheckPdeForSessionSpace(
  6490. IN PVOID VirtualAddress
  6491. );
  6492. NTSTATUS
  6493. MiShareSessionImage (
  6494. IN PVOID BaseAddress,
  6495. IN PSECTION Section
  6496. );
  6497. VOID
  6498. MiSessionWideInitializeAddresses (
  6499. VOID
  6500. );
  6501. NTSTATUS
  6502. MiSessionWideReserveImageAddress (
  6503. IN PSECTION Section,
  6504. OUT PVOID *AssignedAddress,
  6505. OUT PSECTION *NewSectionPointer
  6506. );
  6507. VOID
  6508. MiInitializeSessionIds (
  6509. VOID
  6510. );
  6511. VOID
  6512. MiInitializeSessionWsSupport(
  6513. VOID
  6514. );
  6515. VOID
  6516. MiSessionAddProcess (
  6517. IN PEPROCESS NewProcess
  6518. );
  6519. VOID
  6520. MiSessionRemoveProcess (
  6521. VOID
  6522. );
  6523. VOID
  6524. MiRemoveImageSessionWide (
  6525. IN PKLDR_DATA_TABLE_ENTRY DataTableEntry OPTIONAL,
  6526. IN PVOID BaseAddress,
  6527. IN ULONG_PTR NumberOfBytes
  6528. );
  6529. NTSTATUS
  6530. MiDeleteSessionVirtualAddresses(
  6531. IN PVOID VirtualAddress,
  6532. IN SIZE_T NumberOfBytes
  6533. );
  6534. NTSTATUS
  6535. MiUnloadSessionImageByForce (
  6536. IN SIZE_T NumberOfPtes,
  6537. IN PVOID ImageBase
  6538. );
  6539. PIMAGE_ENTRY_IN_SESSION
  6540. MiSessionLookupImage (
  6541. IN PVOID BaseAddress
  6542. );
  6543. VOID
  6544. MiSessionUnloadAllImages (
  6545. VOID
  6546. );
  6547. VOID
  6548. MiFreeSessionSpaceMap (
  6549. VOID
  6550. );
  6551. NTSTATUS
  6552. MiSessionInitializeWorkingSetList (
  6553. VOID
  6554. );
  6555. VOID
  6556. MiSessionUnlinkWorkingSet (
  6557. VOID
  6558. );
  6559. VOID
  6560. MiSessionOutSwapProcess (
  6561. IN PEPROCESS Process
  6562. );
  6563. VOID
  6564. MiSessionInSwapProcess (
  6565. IN PEPROCESS Process
  6566. );
  6567. #if !defined (_X86PAE_)
  6568. #define MI_GET_DIRECTORY_FRAME_FROM_PROCESS(_Process) \
  6569. MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&((_Process)->Pcb.DirectoryTableBase[0])))
  6570. #define MI_GET_HYPER_PAGE_TABLE_FRAME_FROM_PROCESS(_Process) \
  6571. MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&((_Process)->Pcb.DirectoryTableBase[1])))
  6572. #else
  6573. #define MI_GET_DIRECTORY_FRAME_FROM_PROCESS(_Process) \
  6574. (MI_GET_PAGE_FRAME_FROM_PTE(((PMMPTE)((_Process)->PaeTop)) + PD_PER_SYSTEM - 1))
  6575. #define MI_GET_HYPER_PAGE_TABLE_FRAME_FROM_PROCESS(_Process) \
  6576. ((PFN_NUMBER)((_Process)->Pcb.DirectoryTableBase[1]))
  6577. #endif
  6578. #if defined(_MIALT4K_)
  6579. NTSTATUS
  6580. MiSetCopyPagesFor4kPage (
  6581. IN PEPROCESS Process,
  6582. IN PMMVAD Vad,
  6583. IN OUT PVOID StartingAddress,
  6584. IN OUT PVOID EndingAddress,
  6585. IN ULONG ProtectionMask,
  6586. OUT PMMVAD *CallerNewVad
  6587. );
  6588. VOID
  6589. MiRemoveAliasedVads (
  6590. IN PEPROCESS Process,
  6591. IN PMMVAD Vad
  6592. );
  6593. PVOID
  6594. MiDuplicateAliasVadList (
  6595. IN PMMVAD Vad
  6596. );
  6597. #endif
  6598. //
  6599. // The LDR_DATA_TABLE_ENTRY->LoadedImports is used as a list of imported DLLs.
  6600. //
  6601. // This field is zero if the module was loaded at boot time and the
  6602. // import information was never filled in.
  6603. //
  6604. // This field is -1 if no imports are defined by the module.
  6605. //
  6606. // This field contains a valid paged pool PLDR_DATA_TABLE_ENTRY pointer
  6607. // with a low-order (bit 0) tag of 1 if there is only 1 usable import needed
  6608. // by this driver.
  6609. //
  6610. // This field will contain a valid paged pool PLOAD_IMPORTS pointer in all
  6611. // other cases (ie: where at least 2 imports exist).
  6612. //
  6613. typedef struct _LOAD_IMPORTS {
  6614. SIZE_T Count;
  6615. PKLDR_DATA_TABLE_ENTRY Entry[1];
  6616. } LOAD_IMPORTS, *PLOAD_IMPORTS;
  6617. #define LOADED_AT_BOOT ((PLOAD_IMPORTS)0)
  6618. #define NO_IMPORTS_USED ((PLOAD_IMPORTS)-2)
  6619. #define SINGLE_ENTRY(ImportVoid) ((ULONG)((ULONG_PTR)(ImportVoid) & 0x1))
  6620. #define SINGLE_ENTRY_TO_POINTER(ImportVoid) ((PKLDR_DATA_TABLE_ENTRY)((ULONG_PTR)(ImportVoid) & ~0x1))
  6621. #define POINTER_TO_SINGLE_ENTRY(Pointer) ((PKLDR_DATA_TABLE_ENTRY)((ULONG_PTR)(Pointer) | 0x1))
  6622. // #define _MI_DEBUG_RONLY 1 // Uncomment this for session readonly tracking
  6623. #if _MI_DEBUG_RONLY
  6624. VOID
  6625. MiAssertNotSessionData (
  6626. IN PMMPTE PointerPte
  6627. );
  6628. VOID
  6629. MiLogSessionDataStart (
  6630. IN PKLDR_DATA_TABLE_ENTRY DataTableEntry
  6631. );
  6632. #define MI_ASSERT_NOT_SESSION_DATA(PTE) MiAssertNotSessionData(PTE)
  6633. #define MI_LOG_SESSION_DATA_START(DataTableEntry) MiLogSessionDataStart(DataTableEntry)
  6634. #else
  6635. #define MI_ASSERT_NOT_SESSION_DATA(PTE)
  6636. #define MI_LOG_SESSION_DATA_START(DataTableEntry)
  6637. #endif
  6638. //
  6639. // This tracks driver-specified individual verifier thunks.
  6640. //
  6641. typedef struct _DRIVER_SPECIFIED_VERIFIER_THUNKS {
  6642. LIST_ENTRY ListEntry;
  6643. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  6644. ULONG NumberOfThunks;
  6645. } DRIVER_SPECIFIED_VERIFIER_THUNKS, *PDRIVER_SPECIFIED_VERIFIER_THUNKS;
  6646. // #define _MI_DEBUG_SUB 1 // Uncomment this for subsection logging
  6647. #if defined (_MI_DEBUG_SUB)
  6648. extern ULONG MiTrackSubs;
  6649. #define MI_SUB_BACKTRACE_LENGTH 8
  6650. typedef struct _MI_SUB_TRACES {
  6651. PETHREAD Thread;
  6652. PMSUBSECTION Subsection;
  6653. PCONTROL_AREA ControlArea;
  6654. ULONG_PTR CallerId;
  6655. PVOID StackTrace [MI_SUB_BACKTRACE_LENGTH];
  6656. MSUBSECTION SubsectionContents;
  6657. CONTROL_AREA ControlAreaContents;
  6658. } MI_SUB_TRACES, *PMI_SUB_TRACES;
  6659. extern LONG MiSubsectionIndex;
  6660. extern PMI_SUB_TRACES MiSubsectionTraces;
  6661. VOID
  6662. FORCEINLINE
  6663. MiSnapSubsection (
  6664. IN PMSUBSECTION Subsection,
  6665. IN ULONG CallerId
  6666. )
  6667. {
  6668. PMI_SUB_TRACES Information;
  6669. PCONTROL_AREA ControlArea;
  6670. ULONG Index;
  6671. ULONG Hash;
  6672. if (MiSubsectionTraces == NULL) {
  6673. return;
  6674. }
  6675. ControlArea = Subsection->ControlArea;
  6676. Index = InterlockedIncrement (&MiSubsectionIndex);
  6677. Index &= (MiTrackSubs - 1);
  6678. Information = &MiSubsectionTraces[Index];
  6679. Information->Subsection = Subsection;
  6680. Information->ControlArea = ControlArea;
  6681. *(PMSUBSECTION)&Information->SubsectionContents = *Subsection;
  6682. *(PCONTROL_AREA)&Information->ControlAreaContents = *ControlArea;
  6683. Information->Thread = PsGetCurrentThread();
  6684. Information->CallerId = CallerId;
  6685. #if defined (_WIN64)
  6686. if (KeAreAllApcsDisabled () == TRUE) {
  6687. Information->StackTrace[1] = (PVOID) _ReturnAddress ();
  6688. Information->StackTrace[0] = MiGetInstructionPointer ();
  6689. }
  6690. else
  6691. #endif
  6692. RtlCaptureStackBackTrace (0, MI_SUB_BACKTRACE_LENGTH, Information->StackTrace, &Hash);
  6693. }
  6694. #define MI_SNAP_SUB(_Sub, callerid) MiSnapSubsection(_Sub, callerid)
  6695. #else
  6696. #define MI_SNAP_SUB(_Sub, callerid)
  6697. #endif
  6698. //
  6699. // Hot-patching private definitions
  6700. //
  6701. extern LIST_ENTRY MiHotPatchList;
  6702. #endif // MI