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.

6243 lines
178 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. mapview.c
  5. Abstract:
  6. This module contains the routines which implement the
  7. NtMapViewOfSection service.
  8. Author:
  9. Lou Perazzoli (loup) 22-May-1989
  10. Landy Wang (landyw) 02-June-1997
  11. Revision History:
  12. --*/
  13. #include "mi.h"
  14. #if defined(_WIN64)
  15. #include <wow64t.h>
  16. #endif
  17. const ULONG MMDB = 'bDmM';
  18. extern const ULONG MMVADKEY;
  19. #if DBG
  20. #define MI_BP_BADMAPS() TRUE
  21. #else
  22. ULONG MiStopBadMaps;
  23. #define MI_BP_BADMAPS() (MiStopBadMaps & 0x1)
  24. #endif
  25. NTSTATUS
  26. MiSetPageModified (
  27. IN PMMVAD Vad,
  28. IN PVOID Address
  29. );
  30. extern LIST_ENTRY MmLoadedUserImageList;
  31. ULONG MiSubsectionsConvertedToDynamic;
  32. #define X256MEG (256*1024*1024)
  33. #if DBG
  34. extern PEPROCESS MmWatchProcess;
  35. #endif // DBG
  36. #define ROUND_TO_PAGES64(Size) (((UINT64)(Size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
  37. MMSESSION MmSession;
  38. NTSTATUS
  39. MiMapViewOfImageSection (
  40. IN PCONTROL_AREA ControlArea,
  41. IN PEPROCESS Process,
  42. IN PVOID *CapturedBase,
  43. IN PLARGE_INTEGER SectionOffset,
  44. IN PSIZE_T CapturedViewSize,
  45. IN PSECTION Section,
  46. IN SECTION_INHERIT InheritDisposition,
  47. IN ULONG_PTR ZeroBits,
  48. IN SIZE_T ImageCommitment
  49. );
  50. NTSTATUS
  51. MiMapViewOfDataSection (
  52. IN PCONTROL_AREA ControlArea,
  53. IN PEPROCESS Process,
  54. IN PVOID *CapturedBase,
  55. IN PLARGE_INTEGER SectionOffset,
  56. IN PSIZE_T CapturedViewSize,
  57. IN PSECTION Section,
  58. IN SECTION_INHERIT InheritDisposition,
  59. IN ULONG ProtectionMask,
  60. IN SIZE_T CommitSize,
  61. IN ULONG_PTR ZeroBits,
  62. IN ULONG AllocationType
  63. );
  64. VOID
  65. MiRemoveMappedPtes (
  66. IN PVOID BaseAddress,
  67. IN ULONG NumberOfPtes,
  68. IN PCONTROL_AREA ControlArea,
  69. IN PMMSUPPORT WorkingSetInfo
  70. );
  71. NTSTATUS
  72. MiMapViewInSystemSpace (
  73. IN PVOID Section,
  74. IN PMMSESSION Session,
  75. OUT PVOID *MappedBase,
  76. IN OUT PSIZE_T ViewSize
  77. );
  78. NTSTATUS
  79. MiUnmapViewInSystemSpace (
  80. IN PMMSESSION Session,
  81. IN PVOID MappedBase
  82. );
  83. VOID
  84. MiFillSystemPageDirectory (
  85. PVOID Base,
  86. SIZE_T NumberOfBytes
  87. );
  88. VOID
  89. MiLoadUserSymbols (
  90. IN PCONTROL_AREA ControlArea,
  91. IN PVOID StartingAddress,
  92. IN PEPROCESS Process
  93. );
  94. #if DBG
  95. VOID
  96. VadTreeWalk (
  97. VOID
  98. );
  99. VOID
  100. MiDumpConflictingVad(
  101. IN PVOID StartingAddress,
  102. IN PVOID EndingAddress,
  103. IN PMMVAD Vad
  104. );
  105. #endif //DBG
  106. PVOID
  107. MiCacheImageSymbols(
  108. IN PVOID ImageBase
  109. );
  110. PVOID
  111. MiInsertInSystemSpace (
  112. IN PMMSESSION Session,
  113. IN ULONG SizeIn64k,
  114. IN PCONTROL_AREA ControlArea
  115. );
  116. ULONG
  117. MiRemoveFromSystemSpace (
  118. IN PMMSESSION Session,
  119. IN PVOID Base,
  120. OUT PCONTROL_AREA *ControlArea
  121. );
  122. VOID
  123. MiInsertPhysicalViewAndRefControlArea (
  124. IN PEPROCESS Process,
  125. IN PCONTROL_AREA ControlArea,
  126. IN PMI_PHYSICAL_VIEW PhysicalView
  127. );
  128. #ifdef ALLOC_PRAGMA
  129. #pragma alloc_text(PAGE,NtMapViewOfSection)
  130. #pragma alloc_text(PAGE,MmMapViewOfSection)
  131. #pragma alloc_text(PAGE,MmSecureVirtualMemory)
  132. #pragma alloc_text(PAGE,MiSecureVirtualMemory)
  133. #pragma alloc_text(PAGE,MmUnsecureVirtualMemory)
  134. #pragma alloc_text(PAGE,MiUnsecureVirtualMemory)
  135. #pragma alloc_text(PAGE,MiCacheImageSymbols)
  136. #pragma alloc_text(PAGE,NtAreMappedFilesTheSame)
  137. #pragma alloc_text(PAGE,MiLoadUserSymbols)
  138. #pragma alloc_text(PAGE,MiMapViewOfImageSection)
  139. #pragma alloc_text(PAGE,MiMapViewOfDataSection)
  140. #pragma alloc_text(PAGE,MiMapViewOfPhysicalSection)
  141. #pragma alloc_text(PAGE,MiInsertInSystemSpace)
  142. #pragma alloc_text(PAGE,MmMapViewInSystemSpace)
  143. #pragma alloc_text(PAGE,MmMapViewInSessionSpace)
  144. #pragma alloc_text(PAGE,MiUnmapViewInSystemSpace)
  145. #pragma alloc_text(PAGE,MmUnmapViewInSystemSpace)
  146. #pragma alloc_text(PAGE,MmUnmapViewInSessionSpace)
  147. #pragma alloc_text(PAGE,MiMapViewInSystemSpace)
  148. #pragma alloc_text(PAGE,MiRemoveFromSystemSpace)
  149. #pragma alloc_text(PAGE,MiInitializeSystemSpaceMap)
  150. #pragma alloc_text(PAGE,MiFreeSessionSpaceMap)
  151. #pragma alloc_text(PAGE,MmGetSessionMappedViewInformation)
  152. #pragma alloc_text(PAGELK,MiInsertPhysicalViewAndRefControlArea)
  153. #if DBG
  154. #pragma alloc_text(PAGE,MiDumpConflictingVad)
  155. #endif
  156. #endif
  157. NTSTATUS
  158. NtMapViewOfSection (
  159. IN HANDLE SectionHandle,
  160. IN HANDLE ProcessHandle,
  161. IN OUT PVOID *BaseAddress,
  162. IN ULONG_PTR ZeroBits,
  163. IN SIZE_T CommitSize,
  164. IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
  165. IN OUT PSIZE_T ViewSize,
  166. IN SECTION_INHERIT InheritDisposition,
  167. IN ULONG AllocationType,
  168. IN ULONG Protect
  169. )
  170. /*++
  171. Routine Description:
  172. This function maps a view in the specified subject process to
  173. the section object.
  174. Arguments:
  175. SectionHandle - Supplies an open handle to a section object.
  176. ProcessHandle - Supplies an open handle to a process object.
  177. BaseAddress - Supplies a pointer to a variable that will receive
  178. the base address of the view. If the initial value
  179. of this argument is not null, then the view will
  180. be allocated starting at the specified virtual
  181. address rounded down to the next 64kb address
  182. boundary. If the initial value of this argument is
  183. null, then the operating system will determine
  184. where to allocate the view using the information
  185. specified by the ZeroBits argument value and the
  186. section allocation attributes (i.e. based and
  187. tiled).
  188. ZeroBits - Supplies the number of high order address bits that
  189. must be zero in the base address of the section
  190. view. The value of this argument must be less than
  191. or equal to the maximum number of zero bits and is only
  192. used when memory management determines where to allocate
  193. the view (i.e. when BaseAddress is null).
  194. If ZeroBits is zero, then no zero bit constraints are applied.
  195. If ZeroBits is greater than 0 and less than 32, then it is
  196. the number of leading zero bits from bit 31. Bits 63:32 are
  197. also required to be zero. This retains compatibility
  198. with 32-bit systems.
  199. If ZeroBits is greater than 32, then it is considered as
  200. a mask and the number of leading zeroes are counted out
  201. in the mask. This then becomes the zero bits argument.
  202. CommitSize - Supplies the size of the initially committed region
  203. of the view in bytes. This value is rounded up to
  204. the next host page size boundary.
  205. SectionOffset - Supplies the offset from the beginning of the
  206. section to the view in bytes. This value is
  207. rounded down to the next host page size boundary.
  208. ViewSize - Supplies a pointer to a variable that will receive
  209. the actual size in bytes of the view. If the value
  210. of this argument is zero, then a view of the
  211. section will be mapped starting at the specified
  212. section offset and continuing to the end of the
  213. section. Otherwise the initial value of this
  214. argument specifies the size of the view in bytes
  215. and is rounded up to the next host page size
  216. boundary.
  217. InheritDisposition - Supplies a value that specifies how the
  218. view is to be shared by a child process created
  219. with a create process operation.
  220. InheritDisposition Values
  221. ViewShare - Inherit view and share a single copy
  222. of the committed pages with a child process
  223. using the current protection value.
  224. ViewUnmap - Do not map the view into a child process.
  225. AllocationType - Supplies the type of allocation.
  226. MEM_TOP_DOWN
  227. MEM_DOS_LIM
  228. MEM_LARGE_PAGES
  229. MEM_RESERVE - for file mapped sections only.
  230. Protect - Supplies the protection desired for the region of
  231. initially committed pages.
  232. Protect Values
  233. PAGE_NOACCESS - No access to the committed region
  234. of pages is allowed. An attempt to read,
  235. write, or execute the committed region
  236. results in an access violation (i.e. a GP
  237. fault).
  238. PAGE_EXECUTE - Execute access to the committed
  239. region of pages is allowed. An attempt to
  240. read or write the committed region results in
  241. an access violation.
  242. PAGE_READONLY - Read only and execute access to the
  243. committed region of pages is allowed. An
  244. attempt to write the committed region results
  245. in an access violation.
  246. PAGE_READWRITE - Read, write, and execute access to
  247. the region of committed pages is allowed. If
  248. write access to the underlying section is
  249. allowed, then a single copy of the pages are
  250. shared. Otherwise the pages are shared read
  251. only/copy on write.
  252. Return Value:
  253. Various NTSTATUS codes.
  254. --*/
  255. {
  256. PSECTION Section;
  257. PEPROCESS Process;
  258. KPROCESSOR_MODE PreviousMode;
  259. NTSTATUS Status;
  260. PVOID CapturedBase;
  261. SIZE_T CapturedViewSize;
  262. LARGE_INTEGER TempViewSize;
  263. LARGE_INTEGER CapturedOffset;
  264. ULONGLONG HighestPhysicalAddressInPfnDatabase;
  265. ACCESS_MASK DesiredSectionAccess;
  266. ULONG ProtectMaskForAccess;
  267. LOGICAL WriteCombined;
  268. PETHREAD CurrentThread;
  269. PEPROCESS CurrentProcess;
  270. PAGED_CODE();
  271. //
  272. // Check the zero bits argument for correctness.
  273. //
  274. #if defined (_WIN64)
  275. if (ZeroBits >= 32) {
  276. //
  277. // ZeroBits is a mask instead of a count. Translate it to a count now.
  278. //
  279. ZeroBits = 64 - RtlFindMostSignificantBit (ZeroBits) - 1;
  280. }
  281. else if (ZeroBits) {
  282. ZeroBits += 32;
  283. }
  284. #endif
  285. if (ZeroBits > MM_MAXIMUM_ZERO_BITS) {
  286. return STATUS_INVALID_PARAMETER_4;
  287. }
  288. //
  289. // Check the inherit disposition flags.
  290. //
  291. if ((InheritDisposition > ViewUnmap) ||
  292. (InheritDisposition < ViewShare)) {
  293. return STATUS_INVALID_PARAMETER_8;
  294. }
  295. //
  296. // Check the allocation type field.
  297. //
  298. #ifdef i386
  299. //
  300. // Only allow DOS_LIM support for i386. The MEM_DOS_LIM flag allows
  301. // map views of data sections to be done on 4k boundaries rather
  302. // than 64k boundaries.
  303. //
  304. if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES | MEM_DOS_LIM |
  305. SEC_NO_CHANGE | MEM_RESERVE)) != 0) {
  306. return STATUS_INVALID_PARAMETER_9;
  307. }
  308. #else
  309. if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES |
  310. SEC_NO_CHANGE | MEM_RESERVE)) != 0) {
  311. return STATUS_INVALID_PARAMETER_9;
  312. }
  313. #endif //i386
  314. //
  315. // Check the protection field.
  316. //
  317. if (Protect & PAGE_WRITECOMBINE) {
  318. Protect &= ~PAGE_WRITECOMBINE;
  319. WriteCombined = TRUE;
  320. }
  321. else {
  322. WriteCombined = FALSE;
  323. }
  324. ProtectMaskForAccess = MiMakeProtectionMask (Protect);
  325. if (ProtectMaskForAccess == MM_INVALID_PROTECTION) {
  326. return STATUS_INVALID_PAGE_PROTECTION;
  327. }
  328. ProtectMaskForAccess = ProtectMaskForAccess & 0x7;
  329. DesiredSectionAccess = MmMakeSectionAccess[ProtectMaskForAccess];
  330. CurrentThread = PsGetCurrentThread ();
  331. CurrentProcess = PsGetCurrentProcessByThread (CurrentThread);
  332. PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  333. //
  334. // Establish an exception handler, probe the specified addresses
  335. // for write access and capture the initial values.
  336. //
  337. try {
  338. if (PreviousMode != KernelMode) {
  339. ProbeForWritePointer ((PULONG)BaseAddress);
  340. ProbeForWriteUlong_ptr (ViewSize);
  341. }
  342. if (ARGUMENT_PRESENT (SectionOffset)) {
  343. if (PreviousMode != KernelMode) {
  344. ProbeForWriteSmallStructure (SectionOffset,
  345. sizeof(LARGE_INTEGER),
  346. PROBE_ALIGNMENT (LARGE_INTEGER));
  347. }
  348. CapturedOffset = *SectionOffset;
  349. }
  350. else {
  351. ZERO_LARGE (CapturedOffset);
  352. }
  353. //
  354. // Capture the base address.
  355. //
  356. CapturedBase = *BaseAddress;
  357. //
  358. // Capture the region size.
  359. //
  360. CapturedViewSize = *ViewSize;
  361. } except (ExSystemExceptionFilter()) {
  362. //
  363. // If an exception occurs during the probe or capture
  364. // of the initial values, then handle the exception and
  365. // return the exception code as the status value.
  366. //
  367. return GetExceptionCode();
  368. }
  369. //
  370. // Make sure the specified starting and ending addresses are
  371. // within the user part of the virtual address space.
  372. //
  373. if (CapturedBase > MM_HIGHEST_VAD_ADDRESS) {
  374. //
  375. // Invalid base address.
  376. //
  377. return STATUS_INVALID_PARAMETER_3;
  378. }
  379. if (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)CapturedBase) <
  380. CapturedViewSize) {
  381. //
  382. // Invalid region size;
  383. //
  384. return STATUS_INVALID_PARAMETER_3;
  385. }
  386. if (((ULONG_PTR)CapturedBase + CapturedViewSize) > ((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits)) {
  387. //
  388. // Desired Base and zero_bits conflict.
  389. //
  390. return STATUS_INVALID_PARAMETER_4;
  391. }
  392. Status = ObReferenceObjectByHandle ( ProcessHandle,
  393. PROCESS_VM_OPERATION,
  394. PsProcessType,
  395. PreviousMode,
  396. (PVOID *)&Process,
  397. NULL );
  398. if (!NT_SUCCESS(Status)) {
  399. return Status;
  400. }
  401. //
  402. // Reference the section object, if a view is mapped to the section
  403. // object, the object is not dereferenced as the virtual address
  404. // descriptor contains a pointer to the section object.
  405. //
  406. Status = ObReferenceObjectByHandle ( SectionHandle,
  407. DesiredSectionAccess,
  408. MmSectionObjectType,
  409. PreviousMode,
  410. (PVOID *)&Section,
  411. NULL );
  412. if (!NT_SUCCESS(Status)) {
  413. goto ErrorReturn1;
  414. }
  415. if (Section->u.Flags.Image == 0) {
  416. //
  417. // This is not an image section, make sure the section page
  418. // protection is compatible with the specified page protection.
  419. //
  420. if (!MiIsProtectionCompatible (Section->InitialPageProtection,
  421. Protect)) {
  422. Status = STATUS_SECTION_PROTECTION;
  423. goto ErrorReturn;
  424. }
  425. }
  426. //
  427. // Check to see if this the section backs physical memory, if
  428. // so DON'T align the offset on a 64K boundary, just a 4k boundary.
  429. //
  430. if (Section->Segment->ControlArea->u.Flags.PhysicalMemory) {
  431. HighestPhysicalAddressInPfnDatabase = (ULONGLONG)MmHighestPhysicalPage << PAGE_SHIFT;
  432. CapturedOffset.LowPart = CapturedOffset.LowPart & ~(PAGE_SIZE - 1);
  433. //
  434. // No usermode mappings past the end of the PFN database are allowed.
  435. // Address wrap is checked in the common path.
  436. //
  437. if (PreviousMode != KernelMode) {
  438. if ((ULONGLONG)(CapturedOffset.QuadPart + CapturedViewSize) > HighestPhysicalAddressInPfnDatabase) {
  439. Status = STATUS_INVALID_PARAMETER_6;
  440. goto ErrorReturn;
  441. }
  442. }
  443. }
  444. else {
  445. //
  446. // Make sure alignments are correct for specified address
  447. // and offset into the file.
  448. //
  449. if ((AllocationType & MEM_DOS_LIM) == 0) {
  450. if (((ULONG_PTR)CapturedBase & (X64K - 1)) != 0) {
  451. Status = STATUS_MAPPED_ALIGNMENT;
  452. goto ErrorReturn;
  453. }
  454. if ((ARGUMENT_PRESENT (SectionOffset)) &&
  455. ((CapturedOffset.LowPart & (X64K - 1)) != 0)) {
  456. Status = STATUS_MAPPED_ALIGNMENT;
  457. goto ErrorReturn;
  458. }
  459. }
  460. }
  461. //
  462. // Check to make sure the view size plus the offset is less
  463. // than the size of the section.
  464. //
  465. if ((ULONGLONG) (CapturedOffset.QuadPart + CapturedViewSize) <
  466. (ULONGLONG)CapturedOffset.QuadPart) {
  467. Status = STATUS_INVALID_VIEW_SIZE;
  468. goto ErrorReturn;
  469. }
  470. if (((ULONGLONG) (CapturedOffset.QuadPart + CapturedViewSize) >
  471. (ULONGLONG)Section->SizeOfSection.QuadPart) &&
  472. ((AllocationType & MEM_RESERVE) == 0)) {
  473. Status = STATUS_INVALID_VIEW_SIZE;
  474. goto ErrorReturn;
  475. }
  476. if (CapturedViewSize == 0) {
  477. //
  478. // Set the view size to be size of the section less the offset.
  479. //
  480. TempViewSize.QuadPart = Section->SizeOfSection.QuadPart -
  481. CapturedOffset.QuadPart;
  482. CapturedViewSize = (SIZE_T)TempViewSize.QuadPart;
  483. if (
  484. #if !defined(_WIN64)
  485. (TempViewSize.HighPart != 0) ||
  486. #endif
  487. (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)CapturedBase) <
  488. CapturedViewSize)) {
  489. //
  490. // Invalid region size;
  491. //
  492. Status = STATUS_INVALID_VIEW_SIZE;
  493. goto ErrorReturn;
  494. }
  495. }
  496. //
  497. // Check commit size.
  498. //
  499. if ((CommitSize > CapturedViewSize) &&
  500. ((AllocationType & MEM_RESERVE) == 0)) {
  501. Status = STATUS_INVALID_PARAMETER_5;
  502. goto ErrorReturn;
  503. }
  504. if (WriteCombined == TRUE) {
  505. Protect |= PAGE_WRITECOMBINE;
  506. }
  507. Status = MmMapViewOfSection ((PVOID)Section,
  508. Process,
  509. &CapturedBase,
  510. ZeroBits,
  511. CommitSize,
  512. &CapturedOffset,
  513. &CapturedViewSize,
  514. InheritDisposition,
  515. AllocationType,
  516. Protect);
  517. if (!NT_SUCCESS(Status) ) {
  518. if ((Status == STATUS_CONFLICTING_ADDRESSES) &&
  519. (Section->Segment->ControlArea->u.Flags.Image) &&
  520. (Process == CurrentProcess)) {
  521. DbgkMapViewOfSection (Section,
  522. CapturedBase,
  523. CapturedOffset.LowPart,
  524. CapturedViewSize);
  525. }
  526. goto ErrorReturn;
  527. }
  528. //
  529. // Any time the current process maps an image file,
  530. // a potential debug event occurs. DbgkMapViewOfSection
  531. // handles these events.
  532. //
  533. if ((Section->Segment->ControlArea->u.Flags.Image) &&
  534. (Process == CurrentProcess)) {
  535. if (Status != STATUS_IMAGE_NOT_AT_BASE) {
  536. DbgkMapViewOfSection (Section,
  537. CapturedBase,
  538. CapturedOffset.LowPart,
  539. CapturedViewSize);
  540. }
  541. }
  542. //
  543. // Establish an exception handler and write the size and base address.
  544. //
  545. try {
  546. *ViewSize = CapturedViewSize;
  547. *BaseAddress = CapturedBase;
  548. if (ARGUMENT_PRESENT(SectionOffset)) {
  549. *SectionOffset = CapturedOffset;
  550. }
  551. } except (EXCEPTION_EXECUTE_HANDLER) {
  552. NOTHING;
  553. }
  554. ErrorReturn:
  555. ObDereferenceObject (Section);
  556. ErrorReturn1:
  557. ObDereferenceObject (Process);
  558. return Status;
  559. }
  560. NTSTATUS
  561. MmMapViewOfSection (
  562. IN PVOID SectionToMap,
  563. IN PEPROCESS Process,
  564. IN OUT PVOID *CapturedBase,
  565. IN ULONG_PTR ZeroBits,
  566. IN SIZE_T CommitSize,
  567. IN OUT PLARGE_INTEGER SectionOffset,
  568. IN OUT PSIZE_T CapturedViewSize,
  569. IN SECTION_INHERIT InheritDisposition,
  570. IN ULONG AllocationType,
  571. IN ULONG Protect
  572. )
  573. /*++
  574. Routine Description:
  575. This function maps a view in the specified subject process to
  576. the section object.
  577. This function is a kernel mode interface to allow LPC to map
  578. a section given the section pointer to map.
  579. This routine assumes all arguments have been probed and captured.
  580. ********************************************************************
  581. ********************************************************************
  582. ********************************************************************
  583. NOTE:
  584. CapturedViewSize, SectionOffset, and CapturedBase must be
  585. captured in non-paged system space (i.e., kernel stack).
  586. ********************************************************************
  587. ********************************************************************
  588. ********************************************************************
  589. Arguments:
  590. SectionToMap - Supplies a pointer to the section object.
  591. Process - Supplies a pointer to the process object.
  592. BaseAddress - Supplies a pointer to a variable that will receive
  593. the base address of the view. If the initial value
  594. of this argument is not NULL, then the view will
  595. be allocated starting at the specified virtual
  596. address rounded down to the next 64kb address
  597. boundary. If the initial value of this argument is
  598. NULL, then the operating system will determine
  599. where to allocate the view using the information
  600. specified by the ZeroBits argument value and the
  601. section allocation attributes (i.e. based and
  602. tiled).
  603. ZeroBits - Supplies the number of high order address bits that
  604. must be zero in the base address of the section
  605. view. The value of this argument must be less than
  606. 21 and is only used when the operating system
  607. determines where to allocate the view (i.e. when
  608. BaseAddress is NULL).
  609. CommitSize - Supplies the size of the initially committed region
  610. of the view in bytes. This value is rounded up to
  611. the next host page size boundary.
  612. SectionOffset - Supplies the offset from the beginning of the
  613. section to the view in bytes. This value is
  614. rounded down to the next host page size boundary.
  615. ViewSize - Supplies a pointer to a variable that will receive
  616. the actual size in bytes of the view. If the value
  617. of this argument is zero, then a view of the
  618. section will be mapped starting at the specified
  619. section offset and continuing to the end of the
  620. section. Otherwise the initial value of this
  621. argument specifies the size of the view in bytes
  622. and is rounded up to the next host page size boundary.
  623. InheritDisposition - Supplies a value that specifies how the
  624. view is to be shared by a child process created
  625. with a create process operation.
  626. AllocationType - Supplies the type of allocation.
  627. Protect - Supplies the protection desired for the region of
  628. initially committed pages.
  629. Return Value:
  630. NTSTATUS.
  631. --*/
  632. {
  633. KAPC_STATE ApcState;
  634. LOGICAL Attached;
  635. PSECTION Section;
  636. PCONTROL_AREA ControlArea;
  637. ULONG ProtectionMask;
  638. NTSTATUS status;
  639. LOGICAL WriteCombined;
  640. SIZE_T ImageCommitment;
  641. ULONG ExecutePermission;
  642. PAGED_CODE();
  643. Attached = FALSE;
  644. Section = (PSECTION)SectionToMap;
  645. //
  646. // Check to make sure the section is not smaller than the view size.
  647. //
  648. if ((LONGLONG)*CapturedViewSize > Section->SizeOfSection.QuadPart) {
  649. if ((AllocationType & MEM_RESERVE) == 0) {
  650. return STATUS_INVALID_VIEW_SIZE;
  651. }
  652. }
  653. if (AllocationType & MEM_RESERVE) {
  654. if (((Section->InitialPageProtection & PAGE_READWRITE) |
  655. (Section->InitialPageProtection & PAGE_EXECUTE_READWRITE)) == 0) {
  656. return STATUS_SECTION_PROTECTION;
  657. }
  658. }
  659. if (Section->u.Flags.NoCache) {
  660. Protect |= PAGE_NOCACHE;
  661. }
  662. //
  663. // Note that write combining is only relevant to physical memory sections
  664. // because they are never trimmed - the write combining bits in a PTE entry
  665. // are not preserved across trims.
  666. //
  667. if (Protect & PAGE_WRITECOMBINE) {
  668. Protect &= ~PAGE_WRITECOMBINE;
  669. WriteCombined = TRUE;
  670. }
  671. else {
  672. WriteCombined = FALSE;
  673. }
  674. //
  675. // Check the protection field.
  676. //
  677. ProtectionMask = MiMakeProtectionMask (Protect);
  678. if (ProtectionMask == MM_INVALID_PROTECTION) {
  679. return STATUS_INVALID_PAGE_PROTECTION;
  680. }
  681. ControlArea = Section->Segment->ControlArea;
  682. //
  683. // If the specified process is not the current process, attach
  684. // to the specified process.
  685. //
  686. if (PsGetCurrentProcess() != Process) {
  687. KeStackAttachProcess (&Process->Pcb, &ApcState);
  688. Attached = TRUE;
  689. }
  690. //
  691. // Get the address creation mutex to block multiple threads
  692. // creating or deleting address space at the same time.
  693. //
  694. LOCK_ADDRESS_SPACE (Process);
  695. //
  696. // Make sure the address space was not deleted, if so, return an error.
  697. //
  698. if (Process->Flags & PS_PROCESS_FLAGS_VM_DELETED) {
  699. status = STATUS_PROCESS_IS_TERMINATING;
  700. goto ErrorReturn;
  701. }
  702. //
  703. // Map the view base on the type.
  704. //
  705. if (ControlArea->u.Flags.PhysicalMemory) {
  706. status = MiMapViewOfPhysicalSection (ControlArea,
  707. Process,
  708. CapturedBase,
  709. SectionOffset,
  710. CapturedViewSize,
  711. ProtectionMask,
  712. ZeroBits,
  713. AllocationType,
  714. WriteCombined);
  715. }
  716. else if (ControlArea->u.Flags.Image) {
  717. if (AllocationType & MEM_RESERVE) {
  718. status = STATUS_INVALID_PARAMETER_9;
  719. }
  720. else if (WriteCombined == TRUE) {
  721. status = STATUS_INVALID_PARAMETER_10;
  722. }
  723. else {
  724. ImageCommitment = Section->Segment->u1.ImageCommitment;
  725. status = MiMapViewOfImageSection (ControlArea,
  726. Process,
  727. CapturedBase,
  728. SectionOffset,
  729. CapturedViewSize,
  730. Section,
  731. InheritDisposition,
  732. ZeroBits,
  733. ImageCommitment);
  734. }
  735. }
  736. else {
  737. //
  738. // Not an image section, therefore it is a data section.
  739. //
  740. if (WriteCombined == TRUE) {
  741. status = STATUS_INVALID_PARAMETER_10;
  742. }
  743. else {
  744. //
  745. // Add execute permission if necessary.
  746. //
  747. #if defined (_WIN64)
  748. if (Process->Wow64Process == NULL && Process->Peb != NULL)
  749. #elif defined (_X86PAE_)
  750. if (Process->Peb != NULL)
  751. #else
  752. if (FALSE)
  753. #endif
  754. {
  755. ExecutePermission = 0;
  756. try {
  757. ExecutePermission = Process->Peb->ExecuteOptions & MEM_EXECUTE_OPTION_DATA;
  758. } except (EXCEPTION_EXECUTE_HANDLER) {
  759. status = GetExceptionCode();
  760. goto ErrorReturn;
  761. }
  762. if (ExecutePermission != 0) {
  763. switch (Protect & 0xF) {
  764. case PAGE_READONLY:
  765. Protect &= ~PAGE_READONLY;
  766. Protect |= PAGE_EXECUTE_READ;
  767. break;
  768. case PAGE_READWRITE:
  769. Protect &= ~PAGE_READWRITE;
  770. Protect |= PAGE_EXECUTE_READWRITE;
  771. break;
  772. case PAGE_WRITECOPY:
  773. Protect &= ~PAGE_WRITECOPY;
  774. Protect |= PAGE_EXECUTE_WRITECOPY;
  775. break;
  776. default:
  777. break;
  778. }
  779. //
  780. // Recheck protection.
  781. //
  782. ProtectionMask = MiMakeProtectionMask (Protect);
  783. if (ProtectionMask == MM_INVALID_PROTECTION) {
  784. status = STATUS_INVALID_PAGE_PROTECTION;
  785. goto ErrorReturn;
  786. }
  787. }
  788. }
  789. status = MiMapViewOfDataSection (ControlArea,
  790. Process,
  791. CapturedBase,
  792. SectionOffset,
  793. CapturedViewSize,
  794. Section,
  795. InheritDisposition,
  796. ProtectionMask,
  797. CommitSize,
  798. ZeroBits,
  799. AllocationType);
  800. }
  801. }
  802. ErrorReturn:
  803. UNLOCK_ADDRESS_SPACE (Process);
  804. if (Attached) {
  805. KeUnstackDetachProcess (&ApcState);
  806. }
  807. return status;
  808. }
  809. VOID
  810. MiInsertPhysicalViewAndRefControlArea (
  811. IN PEPROCESS Process,
  812. IN PCONTROL_AREA ControlArea,
  813. IN PMI_PHYSICAL_VIEW PhysicalView
  814. )
  815. /*++
  816. Routine Description:
  817. This is a nonpaged helper routine to insert a physical view and reference
  818. the control area accordingly.
  819. Arguments:
  820. Process - Supplies a pointer to the process.
  821. ControlArea - Supplies a pointer to the control area.
  822. PhysicalView - Supplies a pointer to the physical view.
  823. Return Value:
  824. None.
  825. Environment:
  826. Kernel Mode, address creation and working set mutex held.
  827. --*/
  828. {
  829. KIRQL OldIrql;
  830. MmLockPagableSectionByHandle (ExPageLockHandle);
  831. //
  832. // Increment the count of the number of views for the
  833. // section object. This requires the PFN lock to be held.
  834. //
  835. LOCK_PFN (OldIrql);
  836. ASSERT (PhysicalView->Vad->u.VadFlags.PhysicalMapping == 1);
  837. ASSERT (Process->PhysicalVadRoot != NULL);
  838. MiInsertNode ((PMMADDRESS_NODE)PhysicalView, Process->PhysicalVadRoot);
  839. ControlArea->NumberOfMappedViews += 1;
  840. ControlArea->NumberOfUserReferences += 1;
  841. ASSERT (ControlArea->NumberOfSectionReferences != 0);
  842. UNLOCK_PFN (OldIrql);
  843. MmUnlockPagableImageSection (ExPageLockHandle);
  844. }
  845. //
  846. // Nonpaged wrapper.
  847. //
  848. LOGICAL
  849. MiCheckCacheAttributes (
  850. IN PFN_NUMBER PageFrameIndex,
  851. IN PFN_NUMBER NumberOfPages,
  852. IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
  853. )
  854. {
  855. KIRQL OldIrql;
  856. PMMPFN Pfn1;
  857. PFN_NUMBER BadFrameStart;
  858. PFN_NUMBER BadFrameEnd;
  859. LOGICAL AttemptedMapOfUnownedFrame;
  860. #if DBG
  861. #define BACKTRACE_LENGTH 8
  862. ULONG i;
  863. ULONG Hash;
  864. PVOID StackTrace [BACKTRACE_LENGTH];
  865. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  866. PUNICODE_STRING BadDriverName;
  867. #endif
  868. ASSERT (KeGetCurrentIrql () <= APC_LEVEL);
  869. BadFrameStart = 0;
  870. BadFrameEnd = 0;
  871. AttemptedMapOfUnownedFrame = FALSE;
  872. LOCK_PFN (OldIrql);
  873. do {
  874. if (MI_IS_PFN (PageFrameIndex)) {
  875. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  876. switch (Pfn1->u3.e1.CacheAttribute) {
  877. case MiCached:
  878. if (CacheAttribute != MiCached) {
  879. UNLOCK_PFN (OldIrql);
  880. return FALSE;
  881. }
  882. break;
  883. case MiNonCached:
  884. if (CacheAttribute != MiNonCached) {
  885. UNLOCK_PFN (OldIrql);
  886. return FALSE;
  887. }
  888. break;
  889. case MiWriteCombined:
  890. if (CacheAttribute != MiWriteCombined) {
  891. UNLOCK_PFN (OldIrql);
  892. return FALSE;
  893. }
  894. break;
  895. case MiNotMapped:
  896. if (AttemptedMapOfUnownedFrame == FALSE) {
  897. BadFrameStart = PageFrameIndex;
  898. AttemptedMapOfUnownedFrame = TRUE;
  899. }
  900. BadFrameEnd = PageFrameIndex;
  901. break;
  902. default:
  903. ASSERT (FALSE);
  904. break;
  905. }
  906. }
  907. PageFrameIndex += 1;
  908. NumberOfPages -= 1;
  909. } while (NumberOfPages != 0);
  910. UNLOCK_PFN (OldIrql);
  911. if (AttemptedMapOfUnownedFrame == TRUE) {
  912. #if DBG
  913. BadDriverName = NULL;
  914. RtlZeroMemory (StackTrace, sizeof (StackTrace));
  915. RtlCaptureStackBackTrace (1, BACKTRACE_LENGTH, StackTrace, &Hash);
  916. for (i = 0; i < BACKTRACE_LENGTH; i += 1) {
  917. if (StackTrace[i] <= MM_HIGHEST_USER_ADDRESS) {
  918. break;
  919. }
  920. DataTableEntry = MiLookupDataTableEntry (StackTrace[i], FALSE);
  921. if ((DataTableEntry != NULL) && ((PVOID)DataTableEntry != (PVOID)PsLoadedModuleList.Flink)) {
  922. //
  923. // Found the bad caller.
  924. //
  925. BadDriverName = &DataTableEntry->FullDllName;
  926. }
  927. }
  928. if (BadDriverName != NULL) {
  929. DbgPrint ("*******************************************************************************\n"
  930. "*\n"
  931. "* %wZ is mapping physical memory %p->%p\n"
  932. "* that it does not own. This can cause internal CPU corruption.\n"
  933. "*\n"
  934. "*******************************************************************************\n",
  935. BadDriverName,
  936. BadFrameStart << PAGE_SHIFT,
  937. (BadFrameEnd << PAGE_SHIFT) | (PAGE_SIZE - 1));
  938. }
  939. else {
  940. DbgPrint ("*******************************************************************************\n"
  941. "*\n"
  942. "* A driver is mapping physical memory %p->%p\n"
  943. "* that it does not own. This can cause internal CPU corruption.\n"
  944. "*\n"
  945. "*******************************************************************************\n",
  946. BadFrameStart << PAGE_SHIFT,
  947. (BadFrameEnd << PAGE_SHIFT) | (PAGE_SIZE - 1));
  948. }
  949. #else
  950. DbgPrint ("*******************************************************************************\n"
  951. "*\n"
  952. "* A driver is mapping physical memory %p->%p\n"
  953. "* that it does not own. This can cause internal CPU corruption.\n"
  954. "* A checked build will stop in the kernel debugger\n"
  955. "* so this problem can be fully debugged.\n"
  956. "*\n"
  957. "*******************************************************************************\n",
  958. BadFrameStart << PAGE_SHIFT,
  959. (BadFrameEnd << PAGE_SHIFT) | (PAGE_SIZE - 1));
  960. #endif
  961. if (MI_BP_BADMAPS()) {
  962. DbgBreakPoint ();
  963. }
  964. }
  965. return TRUE;
  966. }
  967. NTSTATUS
  968. MiMapViewOfPhysicalSection (
  969. IN PCONTROL_AREA ControlArea,
  970. IN PEPROCESS Process,
  971. IN PVOID *CapturedBase,
  972. IN PLARGE_INTEGER SectionOffset,
  973. IN PSIZE_T CapturedViewSize,
  974. IN ULONG ProtectionMask,
  975. IN ULONG_PTR ZeroBits,
  976. IN ULONG AllocationType,
  977. IN LOGICAL WriteCombined
  978. )
  979. /*++
  980. Routine Description:
  981. This routine maps the specified physical section into the
  982. specified process's address space.
  983. Arguments:
  984. see MmMapViewOfSection above...
  985. ControlArea - Supplies the control area for the section.
  986. Process - Supplies the process pointer which is receiving the section.
  987. ProtectionMask - Supplies the initial page protection-mask.
  988. Return Value:
  989. Status of the map view operation.
  990. Environment:
  991. Kernel Mode, address creation mutex held.
  992. --*/
  993. {
  994. PMMVAD_LONG Vad;
  995. CSHORT IoMapping;
  996. PVOID StartingAddress;
  997. PVOID EndingAddress;
  998. PVOID HighestUserAddress;
  999. PMMPTE PointerPde;
  1000. PMMPTE PointerPte;
  1001. PMMPTE LastPte;
  1002. MMPTE TempPte;
  1003. PMMPFN Pfn2;
  1004. SIZE_T PhysicalViewSize;
  1005. ULONG_PTR Alignment;
  1006. PVOID UsedPageTableHandle;
  1007. PMI_PHYSICAL_VIEW PhysicalView;
  1008. NTSTATUS Status;
  1009. PFN_NUMBER PageFrameIndex;
  1010. PFN_NUMBER StartingPageFrameIndex;
  1011. PFN_NUMBER NumberOfPages;
  1012. MEMORY_CACHING_TYPE CacheType;
  1013. MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
  1014. PMM_AVL_TABLE PhysicalVadRoot;
  1015. //
  1016. // Physical memory section.
  1017. //
  1018. if (AllocationType & MEM_RESERVE) {
  1019. return STATUS_INVALID_PARAMETER_9;
  1020. }
  1021. Alignment = X64K;
  1022. if (*CapturedBase == NULL) {
  1023. //
  1024. // Attempt to locate address space starting on a 64k boundary.
  1025. //
  1026. #if !defined (_MI_MORE_THAN_4GB_)
  1027. ASSERT (SectionOffset->HighPart == 0);
  1028. #endif
  1029. PhysicalViewSize = *CapturedViewSize +
  1030. (SectionOffset->LowPart & (X64K - 1));
  1031. //
  1032. // Check whether the registry indicates that all applications
  1033. // should be given virtual address ranges from the highest
  1034. // address downwards in order to test 3GB-aware apps on 32-bit
  1035. // machines and 64-bit apps on NT64.
  1036. //
  1037. if ((AllocationType & MEM_TOP_DOWN) || (Process->VmTopDown == 1)) {
  1038. if (ZeroBits != 0) {
  1039. HighestUserAddress = (PVOID)((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits);
  1040. if (HighestUserAddress > MM_HIGHEST_VAD_ADDRESS) {
  1041. HighestUserAddress = MM_HIGHEST_VAD_ADDRESS;
  1042. }
  1043. }
  1044. else {
  1045. HighestUserAddress = MM_HIGHEST_VAD_ADDRESS;
  1046. }
  1047. Status = MiFindEmptyAddressRangeDown (&Process->VadRoot,
  1048. PhysicalViewSize,
  1049. HighestUserAddress,
  1050. Alignment,
  1051. &StartingAddress);
  1052. }
  1053. else {
  1054. Status = MiFindEmptyAddressRange (PhysicalViewSize,
  1055. Alignment,
  1056. (ULONG)ZeroBits,
  1057. &StartingAddress);
  1058. }
  1059. if (!NT_SUCCESS (Status)) {
  1060. return Status;
  1061. }
  1062. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  1063. PhysicalViewSize - 1L) | (PAGE_SIZE - 1L));
  1064. StartingAddress = (PVOID)((ULONG_PTR)StartingAddress +
  1065. (SectionOffset->LowPart & (X64K - 1)));
  1066. if (ZeroBits > 0) {
  1067. if (EndingAddress > (PVOID)((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits)) {
  1068. return STATUS_NO_MEMORY;
  1069. }
  1070. }
  1071. }
  1072. else {
  1073. //
  1074. // Check to make sure the specified base address to ending address
  1075. // is currently unused.
  1076. //
  1077. StartingAddress = (PVOID)((ULONG_PTR)MI_64K_ALIGN(*CapturedBase) +
  1078. (SectionOffset->LowPart & (X64K - 1)));
  1079. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  1080. *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
  1081. if (MiCheckForConflictingVadExistence (Process, StartingAddress, EndingAddress) == TRUE) {
  1082. return STATUS_CONFLICTING_ADDRESSES;
  1083. }
  1084. }
  1085. //
  1086. // If a noncachable mapping is requested, none of the physical pages in the
  1087. // range can reside in a large page. Otherwise we would be creating an
  1088. // incoherent overlapping TB entry as the same physical
  1089. // page would be mapped by 2 different TB entries with different
  1090. // cache attributes.
  1091. //
  1092. StartingPageFrameIndex = (PFN_NUMBER) (SectionOffset->QuadPart >> PAGE_SHIFT);
  1093. CacheType = MmCached;
  1094. if (WriteCombined == TRUE) {
  1095. CacheType = MmWriteCombined;
  1096. }
  1097. else if (ProtectionMask & MM_NOCACHE) {
  1098. CacheType = MmNonCached;
  1099. }
  1100. IoMapping = 1;
  1101. if (MI_IS_PFN (StartingPageFrameIndex)) {
  1102. IoMapping = 0;
  1103. }
  1104. CacheAttribute = MI_TRANSLATE_CACHETYPE (CacheType, IoMapping);
  1105. NumberOfPages = MiGetPteAddress (EndingAddress) - MiGetPteAddress (StartingAddress) + 1;
  1106. if (CacheAttribute != MiCached) {
  1107. PageFrameIndex = StartingPageFrameIndex;
  1108. while (PageFrameIndex < StartingPageFrameIndex + NumberOfPages) {
  1109. if (MI_PAGE_FRAME_INDEX_MUST_BE_CACHED (PageFrameIndex)) {
  1110. MiNonCachedCollisions += 1;
  1111. return STATUS_CONFLICTING_ADDRESSES;
  1112. }
  1113. PageFrameIndex += 1;
  1114. }
  1115. }
  1116. //
  1117. // An unoccupied address range has been found, build the virtual
  1118. // address descriptor to describe this range.
  1119. //
  1120. PhysicalVadRoot = Process->PhysicalVadRoot;
  1121. //
  1122. // The address space mutex synchronizes the allocation of the
  1123. // EPROCESS PhysicalVadRoot. This table root is not deleted until
  1124. // the process exits.
  1125. //
  1126. if (Process->PhysicalVadRoot == NULL) {
  1127. PhysicalVadRoot = (PMM_AVL_TABLE) ExAllocatePoolWithTag (
  1128. NonPagedPool,
  1129. sizeof (MM_AVL_TABLE),
  1130. MI_PHYSICAL_VIEW_ROOT_KEY);
  1131. if (PhysicalVadRoot == NULL) {
  1132. return STATUS_INSUFFICIENT_RESOURCES;
  1133. }
  1134. RtlZeroMemory (PhysicalVadRoot, sizeof (MM_AVL_TABLE));
  1135. ASSERT (PhysicalVadRoot->NumberGenericTableElements == 0);
  1136. PhysicalVadRoot->BalancedRoot.u1.Parent = &PhysicalVadRoot->BalancedRoot;
  1137. MiInsertPhysicalVadRoot (Process, PhysicalVadRoot);
  1138. }
  1139. //
  1140. // Attempt to allocate the pool and charge quota during the Vad insertion.
  1141. //
  1142. PhysicalView = (PMI_PHYSICAL_VIEW)ExAllocatePoolWithTag (NonPagedPool,
  1143. sizeof(MI_PHYSICAL_VIEW),
  1144. MI_PHYSICAL_VIEW_KEY);
  1145. if (PhysicalView == NULL) {
  1146. return STATUS_INSUFFICIENT_RESOURCES;
  1147. }
  1148. Vad = (PMMVAD_LONG)ExAllocatePoolWithTag (NonPagedPool,
  1149. sizeof(MMVAD_LONG),
  1150. 'ldaV');
  1151. if (Vad == NULL) {
  1152. ExFreePool (PhysicalView);
  1153. return STATUS_INSUFFICIENT_RESOURCES;
  1154. }
  1155. RtlZeroMemory (Vad, sizeof(MMVAD_LONG));
  1156. Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress);
  1157. Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress);
  1158. Vad->ControlArea = ControlArea;
  1159. Vad->u2.VadFlags2.Inherit = MM_VIEW_UNMAP;
  1160. Vad->u2.VadFlags2.LongVad = 1;
  1161. Vad->u.VadFlags.PhysicalMapping = 1;
  1162. Vad->u.VadFlags.Protection = ProtectionMask;
  1163. PhysicalView->Vad = (PMMVAD) Vad;
  1164. PhysicalView->StartingVpn = Vad->StartingVpn;
  1165. PhysicalView->EndingVpn = Vad->EndingVpn;
  1166. PhysicalView->u.LongFlags = MI_PHYSICAL_VIEW_PHYS;
  1167. //
  1168. // Set the last contiguous PTE field in the Vad to the page frame
  1169. // number of the starting physical page.
  1170. //
  1171. Vad->LastContiguousPte = (PMMPTE) StartingPageFrameIndex;
  1172. Vad->FirstPrototypePte = (PMMPTE) StartingPageFrameIndex;
  1173. ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte);
  1174. //
  1175. // Initialize the PTE templates as the working set mutex is not needed to
  1176. // synchronize this (so avoid adding extra contention).
  1177. //
  1178. PointerPde = MiGetPdeAddress (StartingAddress);
  1179. PointerPte = MiGetPteAddress (StartingAddress);
  1180. LastPte = MiGetPteAddress (EndingAddress);
  1181. MI_MAKE_VALID_PTE (TempPte,
  1182. StartingPageFrameIndex,
  1183. ProtectionMask,
  1184. PointerPte);
  1185. if (TempPte.u.Hard.Write) {
  1186. MI_SET_PTE_DIRTY (TempPte);
  1187. }
  1188. if (CacheAttribute == MiWriteCombined) {
  1189. MI_SET_PTE_WRITE_COMBINE (TempPte);
  1190. }
  1191. else if (CacheAttribute == MiNonCached) {
  1192. MI_DISABLE_CACHING (TempPte);
  1193. }
  1194. MI_ADD_EXECUTE_TO_VALID_PTE_IF_PAE (TempPte);
  1195. //
  1196. // Ensure no page frame cache attributes conflict.
  1197. //
  1198. if (MiCheckCacheAttributes (StartingPageFrameIndex, NumberOfPages, CacheAttribute) == FALSE) {
  1199. Status = STATUS_CONFLICTING_ADDRESSES;
  1200. goto Failure1;
  1201. }
  1202. //
  1203. // Insert the VAD. This could fail due to quota charges.
  1204. //
  1205. LOCK_WS_UNSAFE (Process);
  1206. Status = MiInsertVad ((PMMVAD) Vad);
  1207. if (!NT_SUCCESS(Status)) {
  1208. UNLOCK_WS_UNSAFE (Process);
  1209. Failure1:
  1210. ExFreePool (PhysicalView);
  1211. //
  1212. // The pool allocation succeeded, but the quota charge
  1213. // in InsertVad failed, deallocate the pool and return
  1214. // an error.
  1215. //
  1216. ExFreePool (Vad);
  1217. return Status;
  1218. }
  1219. //
  1220. // Build the PTEs in the address space.
  1221. //
  1222. MI_PREPARE_FOR_NONCACHED (CacheAttribute);
  1223. MiMakePdeExistAndMakeValid (PointerPde, Process, MM_NOIRQL);
  1224. Pfn2 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber);
  1225. UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (StartingAddress);
  1226. while (PointerPte <= LastPte) {
  1227. if (MiIsPteOnPdeBoundary (PointerPte)) {
  1228. PointerPde = MiGetPteAddress (PointerPte);
  1229. MiMakePdeExistAndMakeValid (PointerPde, Process, MM_NOIRQL);
  1230. Pfn2 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber);
  1231. UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte));
  1232. }
  1233. //
  1234. // Increment the count of non-zero page table entries for this
  1235. // page table and the number of private pages for the process.
  1236. //
  1237. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle);
  1238. ASSERT (PointerPte->u.Long == 0);
  1239. MI_WRITE_VALID_PTE (PointerPte, TempPte);
  1240. Pfn2->u2.ShareCount += 1;
  1241. PointerPte += 1;
  1242. TempPte.u.Hard.PageFrameNumber += 1;
  1243. }
  1244. MI_SWEEP_CACHE (CacheAttribute,
  1245. StartingAddress,
  1246. (PCHAR) EndingAddress - (PCHAR) StartingAddress);
  1247. //
  1248. // Increment the count of the number of views for the
  1249. // section object. This requires the PFN lock to be held.
  1250. // At the same time, insert the physical view descriptor now that
  1251. // the page table page hierarchy is in place. Note probes can find
  1252. // this descriptor immediately.
  1253. //
  1254. MiInsertPhysicalViewAndRefControlArea (Process, ControlArea, PhysicalView);
  1255. UNLOCK_WS_UNSAFE (Process);
  1256. //
  1257. // Update the current virtual size in the process header.
  1258. //
  1259. *CapturedViewSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
  1260. Process->VirtualSize += *CapturedViewSize;
  1261. if (Process->VirtualSize > Process->PeakVirtualSize) {
  1262. Process->PeakVirtualSize = Process->VirtualSize;
  1263. }
  1264. *CapturedBase = StartingAddress;
  1265. return STATUS_SUCCESS;
  1266. }
  1267. VOID
  1268. MiSetControlAreaSymbolsLoaded (
  1269. IN PCONTROL_AREA ControlArea
  1270. )
  1271. /*++
  1272. Routine Description:
  1273. This is a nonpaged helper routine to mark the specified control area as
  1274. having its debug symbols loaded.
  1275. Arguments:
  1276. ControlArea - Supplies a pointer to the control area.
  1277. Return Value:
  1278. None.
  1279. --*/
  1280. {
  1281. KIRQL OldIrql;
  1282. LOCK_PFN (OldIrql);
  1283. ControlArea->u.Flags.DebugSymbolsLoaded = 1;
  1284. UNLOCK_PFN (OldIrql);
  1285. }
  1286. VOID
  1287. MiLoadUserSymbols (
  1288. IN PCONTROL_AREA ControlArea,
  1289. IN PVOID StartingAddress,
  1290. IN PEPROCESS Process
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. This routine loads symbols for user space executables and DLLs.
  1295. Arguments:
  1296. ControlArea - Supplies the control area for the section.
  1297. StartingAddress - Supplies the virtual address the section is mapped at.
  1298. Process - Supplies the process pointer which is receiving the section.
  1299. Return Value:
  1300. None.
  1301. Environment:
  1302. Kernel Mode, address creation mutex held.
  1303. --*/
  1304. {
  1305. PLIST_ENTRY Head;
  1306. PLIST_ENTRY Next;
  1307. PKLDR_DATA_TABLE_ENTRY Entry;
  1308. PIMAGE_NT_HEADERS NtHeaders;
  1309. PUNICODE_STRING FileName;
  1310. ANSI_STRING AnsiName;
  1311. NTSTATUS Status;
  1312. PKTHREAD CurrentThread;
  1313. //
  1314. // TEMP TEMP TEMP rip out ANSI conversion when debugger converted.
  1315. //
  1316. FileName = (PUNICODE_STRING)&ControlArea->FilePointer->FileName;
  1317. if (FileName->Length == 0) {
  1318. return;
  1319. }
  1320. CurrentThread = KeGetCurrentThread ();
  1321. KeEnterCriticalRegionThread (CurrentThread);
  1322. ExAcquireResourceExclusiveLite (&PsLoadedModuleResource, TRUE);
  1323. Head = &MmLoadedUserImageList;
  1324. Next = Head->Flink;
  1325. while (Next != Head) {
  1326. Entry = CONTAINING_RECORD (Next,
  1327. KLDR_DATA_TABLE_ENTRY,
  1328. InLoadOrderLinks);
  1329. if (Entry->DllBase == StartingAddress) {
  1330. Entry->LoadCount += 1;
  1331. break;
  1332. }
  1333. Next = Next->Flink;
  1334. }
  1335. if (Next == Head) {
  1336. Entry = ExAllocatePoolWithTag (NonPagedPool,
  1337. sizeof( *Entry ) +
  1338. FileName->Length +
  1339. sizeof( UNICODE_NULL ),
  1340. MMDB);
  1341. if (Entry != NULL) {
  1342. RtlZeroMemory (Entry, sizeof(*Entry));
  1343. try {
  1344. NtHeaders = RtlImageNtHeader (StartingAddress);
  1345. if (NtHeaders != NULL) {
  1346. #if defined(_WIN64)
  1347. if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  1348. Entry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
  1349. Entry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
  1350. }
  1351. else {
  1352. PIMAGE_NT_HEADERS32 NtHeaders32 = (PIMAGE_NT_HEADERS32)NtHeaders;
  1353. Entry->SizeOfImage = NtHeaders32->OptionalHeader.SizeOfImage;
  1354. Entry->CheckSum = NtHeaders32->OptionalHeader.CheckSum;
  1355. }
  1356. #else
  1357. Entry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
  1358. Entry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
  1359. #endif
  1360. }
  1361. } except (EXCEPTION_EXECUTE_HANDLER) {
  1362. NOTHING;
  1363. }
  1364. Entry->DllBase = StartingAddress;
  1365. Entry->FullDllName.Buffer = (PWSTR)(Entry+1);
  1366. Entry->FullDllName.Length = FileName->Length;
  1367. Entry->FullDllName.MaximumLength = (USHORT)
  1368. (Entry->FullDllName.Length + sizeof( UNICODE_NULL ));
  1369. RtlCopyMemory (Entry->FullDllName.Buffer,
  1370. FileName->Buffer,
  1371. FileName->Length);
  1372. Entry->FullDllName.Buffer[ Entry->FullDllName.Length / sizeof( WCHAR )] = UNICODE_NULL;
  1373. Entry->LoadCount = 1;
  1374. InsertTailList (&MmLoadedUserImageList,
  1375. &Entry->InLoadOrderLinks);
  1376. }
  1377. }
  1378. ExReleaseResourceLite (&PsLoadedModuleResource);
  1379. KeLeaveCriticalRegionThread (CurrentThread);
  1380. Status = RtlUnicodeStringToAnsiString (&AnsiName,
  1381. FileName,
  1382. TRUE);
  1383. if (NT_SUCCESS( Status)) {
  1384. DbgLoadImageSymbols (&AnsiName,
  1385. StartingAddress,
  1386. (ULONG_PTR)Process);
  1387. RtlFreeAnsiString (&AnsiName);
  1388. }
  1389. return;
  1390. }
  1391. VOID
  1392. MiDereferenceControlArea (
  1393. IN PCONTROL_AREA ControlArea
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. This is a nonpaged helper routine to dereference the specified control area.
  1398. Arguments:
  1399. ControlArea - Supplies a pointer to the control area.
  1400. Return Value:
  1401. None.
  1402. --*/
  1403. {
  1404. KIRQL OldIrql;
  1405. LOCK_PFN (OldIrql);
  1406. ControlArea->NumberOfMappedViews -= 1;
  1407. ControlArea->NumberOfUserReferences -= 1;
  1408. //
  1409. // Check to see if the control area (segment) should be deleted.
  1410. // This routine releases the PFN lock.
  1411. //
  1412. MiCheckControlArea (ControlArea, NULL, OldIrql);
  1413. }
  1414. NTSTATUS
  1415. MiMapViewOfImageSection (
  1416. IN PCONTROL_AREA ControlArea,
  1417. IN PEPROCESS Process,
  1418. IN PVOID *CapturedBase,
  1419. IN PLARGE_INTEGER SectionOffset,
  1420. IN PSIZE_T CapturedViewSize,
  1421. IN PSECTION Section,
  1422. IN SECTION_INHERIT InheritDisposition,
  1423. IN ULONG_PTR ZeroBits,
  1424. IN SIZE_T ImageCommitment
  1425. )
  1426. /*++
  1427. Routine Description:
  1428. This routine maps the specified Image section into the
  1429. specified process's address space.
  1430. Arguments:
  1431. see MmMapViewOfSection above...
  1432. ControlArea - Supplies the control area for the section.
  1433. Process - Supplies the process pointer which is receiving the section.
  1434. Return Value:
  1435. Status of the map view operation.
  1436. Environment:
  1437. Kernel Mode, address creation mutex held.
  1438. --*/
  1439. {
  1440. PMMVAD Vad;
  1441. PMMVAD PreviousVad;
  1442. PMMVAD NextVad;
  1443. PVOID StartingAddress;
  1444. PVOID OutputStartingAddress;
  1445. PVOID EndingAddress;
  1446. PVOID HighestUserAddress;
  1447. LOGICAL Attached;
  1448. PSUBSECTION Subsection;
  1449. ULONG PteOffset;
  1450. NTSTATUS Status;
  1451. NTSTATUS ReturnedStatus;
  1452. PMMPTE ProtoPte;
  1453. PVOID BasedAddress;
  1454. SIZE_T NeededViewSize;
  1455. SIZE_T OutputViewSize;
  1456. Attached = FALSE;
  1457. //
  1458. // Image file.
  1459. //
  1460. // Locate the first subsection (text) and create a virtual
  1461. // address descriptor to map the entire image here.
  1462. //
  1463. if ((ControlArea->u.Flags.GlobalOnlyPerSession == 0) &&
  1464. (ControlArea->u.Flags.Rom == 0)) {
  1465. Subsection = (PSUBSECTION)(ControlArea + 1);
  1466. }
  1467. else {
  1468. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  1469. }
  1470. //
  1471. // Check to see if a purge operation is in progress and if so, wait
  1472. // for the purge to complete. In addition, up the count of mapped
  1473. // views for this control area.
  1474. //
  1475. Status = MiCheckPurgeAndUpMapCount (ControlArea, TRUE);
  1476. if (!NT_SUCCESS (Status)) {
  1477. return Status;
  1478. }
  1479. //
  1480. // Capture the based address to the stack, to prevent page faults.
  1481. //
  1482. BasedAddress = ControlArea->Segment->BasedAddress;
  1483. if (*CapturedViewSize == 0) {
  1484. *CapturedViewSize =
  1485. (ULONG_PTR)(Section->SizeOfSection.QuadPart - SectionOffset->QuadPart);
  1486. }
  1487. ReturnedStatus = STATUS_SUCCESS;
  1488. //
  1489. // Determine if a specific base was specified.
  1490. //
  1491. if (*CapturedBase != NULL) {
  1492. //
  1493. // Captured base is not NULL.
  1494. //
  1495. // Check to make sure the specified address range is currently unused
  1496. // and within the user address space.
  1497. //
  1498. StartingAddress = MI_64K_ALIGN(*CapturedBase);
  1499. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  1500. *CapturedViewSize - 1) | (PAGE_SIZE - 1));
  1501. if ((StartingAddress <= MM_HIGHEST_VAD_ADDRESS) &&
  1502. (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) -
  1503. (ULONG_PTR)StartingAddress >= *CapturedViewSize) &&
  1504. (EndingAddress <= MM_HIGHEST_VAD_ADDRESS)) {
  1505. if (MiCheckForConflictingVadExistence (Process, StartingAddress, EndingAddress) == TRUE) {
  1506. MiDereferenceControlArea (ControlArea);
  1507. return STATUS_CONFLICTING_ADDRESSES;
  1508. }
  1509. }
  1510. else {
  1511. MiDereferenceControlArea (ControlArea);
  1512. return STATUS_CONFLICTING_ADDRESSES;
  1513. }
  1514. //
  1515. // A conflicting VAD was not found and the specified address range is
  1516. // within the user address space. If the image will not reside at its
  1517. // base address, then set a special return status.
  1518. //
  1519. if (((ULONG_PTR)StartingAddress +
  1520. (ULONG_PTR)MI_64K_ALIGN(SectionOffset->LowPart)) != (ULONG_PTR)BasedAddress) {
  1521. ReturnedStatus = STATUS_IMAGE_NOT_AT_BASE;
  1522. }
  1523. }
  1524. else {
  1525. //
  1526. // Captured base is NULL.
  1527. //
  1528. // If the captured view size is greater than the largest size that
  1529. // can fit in the user address space, then it is not possible to map
  1530. // the image.
  1531. //
  1532. if ((PVOID)*CapturedViewSize > MM_HIGHEST_VAD_ADDRESS) {
  1533. MiDereferenceControlArea (ControlArea);
  1534. return STATUS_NO_MEMORY;
  1535. }
  1536. //
  1537. // Check to make sure the specified address range is currently unused
  1538. // and within the user address space.
  1539. //
  1540. StartingAddress = (PVOID)((ULONG_PTR)BasedAddress +
  1541. (ULONG_PTR)MI_64K_ALIGN(SectionOffset->LowPart));
  1542. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  1543. *CapturedViewSize - 1) | (PAGE_SIZE - 1));
  1544. Vad = (PMMVAD) TRUE;
  1545. NeededViewSize = *CapturedViewSize;
  1546. if ((StartingAddress >= MM_LOWEST_USER_ADDRESS) &&
  1547. (StartingAddress <= MM_HIGHEST_VAD_ADDRESS) &&
  1548. (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) -
  1549. (ULONG_PTR)StartingAddress >= *CapturedViewSize) &&
  1550. (EndingAddress <= MM_HIGHEST_VAD_ADDRESS)) {
  1551. Vad = (PMMVAD) (ULONG_PTR) MiCheckForConflictingVadExistence (Process, StartingAddress, EndingAddress);
  1552. }
  1553. //
  1554. // If the VAD address is not NULL, then a conflict was discovered.
  1555. // Attempt to select another address range in which to map the image.
  1556. //
  1557. if (Vad != NULL) {
  1558. //
  1559. // The image could not be mapped at its natural base address
  1560. // try to find another place to map it.
  1561. //
  1562. // If the system has been biased to an alternate base address to
  1563. // allow 3gb of user address space, then make sure the high order
  1564. // address bit is zero.
  1565. //
  1566. if ((MmVirtualBias != 0) && (ZeroBits == 0)) {
  1567. ZeroBits = 1;
  1568. }
  1569. ReturnedStatus = STATUS_IMAGE_NOT_AT_BASE;
  1570. //
  1571. // Find a starting address on a 64k boundary.
  1572. //
  1573. // Check whether the registry indicates that all applications
  1574. // should be given virtual address ranges from the highest
  1575. // address downwards in order to test 3GB-aware apps on 32-bit
  1576. // machines and 64-bit apps on NT64.
  1577. //
  1578. if (Process->VmTopDown == 1) {
  1579. if (ZeroBits != 0) {
  1580. HighestUserAddress = (PVOID)((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits);
  1581. if (HighestUserAddress > MM_HIGHEST_VAD_ADDRESS) {
  1582. HighestUserAddress = MM_HIGHEST_VAD_ADDRESS;
  1583. }
  1584. }
  1585. else {
  1586. HighestUserAddress = MM_HIGHEST_VAD_ADDRESS;
  1587. }
  1588. Status = MiFindEmptyAddressRangeDown (&Process->VadRoot,
  1589. NeededViewSize,
  1590. HighestUserAddress,
  1591. X64K,
  1592. &StartingAddress);
  1593. }
  1594. else {
  1595. Status = MiFindEmptyAddressRange (NeededViewSize,
  1596. X64K,
  1597. (ULONG)ZeroBits,
  1598. &StartingAddress);
  1599. }
  1600. if (!NT_SUCCESS (Status)) {
  1601. MiDereferenceControlArea (ControlArea);
  1602. return Status;
  1603. }
  1604. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  1605. *CapturedViewSize - 1) | (PAGE_SIZE - 1));
  1606. }
  1607. }
  1608. //
  1609. // Allocate and initialize a VAD for the specified address range.
  1610. //
  1611. Vad = ExAllocatePoolWithTag (NonPagedPool, sizeof(MMVAD), MMVADKEY);
  1612. if (Vad == NULL) {
  1613. MiDereferenceControlArea (ControlArea);
  1614. return STATUS_INSUFFICIENT_RESOURCES;
  1615. }
  1616. RtlZeroMemory (Vad, sizeof(MMVAD));
  1617. Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress);
  1618. Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress);
  1619. Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
  1620. Vad->u.VadFlags.ImageMap = 1;
  1621. //
  1622. // Set the protection in the VAD as EXECUTE_WRITE_COPY.
  1623. //
  1624. Vad->u.VadFlags.Protection = MM_EXECUTE_WRITECOPY;
  1625. Vad->ControlArea = ControlArea;
  1626. //
  1627. // Set the first prototype PTE field in the Vad.
  1628. //
  1629. SectionOffset->LowPart = SectionOffset->LowPart & ~(X64K - 1);
  1630. PteOffset = (ULONG)(SectionOffset->QuadPart >> PAGE_SHIFT);
  1631. Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
  1632. Vad->LastContiguousPte = MM_ALLOCATION_FILLS_VAD;
  1633. //
  1634. // NOTE: the full commitment is charged even if a partial map of an
  1635. // image is being done. This saves from having to run through the
  1636. // entire image (via prototype PTEs) and calculate the charge on
  1637. // a per page basis for the partial map.
  1638. //
  1639. Vad->u.VadFlags.CommitCharge = (SIZE_T)ImageCommitment; // ****** temp
  1640. ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte);
  1641. LOCK_WS_UNSAFE (Process);
  1642. Status = MiInsertVad (Vad);
  1643. UNLOCK_WS_UNSAFE (Process);
  1644. if (!NT_SUCCESS(Status)) {
  1645. MiDereferenceControlArea (ControlArea);
  1646. //
  1647. // The quota charge in InsertVad failed,
  1648. // deallocate the pool and return an error.
  1649. //
  1650. ExFreePool (Vad);
  1651. return Status;
  1652. }
  1653. OutputStartingAddress = StartingAddress;
  1654. OutputViewSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
  1655. #if DBG
  1656. if (MmDebug & MM_DBG_WALK_VAD_TREE) {
  1657. DbgPrint("mapped image section vads\n");
  1658. VadTreeWalk ();
  1659. }
  1660. #endif
  1661. //
  1662. // Update the current virtual size in the process header.
  1663. //
  1664. Process->VirtualSize += OutputViewSize;
  1665. if (Process->VirtualSize > Process->PeakVirtualSize) {
  1666. Process->PeakVirtualSize = Process->VirtualSize;
  1667. }
  1668. #if defined(_MIALT4K_)
  1669. //
  1670. // Clear the alternate PTE bitmap so that future faults in this image range
  1671. // will result in MiSyncAltPte being called. This prevents stale ALTPTEs
  1672. // (filled if the user app previously referenced bogus addresses not in
  1673. // any VAD from inside a try-except) from causing AVs on what will be
  1674. // a now-legitimate image address.
  1675. //
  1676. if (Process->Wow64Process != NULL) {
  1677. MiDeleteFor4kPage (StartingAddress, EndingAddress, Process);
  1678. }
  1679. #endif
  1680. if (ControlArea->u.Flags.FloppyMedia) {
  1681. //
  1682. // The image resides on a floppy disk, in-page all
  1683. // pages from the floppy and mark them as modified so
  1684. // they migrate to the paging file rather than reread
  1685. // them from the floppy disk which may have been removed.
  1686. //
  1687. ProtoPte = Vad->FirstPrototypePte;
  1688. //
  1689. // This could get an in-page error from the floppy.
  1690. //
  1691. while (StartingAddress < EndingAddress) {
  1692. //
  1693. // If the prototype PTE is valid, transition or
  1694. // in prototype PTE format, bring the page into
  1695. // memory and set the modified bit.
  1696. //
  1697. if ((ProtoPte->u.Hard.Valid == 1) ||
  1698. (((ProtoPte->u.Soft.Prototype == 1) ||
  1699. (ProtoPte->u.Soft.Transition == 1)) &&
  1700. (ProtoPte->u.Soft.Protection != MM_NOACCESS))
  1701. ) {
  1702. Status = MiSetPageModified (Vad, StartingAddress);
  1703. if (!NT_SUCCESS (Status)) {
  1704. //
  1705. // An in page error must have occurred touching the image,
  1706. // Ignore the error and continue to the next page - unless
  1707. // it's being run over a network. If it's being run over
  1708. // a net and the control area is marked as floppy, then
  1709. // the image must be marked NET_RUN_FROM_SWAP, so any
  1710. // inpage error must be treated as terminal now - so the app
  1711. // doesn't later spontaneously abort when referencing
  1712. // this page. This provides app writers with a way to
  1713. // mark their app in a way which is robust regardless of
  1714. // network conditions.
  1715. //
  1716. if (ControlArea->u.Flags.Networked) {
  1717. //
  1718. // N.B. There are no race conditions with the user
  1719. // deleting/substituting this mapping from another
  1720. // thread as the address space mutex is still held.
  1721. //
  1722. Process->VirtualSize -= OutputViewSize;
  1723. PreviousVad = MiGetPreviousVad (Vad);
  1724. NextVad = MiGetNextVad (Vad);
  1725. StartingAddress = MI_VPN_TO_VA (Vad->StartingVpn);
  1726. EndingAddress = MI_VPN_TO_VA_ENDING (Vad->EndingVpn);
  1727. LOCK_WS_UNSAFE (Process);
  1728. MiRemoveVad (Vad);
  1729. //
  1730. // Return commitment for page table pages.
  1731. //
  1732. MiReturnPageTablePageCommitment (StartingAddress,
  1733. EndingAddress,
  1734. Process,
  1735. PreviousVad,
  1736. NextVad);
  1737. MiRemoveMappedView (Process, Vad);
  1738. UNLOCK_WS_UNSAFE (Process);
  1739. ExFreePool (Vad);
  1740. return Status;
  1741. }
  1742. }
  1743. }
  1744. ProtoPte += 1;
  1745. StartingAddress = (PVOID)((PCHAR)StartingAddress + PAGE_SIZE);
  1746. }
  1747. }
  1748. *CapturedViewSize = OutputViewSize;
  1749. *CapturedBase = OutputStartingAddress;
  1750. ASSERT (NT_SUCCESS (ReturnedStatus));
  1751. //
  1752. // Check to see if this image is for the architecture of the current
  1753. // machine.
  1754. //
  1755. if (ControlArea->Segment->u2.ImageInformation->ImageContainsCode &&
  1756. ((ControlArea->Segment->u2.ImageInformation->Machine <
  1757. USER_SHARED_DATA->ImageNumberLow) ||
  1758. (ControlArea->Segment->u2.ImageInformation->Machine >
  1759. USER_SHARED_DATA->ImageNumberHigh)
  1760. )
  1761. ) {
  1762. #if defined (_WIN64)
  1763. //
  1764. // If this is a wow64 process then allow i386 images.
  1765. //
  1766. if (!Process->Wow64Process ||
  1767. ControlArea->Segment->u2.ImageInformation->Machine != IMAGE_FILE_MACHINE_I386) {
  1768. return STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
  1769. }
  1770. #else //!_WIN64
  1771. return STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
  1772. #endif
  1773. }
  1774. StartingAddress = MI_VPN_TO_VA (Vad->StartingVpn);
  1775. if (PsImageNotifyEnabled) {
  1776. IMAGE_INFO ImageInfo;
  1777. if ((StartingAddress < MmHighestUserAddress) &&
  1778. (Process->UniqueProcessId) &&
  1779. (Process != PsInitialSystemProcess)) {
  1780. ImageInfo.Properties = 0;
  1781. ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
  1782. ImageInfo.ImageBase = StartingAddress;
  1783. ImageInfo.ImageSize = OutputViewSize;
  1784. ImageInfo.ImageSelector = 0;
  1785. ImageInfo.ImageSectionNumber = 0;
  1786. PsCallImageNotifyRoutines (&ControlArea->FilePointer->FileName,
  1787. Process->UniqueProcessId,
  1788. &ImageInfo);
  1789. }
  1790. }
  1791. ASSERT (ControlArea->u.Flags.Image);
  1792. if ((NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD) &&
  1793. (ReturnedStatus != STATUS_IMAGE_NOT_AT_BASE) &&
  1794. (ControlArea->u.Flags.DebugSymbolsLoaded == 0)) {
  1795. if (MiCacheImageSymbols (StartingAddress)) {
  1796. MiSetControlAreaSymbolsLoaded (ControlArea);
  1797. MiLoadUserSymbols (ControlArea, StartingAddress, Process);
  1798. }
  1799. }
  1800. #if defined(_MIALT4K_)
  1801. if (Process->Wow64Process != NULL) {
  1802. MiProtectImageFileFor4kPage (StartingAddress, OutputViewSize);
  1803. }
  1804. #endif
  1805. return ReturnedStatus;
  1806. }
  1807. NTSTATUS
  1808. MiAddViewsForSectionWithPfn (
  1809. IN PMSUBSECTION StartMappedSubsection,
  1810. IN UINT64 LastPteOffset OPTIONAL
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. This nonpagable wrapper routine maps the views into the specified section.
  1815. Arguments:
  1816. StartMappedSubsection - Supplies the mapped subsection to start at.
  1817. LastPteOffset - Supplies the last PTE offset to end the views at.
  1818. Supplies zero if views are desired from the supplied
  1819. subsection to the end of the file.
  1820. Return Value:
  1821. NTSTATUS.
  1822. Environment:
  1823. Kernel Mode, address creation mutex optionally held if called in process
  1824. context. APC_LEVEL or below.
  1825. --*/
  1826. {
  1827. KIRQL OldIrql;
  1828. NTSTATUS Status;
  1829. ULONG Waited;
  1830. ASSERT (KeGetCurrentIrql () <= APC_LEVEL);
  1831. LOCK_PFN (OldIrql);
  1832. //
  1833. // This routine returns with the PFN lock released !
  1834. //
  1835. Status = MiAddViewsForSection (StartMappedSubsection,
  1836. LastPteOffset,
  1837. OldIrql,
  1838. &Waited);
  1839. ASSERT (KeGetCurrentIrql () <= APC_LEVEL);
  1840. return Status;
  1841. }
  1842. LOGICAL
  1843. MiReferenceSubsection (
  1844. IN PMSUBSECTION MappedSubsection
  1845. )
  1846. /*++
  1847. Routine Description:
  1848. This nonpagable routine reference counts the specified subsection if
  1849. its prototype PTEs are already setup, otherwise it returns FALSE.
  1850. Arguments:
  1851. MappedSubsection - Supplies the mapped subsection to start at.
  1852. Return Value:
  1853. NTSTATUS.
  1854. Environment:
  1855. Kernel Mode, PFN lock held.
  1856. --*/
  1857. {
  1858. ASSERT ((MappedSubsection->ControlArea->u.Flags.Image == 0) &&
  1859. (MappedSubsection->ControlArea->FilePointer != NULL) &&
  1860. (MappedSubsection->ControlArea->u.Flags.PhysicalMemory == 0));
  1861. MM_PFN_LOCK_ASSERT();
  1862. //
  1863. // Note the control area is not necessarily active at this point.
  1864. //
  1865. if (MappedSubsection->SubsectionBase == NULL) {
  1866. //
  1867. // No prototype PTEs exist, caller will have to go the long way.
  1868. //
  1869. return FALSE;
  1870. }
  1871. //
  1872. // The mapping base exists so the number of mapped views can be
  1873. // safely incremented. This prevents a trim from starting after
  1874. // we release the lock.
  1875. //
  1876. MappedSubsection->NumberOfMappedViews += 1;
  1877. MI_SNAP_SUB (MappedSubsection, 0x4);
  1878. if (MappedSubsection->DereferenceList.Flink != NULL) {
  1879. //
  1880. // Remove this from the list of unused subsections.
  1881. //
  1882. RemoveEntryList (&MappedSubsection->DereferenceList);
  1883. MI_UNUSED_SUBSECTIONS_COUNT_REMOVE (MappedSubsection);
  1884. MappedSubsection->DereferenceList.Flink = NULL;
  1885. }
  1886. //
  1887. // Set the access bit so an already ongoing trim won't blindly
  1888. // delete the prototype PTEs on completion of a mapped write.
  1889. // This can happen if the current thread dirties some pages and
  1890. // then deletes the view before the trim write finishes - this
  1891. // bit informs the trimming thread that a rescan is needed so
  1892. // that writes are not lost.
  1893. //
  1894. MappedSubsection->u2.SubsectionFlags2.SubsectionAccessed = 1;
  1895. return TRUE;
  1896. }
  1897. NTSTATUS
  1898. MiAddViewsForSection (
  1899. IN PMSUBSECTION StartMappedSubsection,
  1900. IN UINT64 LastPteOffset OPTIONAL,
  1901. IN KIRQL OldIrql,
  1902. OUT PULONG Waited
  1903. )
  1904. /*++
  1905. Routine Description:
  1906. This nonpagable routine maps the views into the specified section.
  1907. N.B. This routine may release and reacquire the PFN lock !
  1908. N.B. This routine always returns with the PFN lock released !
  1909. N.B. Callers may pass in view lengths that exceed the length of
  1910. the section and this must succeed. Thus MiAddViews must check
  1911. for this and know to stop the references at the end. More
  1912. importantly, MiRemoveViews must also contain the same logic.
  1913. Arguments:
  1914. StartMappedSubsection - Supplies the mapped subsection to start at.
  1915. LastPteOffset - Supplies the number of PTEs (beginning at the supplied
  1916. subsection) to provide views for. Supplies zero if
  1917. views are desired from the supplied subsection to the
  1918. end of the file.
  1919. Waited - Supplies a pointer to a ULONG to increment if the PFN lock is
  1920. released and reacquired.
  1921. Return Value:
  1922. NTSTATUS, PFN lock released.
  1923. Environment:
  1924. Kernel Mode, PFN lock held.
  1925. --*/
  1926. {
  1927. MMPTE TempPte;
  1928. ULONG Size;
  1929. PMMPTE ProtoPtes;
  1930. PMSUBSECTION MappedSubsection;
  1931. *Waited = 0;
  1932. MappedSubsection = StartMappedSubsection;
  1933. ASSERT ((MappedSubsection->ControlArea->u.Flags.Image == 0) &&
  1934. (MappedSubsection->ControlArea->FilePointer != NULL) &&
  1935. (MappedSubsection->ControlArea->u.Flags.PhysicalMemory == 0));
  1936. MM_PFN_LOCK_ASSERT();
  1937. do {
  1938. //
  1939. // Note the control area must be active at this point.
  1940. //
  1941. ASSERT (MappedSubsection->ControlArea->DereferenceList.Flink == NULL);
  1942. if (MappedSubsection->SubsectionBase != NULL) {
  1943. //
  1944. // The mapping base exists so the number of mapped views can be
  1945. // safely incremented. This prevents a trim from starting after
  1946. // we release the lock.
  1947. //
  1948. MappedSubsection->NumberOfMappedViews += 1;
  1949. MI_SNAP_SUB (MappedSubsection, 0x5);
  1950. if (MappedSubsection->DereferenceList.Flink != NULL) {
  1951. //
  1952. // Remove this from the list of unused subsections.
  1953. //
  1954. RemoveEntryList (&MappedSubsection->DereferenceList);
  1955. MI_UNUSED_SUBSECTIONS_COUNT_REMOVE (MappedSubsection);
  1956. MappedSubsection->DereferenceList.Flink = NULL;
  1957. }
  1958. //
  1959. // Set the access bit so an already ongoing trim won't blindly
  1960. // delete the prototype PTEs on completion of a mapped write.
  1961. // This can happen if the current thread dirties some pages and
  1962. // then deletes the view before the trim write finishes - this
  1963. // bit informs the trimming thread that a rescan is needed so
  1964. // that writes are not lost.
  1965. //
  1966. MappedSubsection->u2.SubsectionFlags2.SubsectionAccessed = 1;
  1967. }
  1968. else {
  1969. ASSERT (MappedSubsection->u.SubsectionFlags.SubsectionStatic == 0);
  1970. ASSERT (MappedSubsection->NumberOfMappedViews == 0);
  1971. MI_SNAP_SUB (MappedSubsection, 0x6);
  1972. //
  1973. // No prototype PTEs currently exist for this subsection.
  1974. // Allocate and populate them properly now.
  1975. //
  1976. UNLOCK_PFN (OldIrql);
  1977. *Waited = 1;
  1978. Size = (MappedSubsection->PtesInSubsection + MappedSubsection->UnusedPtes) * sizeof(MMPTE);
  1979. ASSERT (Size != 0);
  1980. ProtoPtes = (PMMPTE)ExAllocatePoolWithTag (PagedPool | POOL_MM_ALLOCATION,
  1981. Size,
  1982. MMSECT);
  1983. if (ProtoPtes == NULL) {
  1984. MI_SNAP_SUB (MappedSubsection, 0x7);
  1985. goto Failed;
  1986. }
  1987. //
  1988. // Fill in the prototype PTEs for this subsection.
  1989. //
  1990. TempPte.u.Long = MiGetSubsectionAddressForPte (MappedSubsection);
  1991. TempPte.u.Soft.Prototype = 1;
  1992. //
  1993. // Set all the PTEs to the initial execute-read-write protection.
  1994. // The section will control access to these and the segment
  1995. // must provide a method to allow other users to map the file
  1996. // for various protections.
  1997. //
  1998. TempPte.u.Soft.Protection = MappedSubsection->ControlArea->Segment->SegmentPteTemplate.u.Soft.Protection;
  1999. MiFillMemoryPte (ProtoPtes, Size / sizeof (MMPTE), TempPte.u.Long);
  2000. LOCK_PFN (OldIrql);
  2001. //
  2002. // Now that the mapping base is guaranteed to be nonzero (shortly),
  2003. // the number of mapped views can be safely incremented. This
  2004. // prevents a trim from starting after we release the lock.
  2005. //
  2006. MappedSubsection->NumberOfMappedViews += 1;
  2007. MI_SNAP_SUB (MappedSubsection, 0x8);
  2008. //
  2009. // Set the access bit so an already ongoing trim won't blindly
  2010. // delete the prototype PTEs on completion of a mapped write.
  2011. // This can happen if the current thread dirties some pages and
  2012. // then deletes the view before the trim write finishes - this
  2013. // bit informs the trimming thread that a rescan is needed so
  2014. // that writes are not lost.
  2015. //
  2016. MappedSubsection->u2.SubsectionFlags2.SubsectionAccessed = 1;
  2017. //
  2018. // Check to make sure another thread didn't do this already while
  2019. // the lock was released.
  2020. //
  2021. if (MappedSubsection->SubsectionBase == NULL) {
  2022. ASSERT (MappedSubsection->NumberOfMappedViews == 1);
  2023. MappedSubsection->SubsectionBase = ProtoPtes;
  2024. }
  2025. else {
  2026. if (MappedSubsection->DereferenceList.Flink != NULL) {
  2027. //
  2028. // Remove this from the list of unused subsections.
  2029. //
  2030. ASSERT (MappedSubsection->NumberOfMappedViews == 1);
  2031. RemoveEntryList (&MappedSubsection->DereferenceList);
  2032. MI_UNUSED_SUBSECTIONS_COUNT_REMOVE (MappedSubsection);
  2033. MappedSubsection->DereferenceList.Flink = NULL;
  2034. }
  2035. else {
  2036. ASSERT (MappedSubsection->NumberOfMappedViews > 1);
  2037. }
  2038. //
  2039. // This unlock and release of pool could be postponed until
  2040. // the end of this routine when the lock is released anyway
  2041. // but this should be a rare case anyway so don't bother.
  2042. //
  2043. UNLOCK_PFN (OldIrql);
  2044. ExFreePool (ProtoPtes);
  2045. LOCK_PFN (OldIrql);
  2046. }
  2047. MI_SNAP_SUB (MappedSubsection, 0x9);
  2048. }
  2049. if (LastPteOffset != 0) {
  2050. ASSERT ((LONG)MappedSubsection->PtesInSubsection > 0);
  2051. ASSERT ((UINT64)LastPteOffset > 0);
  2052. if (LastPteOffset <= (UINT64) MappedSubsection->PtesInSubsection) {
  2053. break;
  2054. }
  2055. LastPteOffset -= MappedSubsection->PtesInSubsection;
  2056. }
  2057. MappedSubsection = (PMSUBSECTION) MappedSubsection->NextSubsection;
  2058. } while (MappedSubsection != NULL);
  2059. UNLOCK_PFN (OldIrql);
  2060. return STATUS_SUCCESS;
  2061. Failed:
  2062. LOCK_PFN (OldIrql);
  2063. //
  2064. // A prototype PTE pool allocation failed. Carefully undo any allocations
  2065. // and references done so far.
  2066. //
  2067. while (StartMappedSubsection != MappedSubsection) {
  2068. ASSERT ((LONG_PTR)StartMappedSubsection->NumberOfMappedViews >= 1);
  2069. StartMappedSubsection->NumberOfMappedViews -= 1;
  2070. ASSERT (StartMappedSubsection->u.SubsectionFlags.SubsectionStatic == 0);
  2071. ASSERT (StartMappedSubsection->DereferenceList.Flink == NULL);
  2072. MI_SNAP_SUB (MappedSubsection, 0xA);
  2073. if (StartMappedSubsection->NumberOfMappedViews == 0) {
  2074. //
  2075. // Insert this subsection into the unused subsection list.
  2076. // Since it's not likely there are any resident protos at this
  2077. // point, enqueue each subsection at the front.
  2078. //
  2079. InsertHeadList (&MmUnusedSubsectionList,
  2080. &StartMappedSubsection->DereferenceList);
  2081. MI_UNUSED_SUBSECTIONS_COUNT_INSERT (MappedSubsection);
  2082. }
  2083. StartMappedSubsection = (PMSUBSECTION) StartMappedSubsection->NextSubsection;
  2084. }
  2085. UNLOCK_PFN (OldIrql);
  2086. return STATUS_INSUFFICIENT_RESOURCES;
  2087. }
  2088. VOID
  2089. MiRemoveViewsFromSection (
  2090. IN PMSUBSECTION StartMappedSubsection,
  2091. IN UINT64 LastPteOffset OPTIONAL
  2092. )
  2093. /*++
  2094. Routine Description:
  2095. This nonpagable routine removes the views from the specified section if
  2096. the reference count reaches zero.
  2097. N.B. Callers may pass in view lengths that exceed the length of
  2098. the section and this must succeed. Thus MiAddViews checks
  2099. for this and knows to stop the references at the end. More
  2100. importantly, MiRemoveViews must also contain the same logic.
  2101. Arguments:
  2102. StartMappedSubsection - Supplies the mapped subsection to start at.
  2103. LastPteOffset - Supplies the number of PTEs (beginning at the supplied
  2104. subsection) to remove. Supplies zero to remove views
  2105. from the supplied subsection to the end of the file.
  2106. Return Value:
  2107. None.
  2108. Environment:
  2109. Kernel Mode, PFN lock held.
  2110. --*/
  2111. {
  2112. PMSUBSECTION MappedSubsection;
  2113. MappedSubsection = StartMappedSubsection;
  2114. ASSERT ((MappedSubsection->ControlArea->u.Flags.Image == 0) &&
  2115. (MappedSubsection->ControlArea->FilePointer != NULL) &&
  2116. (MappedSubsection->ControlArea->u.Flags.PhysicalMemory == 0));
  2117. MM_PFN_LOCK_ASSERT();
  2118. do {
  2119. //
  2120. // Note the control area must be active at this point.
  2121. //
  2122. ASSERT (MappedSubsection->ControlArea->DereferenceList.Flink == NULL);
  2123. ASSERT (MappedSubsection->SubsectionBase != NULL);
  2124. ASSERT (MappedSubsection->DereferenceList.Flink == NULL);
  2125. ASSERT (((LONG_PTR)MappedSubsection->NumberOfMappedViews >= 1) ||
  2126. (MappedSubsection->u.SubsectionFlags.SubsectionStatic == 1));
  2127. MappedSubsection->NumberOfMappedViews -= 1;
  2128. MI_SNAP_SUB (MappedSubsection, 0x3);
  2129. if ((MappedSubsection->NumberOfMappedViews == 0) &&
  2130. (MappedSubsection->u.SubsectionFlags.SubsectionStatic == 0)) {
  2131. //
  2132. // Insert this subsection into the unused subsection list.
  2133. //
  2134. InsertTailList (&MmUnusedSubsectionList,
  2135. &MappedSubsection->DereferenceList);
  2136. MI_UNUSED_SUBSECTIONS_COUNT_INSERT (MappedSubsection);
  2137. }
  2138. if (LastPteOffset != 0) {
  2139. if (LastPteOffset <= (UINT64)MappedSubsection->PtesInSubsection) {
  2140. break;
  2141. }
  2142. LastPteOffset -= MappedSubsection->PtesInSubsection;
  2143. }
  2144. MappedSubsection = (PMSUBSECTION) MappedSubsection->NextSubsection;
  2145. } while (MappedSubsection != NULL);
  2146. return;
  2147. }
  2148. VOID
  2149. MiRemoveViewsFromSectionWithPfn (
  2150. IN PMSUBSECTION StartMappedSubsection,
  2151. IN UINT64 LastPteOffset OPTIONAL
  2152. )
  2153. /*++
  2154. Routine Description:
  2155. This nonpagable routine removes the views from the specified section if
  2156. the reference count reaches zero.
  2157. Arguments:
  2158. StartMappedSubsection - Supplies the mapped subsection to start at.
  2159. LastPteOffset - Supplies the number of PTEs (beginning at the supplied
  2160. subsection) to remove. Supplies zero to remove views
  2161. from the supplied subsection to the end of the file.
  2162. Return Value:
  2163. None.
  2164. Environment:
  2165. Kernel Mode, address creation mutex optionally held if called in process
  2166. context. APC_LEVEL or below.
  2167. --*/
  2168. {
  2169. KIRQL OldIrql;
  2170. ASSERT (KeGetCurrentIrql () <= APC_LEVEL);
  2171. LOCK_PFN (OldIrql);
  2172. MiRemoveViewsFromSection (StartMappedSubsection, LastPteOffset);
  2173. UNLOCK_PFN (OldIrql);
  2174. }
  2175. #if DBG
  2176. extern PMSUBSECTION MiActiveSubsection;
  2177. #endif
  2178. VOID
  2179. MiConvertStaticSubsections (
  2180. IN PCONTROL_AREA ControlArea
  2181. )
  2182. {
  2183. PMSUBSECTION MappedSubsection;
  2184. ASSERT (ControlArea->u.Flags.Image == 0);
  2185. ASSERT (ControlArea->FilePointer != NULL);
  2186. ASSERT (ControlArea->u.Flags.PhysicalMemory == 0);
  2187. if (ControlArea->u.Flags.Rom == 0) {
  2188. MappedSubsection = (PMSUBSECTION)(ControlArea + 1);
  2189. }
  2190. else {
  2191. MappedSubsection = (PMSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  2192. }
  2193. do {
  2194. MI_SNAP_SUB (MappedSubsection, 0xB);
  2195. if (MappedSubsection->DereferenceList.Flink != NULL) {
  2196. //
  2197. // This subsection is already on the dereference subsection list.
  2198. // This is the expected case.
  2199. //
  2200. NOTHING;
  2201. }
  2202. else if (MappedSubsection->u.SubsectionFlags.SubsectionStatic == 1) {
  2203. //
  2204. // This subsection was not put on the dereference subsection list
  2205. // because it was created as part of an extension or nowrite.
  2206. // Since this is the last segment dereference, convert the
  2207. // subsection and its prototype PTEs to dynamic now (iff nowrite
  2208. // is clear).
  2209. //
  2210. MappedSubsection->u.SubsectionFlags.SubsectionStatic = 0;
  2211. MappedSubsection->u2.SubsectionFlags2.SubsectionConverted = 1;
  2212. MappedSubsection->NumberOfMappedViews = 1;
  2213. MiRemoveViewsFromSection (MappedSubsection,
  2214. MappedSubsection->PtesInSubsection);
  2215. MiSubsectionsConvertedToDynamic += 1;
  2216. }
  2217. else if (MappedSubsection->SubsectionBase == NULL) {
  2218. //
  2219. // This subsection has already had its prototype PTEs reclaimed
  2220. // (or never allocated), hence it is not on any reclaim lists.
  2221. //
  2222. NOTHING;
  2223. }
  2224. else {
  2225. //
  2226. // This subsection is being processed by the dereference
  2227. // segment thread right now ! The dereference thread sets the
  2228. // mapped view count to 1 when it starts processing the subsection.
  2229. // The subsequent flush then increases it to 2 while in progress.
  2230. // So the count must be either 1 or 2 at this point.
  2231. //
  2232. ASSERT (MappedSubsection == MiActiveSubsection);
  2233. ASSERT ((MappedSubsection->NumberOfMappedViews == 1) ||
  2234. (MappedSubsection->NumberOfMappedViews == 2));
  2235. }
  2236. MappedSubsection = (PMSUBSECTION) MappedSubsection->NextSubsection;
  2237. } while (MappedSubsection != NULL);
  2238. }
  2239. NTSTATUS
  2240. MiMapViewOfDataSection (
  2241. IN PCONTROL_AREA ControlArea,
  2242. IN PEPROCESS Process,
  2243. IN PVOID *CapturedBase,
  2244. IN PLARGE_INTEGER SectionOffset,
  2245. IN PSIZE_T CapturedViewSize,
  2246. IN PSECTION Section,
  2247. IN SECTION_INHERIT InheritDisposition,
  2248. IN ULONG ProtectionMask,
  2249. IN SIZE_T CommitSize,
  2250. IN ULONG_PTR ZeroBits,
  2251. IN ULONG AllocationType
  2252. )
  2253. /*++
  2254. Routine Description:
  2255. This routine maps the specified mapped file or pagefile-backed section
  2256. into the specified process's address space.
  2257. Arguments:
  2258. see MmMapViewOfSection above...
  2259. ControlArea - Supplies the control area for the section.
  2260. Process - Supplies the process pointer which is receiving the section.
  2261. ProtectionMask - Supplies the initial page protection-mask.
  2262. Return Value:
  2263. Status of the map view operation.
  2264. Environment:
  2265. Kernel Mode, address creation mutex held.
  2266. --*/
  2267. {
  2268. PMMVAD Vad;
  2269. SIZE_T VadSize;
  2270. PVOID StartingAddress;
  2271. PVOID EndingAddress;
  2272. PSUBSECTION Subsection;
  2273. UINT64 PteOffset;
  2274. UINT64 LastPteOffset;
  2275. UINT64 TotalNumberOfPtes;
  2276. PVOID HighestUserAddress;
  2277. PMMPTE PointerPte;
  2278. PMMPTE LastPte;
  2279. MMPTE TempPte;
  2280. ULONG_PTR Alignment;
  2281. SIZE_T QuotaCharge;
  2282. SIZE_T QuotaExcess;
  2283. PMMPTE TheFirstPrototypePte;
  2284. PVOID CapturedStartingVa;
  2285. ULONG CapturedCopyOnWrite;
  2286. NTSTATUS Status;
  2287. PSEGMENT Segment;
  2288. SIZE_T SizeOfSection;
  2289. #if defined(_MIALT4K_)
  2290. SIZE_T ViewSizeFor4k;
  2291. ULONG AltFlags;
  2292. #endif
  2293. QuotaCharge = 0;
  2294. Segment = ControlArea->Segment;
  2295. if ((AllocationType & MEM_RESERVE) && (ControlArea->FilePointer == NULL)) {
  2296. return STATUS_INVALID_PARAMETER_9;
  2297. }
  2298. //
  2299. // Check to see if there is a purge operation ongoing for
  2300. // this segment.
  2301. //
  2302. if ((AllocationType & MEM_DOS_LIM) != 0) {
  2303. if ((*CapturedBase == NULL) ||
  2304. (AllocationType & MEM_RESERVE)) {
  2305. //
  2306. // If MEM_DOS_LIM is specified, the address to map the
  2307. // view MUST be specified as well.
  2308. //
  2309. return STATUS_INVALID_PARAMETER_3;
  2310. }
  2311. Alignment = PAGE_SIZE;
  2312. }
  2313. else {
  2314. Alignment = X64K;
  2315. }
  2316. //
  2317. // Check to see if a purge operation is in progress and if so, wait
  2318. // for the purge to complete. In addition, up the count of mapped
  2319. // views for this control area.
  2320. //
  2321. Status = MiCheckPurgeAndUpMapCount (ControlArea, FALSE);
  2322. if (!NT_SUCCESS (Status)) {
  2323. return Status;
  2324. }
  2325. if (*CapturedViewSize == 0) {
  2326. SectionOffset->LowPart &= ~((ULONG)Alignment - 1);
  2327. *CapturedViewSize = (ULONG_PTR)(Section->SizeOfSection.QuadPart -
  2328. SectionOffset->QuadPart);
  2329. }
  2330. else {
  2331. *CapturedViewSize += SectionOffset->LowPart & (Alignment - 1);
  2332. SectionOffset->LowPart &= ~((ULONG)Alignment - 1);
  2333. }
  2334. ASSERT ((SectionOffset->LowPart & ((ULONG)Alignment - 1)) == 0);
  2335. if ((LONG_PTR)*CapturedViewSize <= 0) {
  2336. //
  2337. // Section offset or view size past size of section.
  2338. //
  2339. MiDereferenceControlArea (ControlArea);
  2340. return STATUS_INVALID_VIEW_SIZE;
  2341. }
  2342. //
  2343. // Calculate the first prototype PTE field so it can be stored in the Vad.
  2344. //
  2345. ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
  2346. if (ControlArea->u.Flags.Rom == 0) {
  2347. Subsection = (PSUBSECTION)(ControlArea + 1);
  2348. }
  2349. else {
  2350. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  2351. }
  2352. PteOffset = (SectionOffset->QuadPart >> PAGE_SHIFT);
  2353. //
  2354. // Make sure the PTEs are not in the extended part of the segment.
  2355. //
  2356. TotalNumberOfPtes = (((UINT64)Segment->SegmentFlags.TotalNumberOfPtes4132) << 32) | Segment->TotalNumberOfPtes;
  2357. if (PteOffset >= TotalNumberOfPtes) {
  2358. MiDereferenceControlArea (ControlArea);
  2359. return STATUS_INVALID_VIEW_SIZE;
  2360. }
  2361. LastPteOffset = ((SectionOffset->QuadPart + *CapturedViewSize + PAGE_SIZE - 1) >> PAGE_SHIFT);
  2362. ASSERT (LastPteOffset >= PteOffset);
  2363. while (PteOffset >= (UINT64)Subsection->PtesInSubsection) {
  2364. PteOffset -= Subsection->PtesInSubsection;
  2365. LastPteOffset -= Subsection->PtesInSubsection;
  2366. Subsection = Subsection->NextSubsection;
  2367. ASSERT (Subsection != NULL);
  2368. }
  2369. if (ControlArea->FilePointer != NULL) {
  2370. //
  2371. // Increment the view count for every subsection spanned by this view.
  2372. //
  2373. // N.B. Callers may pass in view lengths that exceed the length of
  2374. // the section and this must succeed. Thus MiAddViews must check
  2375. // for this and know to stop the references at the end. More
  2376. // importantly, MiRemoveViews must also contain the same logic.
  2377. //
  2378. Status = MiAddViewsForSectionWithPfn ((PMSUBSECTION)Subsection,
  2379. LastPteOffset);
  2380. if (!NT_SUCCESS (Status)) {
  2381. MiDereferenceControlArea (ControlArea);
  2382. return Status;
  2383. }
  2384. }
  2385. ASSERT (Subsection->SubsectionBase != NULL);
  2386. TheFirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
  2387. //
  2388. // Calculate the quota for the specified pages.
  2389. //
  2390. if ((ControlArea->FilePointer == NULL) &&
  2391. (CommitSize != 0) &&
  2392. (Segment->NumberOfCommittedPages < TotalNumberOfPtes)) {
  2393. PointerPte = TheFirstPrototypePte;
  2394. LastPte = PointerPte + BYTES_TO_PAGES(CommitSize);
  2395. //
  2396. // Charge quota for the entire requested range. If the charge succeeds,
  2397. // excess is returned when the PTEs are actually filled in.
  2398. //
  2399. QuotaCharge = LastPte - PointerPte;
  2400. }
  2401. CapturedStartingVa = (PVOID)Section->Address.StartingVpn;
  2402. CapturedCopyOnWrite = Section->u.Flags.CopyOnWrite;
  2403. if ((*CapturedBase == NULL) && (CapturedStartingVa == NULL)) {
  2404. //
  2405. // The section is not based,
  2406. // find an empty range starting on a 64k boundary.
  2407. //
  2408. if ((AllocationType & MEM_TOP_DOWN) || (Process->VmTopDown == 1)) {
  2409. if (ZeroBits != 0) {
  2410. HighestUserAddress = (PVOID)((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits);
  2411. if (HighestUserAddress > MM_HIGHEST_VAD_ADDRESS) {
  2412. HighestUserAddress = MM_HIGHEST_VAD_ADDRESS;
  2413. }
  2414. }
  2415. else {
  2416. HighestUserAddress = MM_HIGHEST_VAD_ADDRESS;
  2417. }
  2418. Status = MiFindEmptyAddressRangeDown (&Process->VadRoot,
  2419. *CapturedViewSize,
  2420. HighestUserAddress,
  2421. Alignment,
  2422. &StartingAddress);
  2423. }
  2424. else {
  2425. Status = MiFindEmptyAddressRange (*CapturedViewSize,
  2426. Alignment,
  2427. (ULONG)ZeroBits,
  2428. &StartingAddress);
  2429. }
  2430. if (!NT_SUCCESS (Status)) {
  2431. if (ControlArea->FilePointer != NULL) {
  2432. MiRemoveViewsFromSectionWithPfn ((PMSUBSECTION)Subsection,
  2433. LastPteOffset);
  2434. }
  2435. MiDereferenceControlArea (ControlArea);
  2436. return Status;
  2437. }
  2438. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  2439. *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
  2440. if (ZeroBits != 0) {
  2441. if (EndingAddress > (PVOID)((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT >> ZeroBits)) {
  2442. if (ControlArea->FilePointer != NULL) {
  2443. MiRemoveViewsFromSectionWithPfn ((PMSUBSECTION)Subsection,
  2444. LastPteOffset);
  2445. }
  2446. MiDereferenceControlArea (ControlArea);
  2447. return STATUS_NO_MEMORY;
  2448. }
  2449. }
  2450. }
  2451. else {
  2452. if (*CapturedBase == NULL) {
  2453. //
  2454. // The section is based.
  2455. //
  2456. #if defined(_WIN64)
  2457. SizeOfSection = SectionOffset->QuadPart;
  2458. #else
  2459. SizeOfSection = SectionOffset->LowPart;
  2460. #endif
  2461. StartingAddress = (PVOID)((PCHAR)CapturedStartingVa + SizeOfSection);
  2462. }
  2463. else {
  2464. StartingAddress = MI_ALIGN_TO_SIZE (*CapturedBase, Alignment);
  2465. }
  2466. //
  2467. // Check to make sure the specified base address to ending address
  2468. // is currently unused.
  2469. //
  2470. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  2471. *CapturedViewSize - 1L) | (PAGE_SIZE - 1L));
  2472. if (MiCheckForConflictingVadExistence (Process, StartingAddress, EndingAddress) == TRUE) {
  2473. if (ControlArea->FilePointer != NULL) {
  2474. MiRemoveViewsFromSectionWithPfn ((PMSUBSECTION)Subsection,
  2475. LastPteOffset);
  2476. }
  2477. MiDereferenceControlArea (ControlArea);
  2478. return STATUS_CONFLICTING_ADDRESSES;
  2479. }
  2480. }
  2481. //
  2482. // An unoccupied address range has been found, build the virtual
  2483. // address descriptor to describe this range.
  2484. //
  2485. if (AllocationType & MEM_RESERVE) {
  2486. VadSize = sizeof (MMVAD_LONG);
  2487. Vad = ExAllocatePoolWithTag (NonPagedPool, VadSize, 'ldaV');
  2488. }
  2489. else {
  2490. VadSize = sizeof (MMVAD);
  2491. Vad = ExAllocatePoolWithTag (NonPagedPool, VadSize, MMVADKEY);
  2492. }
  2493. if (Vad == NULL) {
  2494. if (ControlArea->FilePointer != NULL) {
  2495. MiRemoveViewsFromSectionWithPfn ((PMSUBSECTION)Subsection,
  2496. LastPteOffset);
  2497. }
  2498. MiDereferenceControlArea (ControlArea);
  2499. return STATUS_INSUFFICIENT_RESOURCES;
  2500. }
  2501. RtlZeroMemory (Vad, VadSize);
  2502. Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress);
  2503. Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress);
  2504. Vad->FirstPrototypePte = TheFirstPrototypePte;
  2505. //
  2506. // Set the protection in the PTE template field of the VAD.
  2507. //
  2508. Vad->ControlArea = ControlArea;
  2509. Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
  2510. Vad->u.VadFlags.Protection = ProtectionMask;
  2511. Vad->u2.VadFlags2.CopyOnWrite = CapturedCopyOnWrite;
  2512. //
  2513. // Note that MEM_DOS_LIM significance is lost here, but those
  2514. // files are not mapped MEM_RESERVE.
  2515. //
  2516. Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16);
  2517. if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange)) {
  2518. Vad->u.VadFlags.NoChange = 1;
  2519. Vad->u2.VadFlags2.SecNoChange = 1;
  2520. }
  2521. if (AllocationType & MEM_RESERVE) {
  2522. PMMEXTEND_INFO ExtendInfo;
  2523. PMMVAD_LONG VadLong;
  2524. Vad->u2.VadFlags2.LongVad = 1;
  2525. KeAcquireGuardedMutexUnsafe (&MmSectionBasedMutex);
  2526. ExtendInfo = Segment->ExtendInfo;
  2527. if (ExtendInfo) {
  2528. ExtendInfo->ReferenceCount += 1;
  2529. }
  2530. else {
  2531. ExtendInfo = ExAllocatePoolWithTag (NonPagedPool,
  2532. sizeof(MMEXTEND_INFO),
  2533. 'xCmM');
  2534. if (ExtendInfo == NULL) {
  2535. KeReleaseGuardedMutexUnsafe (&MmSectionBasedMutex);
  2536. if (ControlArea->FilePointer != NULL) {
  2537. MiRemoveViewsFromSectionWithPfn ((PMSUBSECTION)Subsection,
  2538. LastPteOffset);
  2539. }
  2540. MiDereferenceControlArea (ControlArea);
  2541. //
  2542. // The pool allocation succeeded, but the quota charge
  2543. // in InsertVad failed, deallocate the pool and return
  2544. // an error.
  2545. //
  2546. ExFreePool (Vad);
  2547. return STATUS_INSUFFICIENT_RESOURCES;
  2548. }
  2549. ExtendInfo->ReferenceCount = 1;
  2550. ExtendInfo->CommittedSize = Segment->SizeOfSegment;
  2551. Segment->ExtendInfo = ExtendInfo;
  2552. }
  2553. if (ExtendInfo->CommittedSize < (UINT64)Section->SizeOfSection.QuadPart) {
  2554. ExtendInfo->CommittedSize = (UINT64)Section->SizeOfSection.QuadPart;
  2555. }
  2556. KeReleaseGuardedMutexUnsafe (&MmSectionBasedMutex);
  2557. Vad->u2.VadFlags2.ExtendableFile = 1;
  2558. VadLong = (PMMVAD_LONG) Vad;
  2559. ASSERT (VadLong->u4.ExtendedInfo == NULL);
  2560. VadLong->u4.ExtendedInfo = ExtendInfo;
  2561. }
  2562. //
  2563. // If the page protection is write-copy or execute-write-copy
  2564. // charge for each page in the view as it may become private.
  2565. //
  2566. if (MI_IS_PTE_PROTECTION_COPY_WRITE(ProtectionMask)) {
  2567. Vad->u.VadFlags.CommitCharge = (BYTES_TO_PAGES ((PCHAR) EndingAddress -
  2568. (PCHAR) StartingAddress));
  2569. }
  2570. PteOffset += (Vad->EndingVpn - Vad->StartingVpn);
  2571. if (PteOffset < Subsection->PtesInSubsection) {
  2572. Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset];
  2573. }
  2574. else {
  2575. Vad->LastContiguousPte = &Subsection->SubsectionBase[
  2576. (Subsection->PtesInSubsection - 1) +
  2577. Subsection->UnusedPtes];
  2578. }
  2579. if (QuotaCharge != 0) {
  2580. if (MiChargeCommitment (QuotaCharge, NULL) == FALSE) {
  2581. if (ControlArea->FilePointer != NULL) {
  2582. MiRemoveViewsFromSectionWithPfn ((PMSUBSECTION)Subsection,
  2583. LastPteOffset);
  2584. }
  2585. MiDereferenceControlArea (ControlArea);
  2586. ExFreePool (Vad);
  2587. return STATUS_COMMITMENT_LIMIT;
  2588. }
  2589. }
  2590. ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte);
  2591. LOCK_WS_UNSAFE (Process);
  2592. Status = MiInsertVad (Vad);
  2593. UNLOCK_WS_UNSAFE (Process);
  2594. if (!NT_SUCCESS(Status)) {
  2595. if (ControlArea->FilePointer != NULL) {
  2596. MiRemoveViewsFromSectionWithPfn ((PMSUBSECTION)Subsection,
  2597. LastPteOffset);
  2598. }
  2599. MiDereferenceControlArea (ControlArea);
  2600. //
  2601. // The quota charge in InsertVad failed, deallocate the pool and return
  2602. // an error.
  2603. //
  2604. ExFreePool (Vad);
  2605. if (QuotaCharge != 0) {
  2606. MiReturnCommitment (QuotaCharge);
  2607. }
  2608. return Status;
  2609. }
  2610. //
  2611. // Stash the first mapped address for the performance analysis tools.
  2612. // Note this is not synchronized across multiple processes but that's ok.
  2613. //
  2614. if (ControlArea->FilePointer == NULL) {
  2615. if (Segment->u2.FirstMappedVa == NULL) {
  2616. Segment->u2.FirstMappedVa = StartingAddress;
  2617. }
  2618. }
  2619. #if DBG
  2620. if (!(AllocationType & MEM_RESERVE)) {
  2621. ASSERT(((ULONG_PTR)EndingAddress - (ULONG_PTR)StartingAddress) <=
  2622. ROUND_TO_PAGES64(Segment->SizeOfSegment));
  2623. }
  2624. #endif
  2625. //
  2626. // If a commit size was specified, make sure those pages are committed.
  2627. //
  2628. if (QuotaCharge != 0) {
  2629. PointerPte = Vad->FirstPrototypePte;
  2630. LastPte = PointerPte + BYTES_TO_PAGES(CommitSize);
  2631. TempPte = Segment->SegmentPteTemplate;
  2632. QuotaExcess = 0;
  2633. KeAcquireGuardedMutexUnsafe (&MmSectionCommitMutex);
  2634. while (PointerPte < LastPte) {
  2635. if (PointerPte->u.Long == 0) {
  2636. MI_WRITE_INVALID_PTE (PointerPte, TempPte);
  2637. }
  2638. else {
  2639. QuotaExcess += 1;
  2640. }
  2641. PointerPte += 1;
  2642. }
  2643. ASSERT (QuotaCharge >= QuotaExcess);
  2644. QuotaCharge -= QuotaExcess;
  2645. MM_TRACK_COMMIT (MM_DBG_COMMIT_MAPVIEW_DATA, QuotaCharge);
  2646. Segment->NumberOfCommittedPages += QuotaCharge;
  2647. ASSERT (Segment->NumberOfCommittedPages <= TotalNumberOfPtes);
  2648. KeReleaseGuardedMutexUnsafe (&MmSectionCommitMutex);
  2649. InterlockedExchangeAddSizeT (&MmSharedCommit, QuotaCharge);
  2650. if (QuotaExcess != 0) {
  2651. MiReturnCommitment (QuotaExcess);
  2652. }
  2653. }
  2654. #if defined(_MIALT4K_)
  2655. if (Process->Wow64Process != NULL) {
  2656. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  2657. *CapturedViewSize - 1L) | (PAGE_4K - 1L));
  2658. ViewSizeFor4k = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
  2659. if (ControlArea->FilePointer != NULL) {
  2660. AltFlags = (AllocationType & MEM_RESERVE) ? 0 : ALT_COMMIT;
  2661. MiProtectFor4kPage (StartingAddress,
  2662. ViewSizeFor4k,
  2663. ProtectionMask,
  2664. (ALT_ALLOCATE | AltFlags),
  2665. Process);
  2666. }
  2667. else {
  2668. MiProtectMapFileFor4kPage (StartingAddress,
  2669. ViewSizeFor4k,
  2670. ProtectionMask,
  2671. CommitSize,
  2672. Vad->FirstPrototypePte,
  2673. Vad->LastContiguousPte,
  2674. Process);
  2675. }
  2676. }
  2677. #endif
  2678. //
  2679. // Update the current virtual size in the process header.
  2680. //
  2681. *CapturedViewSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L;
  2682. Process->VirtualSize += *CapturedViewSize;
  2683. if (Process->VirtualSize > Process->PeakVirtualSize) {
  2684. Process->PeakVirtualSize = Process->VirtualSize;
  2685. }
  2686. *CapturedBase = StartingAddress;
  2687. //
  2688. // Update the count of writable user mappings so the transaction semantics
  2689. // can be supported. Note that no lock synchronization is needed here as
  2690. // the transaction manager must already check for any open writable handles
  2691. // to the file - and no writable sections can be created without a writable
  2692. // file handle. So all that needs to be provided is a way for the
  2693. // transaction manager to know that there are lingering views or created
  2694. // sections still open that have write access.
  2695. //
  2696. if ((ProtectionMask & MM_READWRITE) &&
  2697. (ControlArea->FilePointer != NULL)) {
  2698. #if 0
  2699. //
  2700. // The section may no longer exist at this point so these ASSERTs
  2701. // cannot be enabled.
  2702. //
  2703. ASSERT (Section->u.Flags.UserWritable == 1);
  2704. ASSERT (Section->InitialPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE));
  2705. #endif
  2706. InterlockedIncrement ((PLONG)&Segment->WritableUserReferences);
  2707. }
  2708. return STATUS_SUCCESS;
  2709. }
  2710. NTSTATUS
  2711. MiCheckPurgeAndUpMapCount (
  2712. IN PCONTROL_AREA ControlArea,
  2713. IN LOGICAL FailIfSystemViews
  2714. )
  2715. /*++
  2716. Routine Description:
  2717. This routine synchronizes with any on going purge operations
  2718. on the same segment (identified via the control area). If
  2719. another purge operation is occurring, the function blocks until
  2720. it is completed.
  2721. When this function returns the MappedView and the NumberOfUserReferences
  2722. count for the control area will be incremented thereby referencing
  2723. the control area.
  2724. Arguments:
  2725. ControlArea - Supplies the control area for the segment to be purged.
  2726. FailIfSystemViews - Supplies TRUE if the request should fail when there
  2727. are active kernel mappings. When the image is mapped
  2728. in system or session space as a driver, copy on write
  2729. does not work so user processes are not allowed to
  2730. map the image.
  2731. Return Value:
  2732. STATUS_SUCCESS if the synchronization was successful.
  2733. NTSTATUS if the synchronization did not occur due to low resources, etc.
  2734. Environment:
  2735. Kernel Mode.
  2736. --*/
  2737. {
  2738. NTSTATUS Status;
  2739. KIRQL OldIrql;
  2740. PEVENT_COUNTER PurgedEvent;
  2741. PEVENT_COUNTER WaitEvent;
  2742. ULONG OldRef;
  2743. PKTHREAD CurrentThread;
  2744. PurgedEvent = NULL;
  2745. OldRef = 1;
  2746. if (FailIfSystemViews == TRUE) {
  2747. ASSERT (ControlArea->u.Flags.Image != 0);
  2748. }
  2749. LOCK_PFN (OldIrql);
  2750. while (ControlArea->u.Flags.BeingPurged != 0) {
  2751. //
  2752. // A purge operation is in progress.
  2753. //
  2754. if (PurgedEvent == NULL) {
  2755. //
  2756. // Release the locks and allocate pool for the event.
  2757. //
  2758. UNLOCK_PFN (OldIrql);
  2759. PurgedEvent = MiGetEventCounter ();
  2760. if (PurgedEvent == NULL) {
  2761. return STATUS_INSUFFICIENT_RESOURCES;
  2762. }
  2763. LOCK_PFN (OldIrql);
  2764. continue;
  2765. }
  2766. if (ControlArea->WaitingForDeletion == NULL) {
  2767. ControlArea->WaitingForDeletion = PurgedEvent;
  2768. WaitEvent = PurgedEvent;
  2769. PurgedEvent = NULL;
  2770. }
  2771. else {
  2772. WaitEvent = ControlArea->WaitingForDeletion;
  2773. //
  2774. // No interlock is needed for the RefCount increment as
  2775. // no thread can be decrementing it since it is still
  2776. // pointed to by the control area.
  2777. //
  2778. WaitEvent->RefCount += 1;
  2779. }
  2780. //
  2781. // Release the PFN lock and wait for the event.
  2782. //
  2783. CurrentThread = KeGetCurrentThread ();
  2784. KeEnterCriticalRegionThread (CurrentThread);
  2785. UNLOCK_PFN_AND_THEN_WAIT(OldIrql);
  2786. KeWaitForSingleObject(&WaitEvent->Event,
  2787. WrVirtualMemory,
  2788. KernelMode,
  2789. FALSE,
  2790. (PLARGE_INTEGER)NULL);
  2791. //
  2792. // Before this event can be set, the control area WaitingForDeletion
  2793. // field must be cleared (and may be reinitialized to something else),
  2794. // but cannot be reset to our local event. This allows us to
  2795. // dereference the event count lock free.
  2796. //
  2797. ASSERT (WaitEvent != ControlArea->WaitingForDeletion);
  2798. MiFreeEventCounter (WaitEvent);
  2799. LOCK_PFN (OldIrql);
  2800. KeLeaveCriticalRegionThread (CurrentThread);
  2801. }
  2802. if ((FailIfSystemViews == TRUE) &&
  2803. (ControlArea->u.Flags.ImageMappedInSystemSpace) &&
  2804. (KeGetPreviousMode() != KernelMode)) {
  2805. UNLOCK_PFN (OldIrql);
  2806. Status = STATUS_CONFLICTING_ADDRESSES;
  2807. }
  2808. else {
  2809. //
  2810. // Indicate another file is mapped for the segment.
  2811. //
  2812. ControlArea->NumberOfMappedViews += 1;
  2813. ControlArea->NumberOfUserReferences += 1;
  2814. ControlArea->u.Flags.HadUserReference = 1;
  2815. ASSERT (ControlArea->NumberOfSectionReferences != 0);
  2816. UNLOCK_PFN (OldIrql);
  2817. Status = STATUS_SUCCESS;
  2818. }
  2819. if (PurgedEvent != NULL) {
  2820. MiFreeEventCounter (PurgedEvent);
  2821. }
  2822. return Status;
  2823. }
  2824. typedef struct _NTSYM {
  2825. struct _NTSYM *Next;
  2826. PVOID SymbolTable;
  2827. ULONG NumberOfSymbols;
  2828. PVOID StringTable;
  2829. USHORT Flags;
  2830. USHORT EntrySize;
  2831. ULONG MinimumVa;
  2832. ULONG MaximumVa;
  2833. PCHAR MapName;
  2834. ULONG MapNameLen;
  2835. } NTSYM, *PNTSYM;
  2836. PVOID
  2837. MiCacheImageSymbols (
  2838. IN PVOID ImageBase
  2839. )
  2840. {
  2841. ULONG DebugSize;
  2842. PVOID DebugDirectory;
  2843. PAGED_CODE ();
  2844. DebugDirectory = NULL;
  2845. try {
  2846. DebugDirectory = RtlImageDirectoryEntryToData (ImageBase,
  2847. TRUE,
  2848. IMAGE_DIRECTORY_ENTRY_DEBUG,
  2849. &DebugSize);
  2850. //
  2851. // If using remote KD, ImageBase is what it wants to see.
  2852. //
  2853. } except (EXCEPTION_EXECUTE_HANDLER) {
  2854. NOTHING;
  2855. }
  2856. return DebugDirectory;
  2857. }
  2858. NTSYSAPI
  2859. NTSTATUS
  2860. NTAPI
  2861. NtAreMappedFilesTheSame (
  2862. IN PVOID File1MappedAsAnImage,
  2863. IN PVOID File2MappedAsFile
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. This routine compares the two files mapped at the specified
  2868. addresses to see if they are both the same file.
  2869. Arguments:
  2870. File1MappedAsAnImage - Supplies an address within the first file which
  2871. is mapped as an image file.
  2872. File2MappedAsFile - Supplies an address within the second file which
  2873. is mapped as either an image file or a data file.
  2874. Return Value:
  2875. STATUS_SUCCESS is returned if the two files are the same.
  2876. STATUS_NOT_SAME_DEVICE is returned if the files are different.
  2877. Other status values can be returned if the addresses are not mapped as
  2878. files, etc.
  2879. Environment:
  2880. User mode callable system service.
  2881. --*/
  2882. {
  2883. PMMVAD FoundVad1;
  2884. PMMVAD FoundVad2;
  2885. NTSTATUS Status;
  2886. PEPROCESS Process;
  2887. Process = PsGetCurrentProcess();
  2888. LOCK_ADDRESS_SPACE (Process);
  2889. FoundVad1 = MiLocateAddress (File1MappedAsAnImage);
  2890. FoundVad2 = MiLocateAddress (File2MappedAsFile);
  2891. if ((FoundVad1 == NULL) || (FoundVad2 == NULL)) {
  2892. //
  2893. // No virtual address is allocated at the specified base address,
  2894. // return an error.
  2895. //
  2896. Status = STATUS_INVALID_ADDRESS;
  2897. goto ErrorReturn;
  2898. }
  2899. //
  2900. // Check file names.
  2901. //
  2902. if ((FoundVad1->u.VadFlags.PrivateMemory == 1) ||
  2903. (FoundVad2->u.VadFlags.PrivateMemory == 1)) {
  2904. Status = STATUS_CONFLICTING_ADDRESSES;
  2905. goto ErrorReturn;
  2906. }
  2907. if ((FoundVad1->ControlArea == NULL) ||
  2908. (FoundVad2->ControlArea == NULL)) {
  2909. Status = STATUS_CONFLICTING_ADDRESSES;
  2910. goto ErrorReturn;
  2911. }
  2912. if ((FoundVad1->ControlArea->FilePointer == NULL) ||
  2913. (FoundVad2->ControlArea->FilePointer == NULL)) {
  2914. Status = STATUS_CONFLICTING_ADDRESSES;
  2915. goto ErrorReturn;
  2916. }
  2917. Status = STATUS_NOT_SAME_DEVICE;
  2918. if ((PVOID)FoundVad1->ControlArea ==
  2919. FoundVad2->ControlArea->FilePointer->SectionObjectPointer->ImageSectionObject) {
  2920. Status = STATUS_SUCCESS;
  2921. }
  2922. ErrorReturn:
  2923. UNLOCK_ADDRESS_SPACE (Process);
  2924. return Status;
  2925. }
  2926. NTSTATUS
  2927. MiSetPageModified (
  2928. IN PMMVAD Vad,
  2929. IN PVOID Address
  2930. )
  2931. /*++
  2932. Routine Description:
  2933. This routine sets the modified bit in the PFN database for the
  2934. pages that correspond to the specified address range.
  2935. Note that the dirty bit in the PTE is cleared by this operation.
  2936. Arguments:
  2937. Vad - Supplies the VAD to charge.
  2938. Address - Supplies the user address to access.
  2939. Return Value:
  2940. NTSTATUS.
  2941. Environment:
  2942. Kernel mode. Address space mutex held.
  2943. --*/
  2944. {
  2945. PMMPFN Pfn1;
  2946. NTSTATUS Status;
  2947. PEPROCESS CurrentProcess;
  2948. SIZE_T RealCharge;
  2949. MMPTE PteContents;
  2950. KIRQL OldIrql;
  2951. PMMPTE PointerPxe;
  2952. PMMPTE PointerPpe;
  2953. PMMPTE PointerPde;
  2954. PMMPTE PointerPte;
  2955. LOGICAL ReturnCommitment;
  2956. LOGICAL ChargedJobCommit;
  2957. //
  2958. // Charge commitment up front even though we may not use it because
  2959. // failing to get it later would make things messy.
  2960. //
  2961. RealCharge = 1;
  2962. ReturnCommitment = FALSE;
  2963. ChargedJobCommit = FALSE;
  2964. CurrentProcess = PsGetCurrentProcess ();
  2965. Status = PsChargeProcessPageFileQuota (CurrentProcess, RealCharge);
  2966. if (!NT_SUCCESS (Status)) {
  2967. return STATUS_COMMITMENT_LIMIT;
  2968. }
  2969. if (CurrentProcess->CommitChargeLimit) {
  2970. if (CurrentProcess->CommitCharge + RealCharge > CurrentProcess->CommitChargeLimit) {
  2971. if (CurrentProcess->Job) {
  2972. PsReportProcessMemoryLimitViolation ();
  2973. }
  2974. PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
  2975. return STATUS_COMMITMENT_LIMIT;
  2976. }
  2977. }
  2978. if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
  2979. if (PsChangeJobMemoryUsage (PS_JOB_STATUS_REPORT_COMMIT_CHANGES,
  2980. RealCharge) == FALSE) {
  2981. PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
  2982. return STATUS_COMMITMENT_LIMIT;
  2983. }
  2984. ChargedJobCommit = TRUE;
  2985. }
  2986. if (MiChargeCommitment (RealCharge, NULL) == FALSE) {
  2987. if (ChargedJobCommit == TRUE) {
  2988. PsChangeJobMemoryUsage (PS_JOB_STATUS_REPORT_COMMIT_CHANGES,
  2989. -(SSIZE_T)RealCharge);
  2990. }
  2991. PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
  2992. return STATUS_COMMITMENT_LIMIT;
  2993. }
  2994. CurrentProcess->CommitCharge += RealCharge;
  2995. if (CurrentProcess->CommitCharge > CurrentProcess->CommitChargePeak) {
  2996. CurrentProcess->CommitChargePeak = CurrentProcess->CommitCharge;
  2997. }
  2998. MI_INCREMENT_TOTAL_PROCESS_COMMIT (RealCharge);
  2999. MM_TRACK_COMMIT (MM_DBG_COMMIT_INSERT_VAD, RealCharge);
  3000. PointerPte = MiGetPteAddress (Address);
  3001. PointerPde = MiGetPdeAddress (Address);
  3002. PointerPpe = MiGetPpeAddress (Address);
  3003. PointerPxe = MiGetPxeAddress (Address);
  3004. do {
  3005. try {
  3006. *(volatile CCHAR *)Address;
  3007. } except (EXCEPTION_EXECUTE_HANDLER) {
  3008. CurrentProcess->CommitCharge -= RealCharge;
  3009. if (ChargedJobCommit == TRUE) {
  3010. PsChangeJobMemoryUsage (PS_JOB_STATUS_REPORT_COMMIT_CHANGES,
  3011. -(SSIZE_T)RealCharge);
  3012. }
  3013. MiReturnCommitment (RealCharge);
  3014. PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
  3015. return GetExceptionCode ();
  3016. }
  3017. LOCK_WS_UNSAFE (CurrentProcess);
  3018. #if (_MI_PAGING_LEVELS >= 4)
  3019. if ((PointerPxe->u.Hard.Valid == 0) ||
  3020. (PointerPpe->u.Hard.Valid == 0) ||
  3021. (PointerPde->u.Hard.Valid == 0) ||
  3022. (PointerPte->u.Hard.Valid == 0))
  3023. #elif (_MI_PAGING_LEVELS >= 3)
  3024. if ((PointerPpe->u.Hard.Valid == 0) ||
  3025. (PointerPde->u.Hard.Valid == 0) ||
  3026. (PointerPte->u.Hard.Valid == 0))
  3027. #else
  3028. if ((PointerPde->u.Hard.Valid == 0) ||
  3029. (PointerPte->u.Hard.Valid == 0))
  3030. #endif
  3031. {
  3032. //
  3033. // Page is no longer valid.
  3034. //
  3035. UNLOCK_WS_UNSAFE (CurrentProcess);
  3036. continue;
  3037. }
  3038. break;
  3039. } while (TRUE);
  3040. PteContents = *PointerPte;
  3041. ASSERT (PteContents.u.Hard.Valid == 1);
  3042. Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
  3043. LOCK_PFN (OldIrql);
  3044. MI_SET_MODIFIED (Pfn1, 1, 0x8);
  3045. if (Pfn1->OriginalPte.u.Soft.Prototype == 0) {
  3046. if (Pfn1->u3.e1.WriteInProgress == 0) {
  3047. MiReleasePageFileSpace (Pfn1->OriginalPte);
  3048. Pfn1->OriginalPte.u.Soft.PageFileHigh = 0;
  3049. }
  3050. //
  3051. // We didn't need to (and shouldn't have) charged commitment for
  3052. // this page as it was already pagefile backed (ie: someone else
  3053. // already charged commitment for it earlier).
  3054. //
  3055. ReturnCommitment = TRUE;
  3056. }
  3057. #ifdef NT_UP
  3058. if (MI_IS_PTE_DIRTY (PteContents)) {
  3059. #endif //NT_UP
  3060. MI_SET_PTE_CLEAN (PteContents);
  3061. //
  3062. // Clear the dirty bit in the PTE so new writes can be tracked.
  3063. //
  3064. MI_WRITE_VALID_PTE_NEW_PROTECTION (PointerPte, PteContents);
  3065. KeFlushSingleTb (Address, TRUE);
  3066. #ifdef NT_UP
  3067. }
  3068. #endif //NT_UP
  3069. UNLOCK_PFN (OldIrql);
  3070. UNLOCK_WS_UNSAFE (CurrentProcess);
  3071. if (ReturnCommitment == TRUE) {
  3072. CurrentProcess->CommitCharge -= RealCharge;
  3073. if (ChargedJobCommit == TRUE) {
  3074. PsChangeJobMemoryUsage(PS_JOB_STATUS_REPORT_COMMIT_CHANGES, -(SSIZE_T)RealCharge);
  3075. }
  3076. MiReturnCommitment (RealCharge);
  3077. PsReturnProcessPageFileQuota (CurrentProcess, RealCharge);
  3078. }
  3079. else {
  3080. //
  3081. // Commit has been charged for the copied page, add the charge
  3082. // to the VAD now so it is automatically returned when the VAD is
  3083. // deleted later.
  3084. //
  3085. MM_TRACK_COMMIT (MM_DBG_COMMIT_IMAGE, 1);
  3086. ASSERT (Vad->u.VadFlags.CommitCharge != MM_MAX_COMMIT);
  3087. Vad->u.VadFlags.CommitCharge += 1;
  3088. }
  3089. return STATUS_SUCCESS;
  3090. }
  3091. NTSTATUS
  3092. MmMapViewInSystemSpace (
  3093. IN PVOID Section,
  3094. OUT PVOID *MappedBase,
  3095. IN OUT PSIZE_T ViewSize
  3096. )
  3097. /*++
  3098. Routine Description:
  3099. This routine maps the specified section into the system's address space.
  3100. Arguments:
  3101. Section - Supplies a pointer to the section to map.
  3102. *MappedBase - Returns the address where the section was mapped.
  3103. ViewSize - Supplies the size of the view to map. If this
  3104. is specified as zero, the whole section is mapped.
  3105. Returns the actual size mapped.
  3106. Return Value:
  3107. Status of the map view operation.
  3108. Environment:
  3109. Kernel Mode, APC_LEVEL or below.
  3110. --*/
  3111. {
  3112. PMMSESSION Session;
  3113. PAGED_CODE();
  3114. Session = &MmSession;
  3115. return MiMapViewInSystemSpace (Section,
  3116. Session,
  3117. MappedBase,
  3118. ViewSize);
  3119. }
  3120. NTSTATUS
  3121. MmMapViewInSessionSpace (
  3122. IN PVOID Section,
  3123. OUT PVOID *MappedBase,
  3124. IN OUT PSIZE_T ViewSize
  3125. )
  3126. /*++
  3127. Routine Description:
  3128. This routine maps the specified section into the current process's
  3129. session address space.
  3130. Arguments:
  3131. Section - Supplies a pointer to the section to map.
  3132. *MappedBase - Returns the address where the section was mapped.
  3133. ViewSize - Supplies the size of the view to map. If this
  3134. is specified as zero, the whole section is mapped.
  3135. Returns the actual size mapped.
  3136. Return Value:
  3137. Status of the map view operation.
  3138. Environment:
  3139. Kernel Mode, APC_LEVEL or below.
  3140. --*/
  3141. {
  3142. PMMSESSION Session;
  3143. PAGED_CODE();
  3144. if ((PsGetCurrentProcess()->Flags & PS_PROCESS_FLAGS_IN_SESSION) == 0) {
  3145. return STATUS_NOT_MAPPED_VIEW;
  3146. }
  3147. ASSERT (MmIsAddressValid(MmSessionSpace) == TRUE);
  3148. Session = &MmSessionSpace->Session;
  3149. return MiMapViewInSystemSpace (Section,
  3150. Session,
  3151. MappedBase,
  3152. ViewSize);
  3153. }
  3154. NTSTATUS
  3155. MiMapViewInSystemSpace (
  3156. IN PVOID Section,
  3157. IN PMMSESSION Session,
  3158. OUT PVOID *MappedBase,
  3159. IN OUT PSIZE_T ViewSize
  3160. )
  3161. /*++
  3162. Routine Description:
  3163. This routine maps the specified section into the system's address space.
  3164. Arguments:
  3165. Section - Supplies a pointer to the section to map.
  3166. Session - Supplies the session data structure for this view.
  3167. *MappedBase - Returns the address where the section was mapped.
  3168. ViewSize - Supplies the size of the view to map. If this
  3169. is specified as zero, the whole section is mapped.
  3170. Returns the actual size mapped.
  3171. Return Value:
  3172. Status of the map view operation.
  3173. Environment:
  3174. Kernel Mode, IRQL of APC_LEVEL or below.
  3175. --*/
  3176. {
  3177. PVOID Base;
  3178. PSUBSECTION Subsection;
  3179. PCONTROL_AREA ControlArea;
  3180. PCONTROL_AREA NewControlArea;
  3181. ULONG StartBit;
  3182. ULONG SizeIn64k;
  3183. ULONG NewSizeIn64k;
  3184. PMMPTE BasePte;
  3185. PFN_NUMBER NumberOfPtes;
  3186. SIZE_T NumberOfBytes;
  3187. SIZE_T SectionSize;
  3188. NTSTATUS Status;
  3189. PAGED_CODE();
  3190. //
  3191. // Check to see if a purge operation is in progress and if so, wait
  3192. // for the purge to complete. In addition, up the count of mapped
  3193. // views for this control area.
  3194. //
  3195. ControlArea = ((PSECTION)Section)->Segment->ControlArea;
  3196. if ((ControlArea->u.Flags.GlobalOnlyPerSession == 0) &&
  3197. (ControlArea->u.Flags.Rom == 0)) {
  3198. Subsection = (PSUBSECTION)(ControlArea + 1);
  3199. }
  3200. else {
  3201. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  3202. }
  3203. Status = MiCheckPurgeAndUpMapCount (ControlArea, FALSE);
  3204. if (!NT_SUCCESS (Status)) {
  3205. return Status;
  3206. }
  3207. #if defined (_WIN64)
  3208. SectionSize = ((PSECTION)Section)->SizeOfSection.QuadPart;
  3209. #else
  3210. SectionSize = ((PSECTION)Section)->SizeOfSection.LowPart;
  3211. #endif
  3212. if (*ViewSize == 0) {
  3213. *ViewSize = SectionSize;
  3214. }
  3215. else if (*ViewSize > SectionSize) {
  3216. //
  3217. // Section offset or view size past size of section.
  3218. //
  3219. MiDereferenceControlArea (ControlArea);
  3220. return STATUS_INVALID_VIEW_SIZE;
  3221. }
  3222. //
  3223. // Calculate the first prototype PTE field in the Vad.
  3224. //
  3225. SizeIn64k = (ULONG)((*ViewSize / X64K) + ((*ViewSize & (X64K - 1)) != 0));
  3226. //
  3227. // 4GB-64K is the maximum individual view size allowed since we encode
  3228. // this into the bottom 16 bits of the MMVIEW entry.
  3229. //
  3230. if (SizeIn64k >= X64K) {
  3231. MiDereferenceControlArea (ControlArea);
  3232. return STATUS_INVALID_VIEW_SIZE;
  3233. }
  3234. Base = MiInsertInSystemSpace (Session, SizeIn64k, ControlArea);
  3235. if (Base == NULL) {
  3236. MiDereferenceControlArea (ControlArea);
  3237. return STATUS_NO_MEMORY;
  3238. }
  3239. NumberOfBytes = (SIZE_T)SizeIn64k * X64K;
  3240. if (Session == &MmSession) {
  3241. MiFillSystemPageDirectory (Base, NumberOfBytes);
  3242. Status = STATUS_SUCCESS;
  3243. }
  3244. else {
  3245. Status = MiSessionCommitPageTables (Base,
  3246. (PVOID)((ULONG_PTR)Base + NumberOfBytes));
  3247. }
  3248. if (!NT_SUCCESS (Status)) {
  3249. bail:
  3250. MiDereferenceControlArea (ControlArea);
  3251. StartBit = (ULONG) (((ULONG_PTR)Base - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16);
  3252. LOCK_SYSTEM_VIEW_SPACE (Session);
  3253. NewSizeIn64k = MiRemoveFromSystemSpace (Session, Base, &NewControlArea);
  3254. ASSERT (ControlArea == NewControlArea);
  3255. ASSERT (SizeIn64k == NewSizeIn64k);
  3256. RtlClearBits (Session->SystemSpaceBitMap, StartBit, SizeIn64k);
  3257. UNLOCK_SYSTEM_VIEW_SPACE (Session);
  3258. return Status;
  3259. }
  3260. BasePte = MiGetPteAddress (Base);
  3261. NumberOfPtes = BYTES_TO_PAGES (*ViewSize);
  3262. //
  3263. // Setup PTEs to point to prototype PTEs.
  3264. //
  3265. Status = MiAddMappedPtes (BasePte, NumberOfPtes, ControlArea);
  3266. if (!NT_SUCCESS (Status)) {
  3267. goto bail;
  3268. }
  3269. *MappedBase = Base;
  3270. return STATUS_SUCCESS;
  3271. }
  3272. NTSTATUS
  3273. MmGetSessionMappedViewInformation (
  3274. OUT PVOID SystemInformation,
  3275. IN ULONG SystemInformationLength,
  3276. OUT PULONG Length,
  3277. IN PULONG SessionId OPTIONAL
  3278. )
  3279. /*++
  3280. Routine Description:
  3281. This function returns information about all the per-session mapped
  3282. views in the system.
  3283. Arguments:
  3284. SystemInformation - A pointer to a buffer which receives the specified
  3285. information.
  3286. SystemInformationLength - Specifies the length in bytes of the system
  3287. information buffer.
  3288. Length - Receives the number of bytes placed (or would have been placed)
  3289. in the system information buffer.
  3290. SessionId - Session Id (-1 indicates enumerate all sessions).
  3291. Environment:
  3292. Kernel mode.
  3293. Return Value:
  3294. Returns one of the following status codes:
  3295. STATUS_SUCCESS - normal, successful completion.
  3296. STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
  3297. did not specify a valid value.
  3298. STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
  3299. parameter did not match the length required for the information
  3300. class requested by the SystemInformationClass parameter.
  3301. STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer
  3302. or the Length pointer value specified an invalid address.
  3303. STATUS_WORKING_SET_QUOTA - The process does not have sufficient
  3304. working set to lock the specified output structure in memory.
  3305. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
  3306. for this request to complete.
  3307. --*/
  3308. {
  3309. PMMSESSION Session;
  3310. KAPC_STATE ApcState;
  3311. PVOID MappedAddress;
  3312. PVOID OpaqueSession;
  3313. PVOID LockVariable;
  3314. ULONG ContiguousFree;
  3315. ULONG Index;
  3316. ULONG Hint;
  3317. ULONG TotalFree;
  3318. ULONG TotalSize;
  3319. ULONG CurrentSessionId;
  3320. ULONG StartingIndex;
  3321. NTSTATUS status;
  3322. NTSTATUS status1;
  3323. PSYSTEM_SESSION_MAPPED_VIEW_INFORMATION SessionMappedViewInfo;
  3324. *Length = 0;
  3325. TotalSize = 0;
  3326. status = STATUS_SUCCESS;
  3327. SessionMappedViewInfo = NULL;
  3328. if (SystemInformationLength > 0) {
  3329. status1 = ExLockUserBuffer (SystemInformation,
  3330. SystemInformationLength,
  3331. KeGetPreviousMode(),
  3332. IoWriteAccess,
  3333. &MappedAddress,
  3334. &LockVariable);
  3335. if (!NT_SUCCESS(status1)) {
  3336. return status1;
  3337. }
  3338. }
  3339. else {
  3340. //
  3341. // This indicates the caller just wants to know the size of the
  3342. // buffer to allocate but is not prepared to accept any data content
  3343. // in this instance.
  3344. //
  3345. MappedAddress = NULL;
  3346. LockVariable = NULL;
  3347. }
  3348. for (OpaqueSession = MmGetNextSession (NULL);
  3349. OpaqueSession != NULL;
  3350. OpaqueSession = MmGetNextSession (OpaqueSession)) {
  3351. SessionMappedViewInfo = (PSYSTEM_SESSION_MAPPED_VIEW_INFORMATION)
  3352. ((PUCHAR)MappedAddress + TotalSize);
  3353. //
  3354. // If a specific session was requested, only extract that one.
  3355. //
  3356. CurrentSessionId = MmGetSessionId (OpaqueSession);
  3357. if ((*SessionId == 0xFFFFFFFF) || (CurrentSessionId == *SessionId)) {
  3358. //
  3359. // Attach to session now to perform operations...
  3360. //
  3361. if (NT_SUCCESS (MmAttachSession (OpaqueSession, &ApcState))) {
  3362. //
  3363. // Session is still alive so include it.
  3364. //
  3365. TotalSize += sizeof (SYSTEM_SESSION_MAPPED_VIEW_INFORMATION);
  3366. if (TotalSize > SystemInformationLength) {
  3367. status = STATUS_INFO_LENGTH_MISMATCH;
  3368. }
  3369. else {
  3370. //
  3371. // Get mapped view information for each session.
  3372. //
  3373. Session = &MmSessionSpace->Session;
  3374. Hint = 0;
  3375. TotalFree = 0;
  3376. LOCK_SYSTEM_VIEW_SPACE (Session);
  3377. ContiguousFree = RtlFindLongestRunClear (
  3378. Session->SystemSpaceBitMap,
  3379. &StartingIndex);
  3380. do {
  3381. Index = RtlFindClearBits (Session->SystemSpaceBitMap,
  3382. 1,
  3383. Hint);
  3384. if ((Index < Hint) || (Index == NO_BITS_FOUND)) {
  3385. break;
  3386. }
  3387. TotalFree += 1;
  3388. Hint = Index + 1;
  3389. } while (TRUE);
  3390. UNLOCK_SYSTEM_VIEW_SPACE (Session);
  3391. SessionMappedViewInfo->NumberOfBytesAvailable =
  3392. (SIZE_T)TotalFree * X64K;
  3393. SessionMappedViewInfo->NumberOfBytesAvailableContiguous =
  3394. (SIZE_T)ContiguousFree * X64K;
  3395. SessionMappedViewInfo->SessionId = CurrentSessionId;
  3396. SessionMappedViewInfo->ViewFailures = Session->BitmapFailures;
  3397. //
  3398. // Point to next session.
  3399. //
  3400. SessionMappedViewInfo->NextEntryOffset = TotalSize;
  3401. }
  3402. //
  3403. // Detach from session.
  3404. //
  3405. MmDetachSession (OpaqueSession, &ApcState);
  3406. }
  3407. //
  3408. // Bail if only this session was of interest.
  3409. //
  3410. if (*SessionId != 0xFFFFFFFF) {
  3411. MmQuitNextSession (OpaqueSession);
  3412. break;
  3413. }
  3414. }
  3415. }
  3416. if ((NT_SUCCESS (status)) && (SessionMappedViewInfo != NULL)) {
  3417. SessionMappedViewInfo->NextEntryOffset = 0;
  3418. }
  3419. if (MappedAddress != NULL) {
  3420. ExUnlockUserBuffer (LockVariable);
  3421. }
  3422. *Length = TotalSize;
  3423. return status;
  3424. }
  3425. VOID
  3426. MiFillSystemPageDirectory (
  3427. IN PVOID Base,
  3428. IN SIZE_T NumberOfBytes
  3429. )
  3430. /*++
  3431. Routine Description:
  3432. This routine allocates page tables and fills the system page directory
  3433. entries for the specified virtual address range.
  3434. Arguments:
  3435. Base - Supplies the virtual address of the view.
  3436. NumberOfBytes - Supplies the number of bytes the view spans.
  3437. Return Value:
  3438. None.
  3439. Environment:
  3440. Kernel Mode, IRQL of dispatch level.
  3441. This routine could be made PAGELK but it is a high frequency routine
  3442. so it is actually better to keep it nonpaged to avoid bringing in the
  3443. entire PAGELK section.
  3444. --*/
  3445. {
  3446. PMMPTE FirstPde;
  3447. PMMPTE LastPde;
  3448. PMMPTE FirstSystemPde;
  3449. PMMPTE PointerPpe;
  3450. PMMPTE PointerPxe;
  3451. MMPTE TempPte;
  3452. PFN_NUMBER PageFrameIndex;
  3453. KIRQL OldIrql;
  3454. #if (_MI_PAGING_LEVELS < 3)
  3455. ULONG i;
  3456. #endif
  3457. PAGED_CODE();
  3458. //
  3459. // CODE IS ALREADY LOCKED BY CALLER.
  3460. //
  3461. FirstPde = MiGetPdeAddress (Base);
  3462. LastPde = MiGetPdeAddress ((PVOID)(((PCHAR)Base) + NumberOfBytes - 1));
  3463. PointerPpe = MiGetPpeAddress (Base);
  3464. PointerPxe = MiGetPxeAddress (Base);
  3465. #if (_MI_PAGING_LEVELS >= 3)
  3466. FirstSystemPde = FirstPde;
  3467. #else
  3468. FirstSystemPde = &MmSystemPagePtes[((ULONG_PTR)FirstPde &
  3469. (PD_PER_SYSTEM * (PDE_PER_PAGE * sizeof(MMPTE)) - 1)) / sizeof(MMPTE) ];
  3470. #endif
  3471. do {
  3472. #if (_MI_PAGING_LEVELS >= 4)
  3473. if (PointerPxe->u.Hard.Valid == 0) {
  3474. //
  3475. // No page directory page exists, get a page and map it in.
  3476. //
  3477. TempPte = ValidKernelPde;
  3478. LOCK_PFN (OldIrql);
  3479. if (PointerPxe->u.Hard.Valid == 0) {
  3480. if ((MmAvailablePages < MM_HIGH_LIMIT) &&
  3481. (MiEnsureAvailablePageOrWait (NULL, PointerPxe, OldIrql))) {
  3482. //
  3483. // PFN_LOCK was dropped, redo this loop as another process
  3484. // could have made this PDE valid.
  3485. //
  3486. UNLOCK_PFN (OldIrql);
  3487. continue;
  3488. }
  3489. MiChargeCommitmentCantExpand (1, TRUE);
  3490. MM_TRACK_COMMIT (MM_DBG_COMMIT_FILL_SYSTEM_DIRECTORY, 1);
  3491. PageFrameIndex = MiRemoveAnyPage (
  3492. MI_GET_PAGE_COLOR_FROM_PTE (PointerPxe));
  3493. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  3494. MI_WRITE_VALID_PTE (PointerPxe, TempPte);
  3495. MiInitializePfn (PageFrameIndex, PointerPxe, 1);
  3496. KeZeroPages (MiGetVirtualAddressMappedByPte (PointerPxe),
  3497. PAGE_SIZE);
  3498. }
  3499. UNLOCK_PFN (OldIrql);
  3500. }
  3501. #endif
  3502. #if (_MI_PAGING_LEVELS >= 3)
  3503. if (PointerPpe->u.Hard.Valid == 0) {
  3504. //
  3505. // No page directory page exists, get a page and map it in.
  3506. //
  3507. TempPte = ValidKernelPde;
  3508. LOCK_PFN (OldIrql);
  3509. if (PointerPpe->u.Hard.Valid == 0) {
  3510. if ((MmAvailablePages < MM_HIGH_LIMIT) &&
  3511. (MiEnsureAvailablePageOrWait (NULL, PointerPpe, OldIrql))) {
  3512. //
  3513. // PFN_LOCK was dropped, redo this loop as another process
  3514. // could have made this PDE valid.
  3515. //
  3516. UNLOCK_PFN (OldIrql);
  3517. continue;
  3518. }
  3519. MiChargeCommitmentCantExpand (1, TRUE);
  3520. MM_TRACK_COMMIT (MM_DBG_COMMIT_FILL_SYSTEM_DIRECTORY, 1);
  3521. PageFrameIndex = MiRemoveAnyPage (
  3522. MI_GET_PAGE_COLOR_FROM_PTE (PointerPpe));
  3523. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  3524. MI_WRITE_VALID_PTE (PointerPpe, TempPte);
  3525. MiInitializePfn (PageFrameIndex, PointerPpe, 1);
  3526. KeZeroPages (MiGetVirtualAddressMappedByPte (PointerPpe),
  3527. PAGE_SIZE);
  3528. }
  3529. UNLOCK_PFN (OldIrql);
  3530. }
  3531. #endif
  3532. if (FirstSystemPde->u.Hard.Valid == 0) {
  3533. //
  3534. // No page table page exists, get a page and map it in.
  3535. //
  3536. TempPte = ValidKernelPde;
  3537. LOCK_PFN (OldIrql);
  3538. if (FirstSystemPde->u.Hard.Valid == 0) {
  3539. if ((MmAvailablePages < MM_HIGH_LIMIT) &&
  3540. (MiEnsureAvailablePageOrWait (NULL, FirstSystemPde, OldIrql))) {
  3541. //
  3542. // PFN_LOCK was dropped, redo this loop as another process
  3543. // could have made this PDE valid.
  3544. //
  3545. UNLOCK_PFN (OldIrql);
  3546. continue;
  3547. }
  3548. MiChargeCommitmentCantExpand (1, TRUE);
  3549. MM_TRACK_COMMIT (MM_DBG_COMMIT_FILL_SYSTEM_DIRECTORY, 1);
  3550. PageFrameIndex = MiRemoveAnyPage (
  3551. MI_GET_PAGE_COLOR_FROM_PTE (FirstSystemPde));
  3552. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  3553. MI_WRITE_VALID_PTE (FirstSystemPde, TempPte);
  3554. //
  3555. // The FirstPde and FirstSystemPde may be identical even on
  3556. // 32-bit machines if we are currently running in the
  3557. // system process, so check for the valid bit first so we
  3558. // don't assert on a checked build.
  3559. //
  3560. if (FirstPde->u.Hard.Valid == 0) {
  3561. MI_WRITE_VALID_PTE (FirstPde, TempPte);
  3562. }
  3563. #if (_MI_PAGING_LEVELS >= 3)
  3564. MiInitializePfn (PageFrameIndex, FirstPde, 1);
  3565. #else
  3566. i = (FirstPde - MiGetPdeAddress(0)) / PDE_PER_PAGE;
  3567. MiInitializePfnForOtherProcess (PageFrameIndex,
  3568. FirstPde,
  3569. MmSystemPageDirectory[i]);
  3570. #endif
  3571. KeZeroPages (MiGetVirtualAddressMappedByPte (FirstPde),
  3572. PAGE_SIZE);
  3573. }
  3574. UNLOCK_PFN (OldIrql);
  3575. }
  3576. FirstSystemPde += 1;
  3577. FirstPde += 1;
  3578. #if (_MI_PAGING_LEVELS >= 3)
  3579. if (MiIsPteOnPdeBoundary (FirstPde)) {
  3580. PointerPpe = MiGetPteAddress (FirstPde);
  3581. if (MiIsPteOnPpeBoundary (FirstPde)) {
  3582. PointerPxe = MiGetPdeAddress (FirstPde);
  3583. }
  3584. }
  3585. #endif
  3586. } while (FirstPde <= LastPde);
  3587. }
  3588. NTSTATUS
  3589. MmUnmapViewInSystemSpace (
  3590. IN PVOID MappedBase
  3591. )
  3592. /*++
  3593. Routine Description:
  3594. This routine unmaps the specified section from the system's address space.
  3595. Arguments:
  3596. MappedBase - Supplies the address of the view to unmap.
  3597. Return Value:
  3598. Status of the map view operation.
  3599. Environment:
  3600. Kernel Mode, IRQL of dispatch level.
  3601. --*/
  3602. {
  3603. PAGED_CODE();
  3604. return MiUnmapViewInSystemSpace (&MmSession, MappedBase);
  3605. }
  3606. NTSTATUS
  3607. MmUnmapViewInSessionSpace (
  3608. IN PVOID MappedBase
  3609. )
  3610. /*++
  3611. Routine Description:
  3612. This routine unmaps the specified section from the system's address space.
  3613. Arguments:
  3614. MappedBase - Supplies the address of the view to unmap.
  3615. Return Value:
  3616. Status of the map view operation.
  3617. Environment:
  3618. Kernel Mode, IRQL of dispatch level.
  3619. --*/
  3620. {
  3621. PMMSESSION Session;
  3622. PAGED_CODE();
  3623. if ((PsGetCurrentProcess()->Flags & PS_PROCESS_FLAGS_IN_SESSION) == 0) {
  3624. return STATUS_NOT_MAPPED_VIEW;
  3625. }
  3626. ASSERT (MmIsAddressValid(MmSessionSpace) == TRUE);
  3627. Session = &MmSessionSpace->Session;
  3628. return MiUnmapViewInSystemSpace (Session, MappedBase);
  3629. }
  3630. NTSTATUS
  3631. MiUnmapViewInSystemSpace (
  3632. IN PMMSESSION Session,
  3633. IN PVOID MappedBase
  3634. )
  3635. /*++
  3636. Routine Description:
  3637. This routine unmaps the specified section from the system's address space.
  3638. Arguments:
  3639. Session - Supplies the session data structure for this view.
  3640. MappedBase - Supplies the address of the view to unmap.
  3641. Return Value:
  3642. Status of the map view operation.
  3643. Environment:
  3644. Kernel Mode, IRQL of dispatch level.
  3645. --*/
  3646. {
  3647. ULONG StartBit;
  3648. ULONG Size;
  3649. PCONTROL_AREA ControlArea;
  3650. PMMSUPPORT Ws;
  3651. PAGED_CODE();
  3652. if (Session == &MmSession) {
  3653. Ws = &MmSystemCacheWs;
  3654. }
  3655. else {
  3656. Ws = &MmSessionSpace->GlobalVirtualAddress->Vm;
  3657. }
  3658. StartBit = (ULONG) (((ULONG_PTR)MappedBase - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16);
  3659. LOCK_SYSTEM_VIEW_SPACE (Session);
  3660. Size = MiRemoveFromSystemSpace (Session, MappedBase, &ControlArea);
  3661. RtlClearBits (Session->SystemSpaceBitMap, StartBit, Size);
  3662. //
  3663. // Zero PTEs.
  3664. //
  3665. Size = Size * (X64K >> PAGE_SHIFT);
  3666. MiRemoveMappedPtes (MappedBase, Size, ControlArea, Ws);
  3667. UNLOCK_SYSTEM_VIEW_SPACE (Session);
  3668. return STATUS_SUCCESS;
  3669. }
  3670. PVOID
  3671. MiInsertInSystemSpace (
  3672. IN PMMSESSION Session,
  3673. IN ULONG SizeIn64k,
  3674. IN PCONTROL_AREA ControlArea
  3675. )
  3676. /*++
  3677. Routine Description:
  3678. This routine creates a view in system space for the specified control
  3679. area (file mapping).
  3680. Arguments:
  3681. SizeIn64k - Supplies the size of the view to be created.
  3682. ControlArea - Supplies a pointer to the control area for this view.
  3683. Return Value:
  3684. Base address where the view was mapped, NULL if the view could not be
  3685. mapped.
  3686. Environment:
  3687. Kernel Mode.
  3688. --*/
  3689. {
  3690. PVOID Base;
  3691. ULONG_PTR Entry;
  3692. ULONG Hash;
  3693. ULONG i;
  3694. ULONG AllocSize;
  3695. PMMVIEW OldTable;
  3696. ULONG StartBit;
  3697. ULONG NewHashSize;
  3698. POOL_TYPE PoolType;
  3699. PAGED_CODE();
  3700. ASSERT (SizeIn64k < X64K);
  3701. //
  3702. // CODE IS ALREADY LOCKED BY CALLER.
  3703. //
  3704. LOCK_SYSTEM_VIEW_SPACE (Session);
  3705. if (Session->SystemSpaceHashEntries + 8 > Session->SystemSpaceHashSize) {
  3706. //
  3707. // Less than 8 free slots, reallocate and rehash.
  3708. //
  3709. NewHashSize = Session->SystemSpaceHashSize << 1;
  3710. AllocSize = sizeof(MMVIEW) * NewHashSize;
  3711. OldTable = Session->SystemSpaceViewTable;
  3712. //
  3713. // The SystemSpaceViewTable for system (not session) space is only
  3714. // allocated from nonpaged pool so it can be safely torn down during
  3715. // clean shutdowns. Otherwise it could be allocated from paged pool
  3716. // just like the session SystemSpaceViewTable.
  3717. //
  3718. if (Session == &MmSession) {
  3719. PoolType = NonPagedPool;
  3720. }
  3721. else {
  3722. PoolType = PagedPool;
  3723. }
  3724. Session->SystemSpaceViewTable = ExAllocatePoolWithTag (PoolType,
  3725. AllocSize,
  3726. ' mM');
  3727. if (Session->SystemSpaceViewTable == NULL) {
  3728. Session->SystemSpaceViewTable = OldTable;
  3729. }
  3730. else {
  3731. RtlZeroMemory (Session->SystemSpaceViewTable, AllocSize);
  3732. Session->SystemSpaceHashSize = NewHashSize;
  3733. Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1;
  3734. for (i = 0; i < (Session->SystemSpaceHashSize / 2); i += 1) {
  3735. if (OldTable[i].Entry != 0) {
  3736. Hash = (ULONG) ((OldTable[i].Entry >> 16) % Session->SystemSpaceHashKey);
  3737. while (Session->SystemSpaceViewTable[Hash].Entry != 0) {
  3738. Hash += 1;
  3739. if (Hash >= Session->SystemSpaceHashSize) {
  3740. Hash = 0;
  3741. }
  3742. }
  3743. Session->SystemSpaceViewTable[Hash] = OldTable[i];
  3744. }
  3745. }
  3746. ExFreePool (OldTable);
  3747. }
  3748. }
  3749. if (Session->SystemSpaceHashEntries == Session->SystemSpaceHashSize) {
  3750. //
  3751. // There are no free hash slots to place a new entry into even
  3752. // though there may still be unused virtual address space.
  3753. //
  3754. UNLOCK_SYSTEM_VIEW_SPACE (Session);
  3755. return NULL;
  3756. }
  3757. StartBit = RtlFindClearBitsAndSet (Session->SystemSpaceBitMap,
  3758. SizeIn64k,
  3759. 0);
  3760. if (StartBit == NO_BITS_FOUND) {
  3761. Session->BitmapFailures += 1;
  3762. UNLOCK_SYSTEM_VIEW_SPACE (Session);
  3763. return NULL;
  3764. }
  3765. Base = (PVOID)((PCHAR)Session->SystemSpaceViewStart + ((ULONG_PTR)StartBit * X64K));
  3766. Entry = (ULONG_PTR) MI_64K_ALIGN(Base) + SizeIn64k;
  3767. Hash = (ULONG) ((Entry >> 16) % Session->SystemSpaceHashKey);
  3768. while (Session->SystemSpaceViewTable[Hash].Entry != 0) {
  3769. Hash += 1;
  3770. if (Hash >= Session->SystemSpaceHashSize) {
  3771. Hash = 0;
  3772. }
  3773. }
  3774. Session->SystemSpaceHashEntries += 1;
  3775. Session->SystemSpaceViewTable[Hash].Entry = Entry;
  3776. Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea;
  3777. UNLOCK_SYSTEM_VIEW_SPACE (Session);
  3778. return Base;
  3779. }
  3780. ULONG
  3781. MiRemoveFromSystemSpace (
  3782. IN PMMSESSION Session,
  3783. IN PVOID Base,
  3784. OUT PCONTROL_AREA *ControlArea
  3785. )
  3786. /*++
  3787. Routine Description:
  3788. This routine looks up the specified view in the system space hash
  3789. table and unmaps the view from system space and the table.
  3790. Arguments:
  3791. Session - Supplies the session data structure for this view.
  3792. Base - Supplies the base address for the view. If this address is
  3793. NOT found in the hash table, the system bugchecks.
  3794. ControlArea - Returns the control area corresponding to the base
  3795. address.
  3796. Return Value:
  3797. Size of the view divided by 64k.
  3798. Environment:
  3799. Kernel Mode, system view hash table locked.
  3800. --*/
  3801. {
  3802. ULONG_PTR Base16;
  3803. ULONG Hash;
  3804. ULONG Size;
  3805. ULONG count;
  3806. PAGED_CODE();
  3807. count = 0;
  3808. Base16 = (ULONG_PTR)Base >> 16;
  3809. Hash = (ULONG)(Base16 % Session->SystemSpaceHashKey);
  3810. while ((Session->SystemSpaceViewTable[Hash].Entry >> 16) != Base16) {
  3811. Hash += 1;
  3812. if (Hash >= Session->SystemSpaceHashSize) {
  3813. Hash = 0;
  3814. count += 1;
  3815. if (count == 2) {
  3816. KeBugCheckEx (DRIVER_UNMAPPING_INVALID_VIEW,
  3817. (ULONG_PTR)Base,
  3818. 1,
  3819. 0,
  3820. 0);
  3821. }
  3822. }
  3823. }
  3824. Session->SystemSpaceHashEntries -= 1;
  3825. Size = (ULONG) (Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF);
  3826. Session->SystemSpaceViewTable[Hash].Entry = 0;
  3827. *ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea;
  3828. return Size;
  3829. }
  3830. LOGICAL
  3831. MiInitializeSystemSpaceMap (
  3832. PVOID InputSession OPTIONAL
  3833. )
  3834. /*++
  3835. Routine Description:
  3836. This routine initializes the tables for mapping views into system space.
  3837. Views are kept in a multiple of 64k bytes in a growable hashed table.
  3838. Arguments:
  3839. InputSession - Supplies NULL if this is the initial system session
  3840. (non-Hydra), a valid session pointer (the pointer must
  3841. be in global space, not session space) for Hydra session
  3842. initialization.
  3843. Return Value:
  3844. TRUE on success, FALSE on failure.
  3845. Environment:
  3846. Kernel Mode, initialization.
  3847. --*/
  3848. {
  3849. SIZE_T AllocSize;
  3850. SIZE_T Size;
  3851. PCHAR ViewStart;
  3852. PMMSESSION Session;
  3853. POOL_TYPE PoolType;
  3854. if (ARGUMENT_PRESENT (InputSession)) {
  3855. Session = (PMMSESSION)InputSession;
  3856. ViewStart = (PCHAR) MiSessionViewStart;
  3857. Size = MmSessionViewSize;
  3858. }
  3859. else {
  3860. Session = &MmSession;
  3861. ViewStart = (PCHAR)MiSystemViewStart;
  3862. Size = MmSystemViewSize;
  3863. }
  3864. //
  3865. // We are passed a system global address for the address of the session.
  3866. // Save a global pointer to the mutex below because multiple sessions will
  3867. // generally give us a session-space (not a global space) pointer to the
  3868. // MMSESSION in subsequent calls. We need the global pointer for the mutex
  3869. // field for the kernel primitives to work properly.
  3870. //
  3871. Session->SystemSpaceViewLockPointer = &Session->SystemSpaceViewLock;
  3872. KeInitializeGuardedMutex (Session->SystemSpaceViewLockPointer);
  3873. //
  3874. // If the kernel image has not been biased to allow for 3gb of user space,
  3875. // then the system space view starts at the defined place. Otherwise, it
  3876. // starts 16mb above the kernel image.
  3877. //
  3878. Session->SystemSpaceViewStart = ViewStart;
  3879. MiCreateBitMap (&Session->SystemSpaceBitMap, Size / X64K, NonPagedPool);
  3880. if (Session->SystemSpaceBitMap == NULL) {
  3881. MM_BUMP_SESSION_FAILURES (MM_SESSION_FAILURE_NO_NONPAGED_POOL);
  3882. return FALSE;
  3883. }
  3884. RtlClearAllBits (Session->SystemSpaceBitMap);
  3885. //
  3886. // Build the view table.
  3887. //
  3888. Session->SystemSpaceHashSize = 31;
  3889. Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1;
  3890. Session->SystemSpaceHashEntries = 0;
  3891. AllocSize = sizeof(MMVIEW) * Session->SystemSpaceHashSize;
  3892. ASSERT (AllocSize < PAGE_SIZE);
  3893. //
  3894. // The SystemSpaceViewTable for system (not session) space is only
  3895. // allocated from nonpaged pool so it can be safely torn down during
  3896. // clean shutdowns. Otherwise it could be allocated from paged pool
  3897. // just like the session SystemSpaceViewTable.
  3898. //
  3899. if (Session == &MmSession) {
  3900. PoolType = NonPagedPool;
  3901. }
  3902. else {
  3903. PoolType = PagedPool;
  3904. }
  3905. Session->SystemSpaceViewTable = ExAllocatePoolWithTag (PoolType,
  3906. AllocSize,
  3907. ' mM');
  3908. if (Session->SystemSpaceViewTable == NULL) {
  3909. MM_BUMP_SESSION_FAILURES (MM_SESSION_FAILURE_NO_SESSION_PAGED_POOL);
  3910. MiRemoveBitMap (&Session->SystemSpaceBitMap);
  3911. return FALSE;
  3912. }
  3913. RtlZeroMemory (Session->SystemSpaceViewTable, AllocSize);
  3914. return TRUE;
  3915. }
  3916. VOID
  3917. MiFreeSessionSpaceMap (
  3918. VOID
  3919. )
  3920. /*++
  3921. Routine Description:
  3922. This routine frees the tables used for mapping session views.
  3923. Arguments:
  3924. None.
  3925. Return Value:
  3926. None.
  3927. Environment:
  3928. Kernel Mode. The caller must be in the correct session context.
  3929. --*/
  3930. {
  3931. PMMSESSION Session;
  3932. PAGED_CODE();
  3933. Session = &MmSessionSpace->Session;
  3934. //
  3935. // Check for leaks of objects in the view table.
  3936. //
  3937. LOCK_SYSTEM_VIEW_SPACE (Session);
  3938. if (Session->SystemSpaceViewTable && Session->SystemSpaceHashEntries) {
  3939. KeBugCheckEx (SESSION_HAS_VALID_VIEWS_ON_EXIT,
  3940. (ULONG_PTR)MmSessionSpace->SessionId,
  3941. Session->SystemSpaceHashEntries,
  3942. (ULONG_PTR)&Session->SystemSpaceViewTable[0],
  3943. Session->SystemSpaceHashSize);
  3944. #if 0
  3945. ULONG Index;
  3946. for (Index = 0; Index < Session->SystemSpaceHashSize; Index += 1) {
  3947. PMMVIEW Table;
  3948. PVOID Base;
  3949. Table = &Session->SystemSpaceViewTable[Index];
  3950. if (Table->Entry) {
  3951. #if DBG
  3952. DbgPrint ("MM: MiFreeSessionSpaceMap: view entry %d leak: ControlArea %p, Addr %p, Size %d\n",
  3953. Index,
  3954. Table->ControlArea,
  3955. Table->Entry & ~0xFFFF,
  3956. Table->Entry & 0x0000FFFF
  3957. );
  3958. #endif
  3959. Base = (PVOID)(Table->Entry & ~0xFFFF);
  3960. //
  3961. // MiUnmapViewInSystemSpace locks the ViewLock.
  3962. //
  3963. UNLOCK_SYSTEM_VIEW_SPACE(Session);
  3964. MiUnmapViewInSystemSpace (Session, Base);
  3965. LOCK_SYSTEM_VIEW_SPACE (Session);
  3966. //
  3967. // The view table may have been deleted while we let go of
  3968. // the lock.
  3969. //
  3970. if (Session->SystemSpaceViewTable == NULL) {
  3971. break;
  3972. }
  3973. }
  3974. }
  3975. #endif
  3976. }
  3977. UNLOCK_SYSTEM_VIEW_SPACE (Session);
  3978. if (Session->SystemSpaceViewTable) {
  3979. ExFreePool (Session->SystemSpaceViewTable);
  3980. Session->SystemSpaceViewTable = NULL;
  3981. }
  3982. if (Session->SystemSpaceBitMap) {
  3983. MiRemoveBitMap (&Session->SystemSpaceBitMap);
  3984. }
  3985. }
  3986. HANDLE
  3987. MmSecureVirtualMemory (
  3988. IN PVOID Address,
  3989. IN SIZE_T Size,
  3990. IN ULONG ProbeMode
  3991. )
  3992. /*++
  3993. Routine Description:
  3994. This routine probes the requested address range and protects
  3995. the specified address range from having its protection made
  3996. more restricted and being deleted.
  3997. MmUnsecureVirtualMemory is used to allow the range to return
  3998. to a normal state.
  3999. Arguments:
  4000. Address - Supplies the base address to probe and secure.
  4001. Size - Supplies the size of the range to secure.
  4002. ProbeMode - Supplies one of PAGE_READONLY or PAGE_READWRITE.
  4003. Return Value:
  4004. Returns a handle to be used to unsecure the range.
  4005. If the range could not be locked because of protection
  4006. problems or noncommitted memory, the value (HANDLE)0
  4007. is returned.
  4008. Environment:
  4009. Kernel Mode.
  4010. --*/
  4011. {
  4012. return MiSecureVirtualMemory (Address, Size, ProbeMode, FALSE);
  4013. }
  4014. HANDLE
  4015. MiSecureVirtualMemory (
  4016. IN PVOID Address,
  4017. IN SIZE_T Size,
  4018. IN ULONG ProbeMode,
  4019. IN LOGICAL AddressSpaceMutexHeld
  4020. )
  4021. /*++
  4022. Routine Description:
  4023. This routine probes the requested address range and protects
  4024. the specified address range from having its protection made
  4025. more restricted and being deleted.
  4026. MmUnsecureVirtualMemory is used to allow the range to return
  4027. to a normal state.
  4028. Arguments:
  4029. Address - Supplies the base address to probe and secure.
  4030. Size - Supplies the size of the range to secure.
  4031. ProbeMode - Supplies one of PAGE_READONLY or PAGE_READWRITE.
  4032. AddressSpaceMutexHeld - Supplies TRUE if the mutex is already held, FALSE
  4033. if not.
  4034. Return Value:
  4035. Returns a handle to be used to unsecure the range.
  4036. If the range could not be locked because of protection
  4037. problems or noncommitted memory, the value (HANDLE)0
  4038. is returned.
  4039. Environment:
  4040. Kernel Mode.
  4041. --*/
  4042. {
  4043. PETHREAD Thread;
  4044. ULONG_PTR EndAddress;
  4045. PVOID StartAddress;
  4046. CHAR Temp;
  4047. ULONG Probe;
  4048. HANDLE Handle;
  4049. PMMVAD Vad;
  4050. PMMVAD VadParent;
  4051. PMMVAD_LONG NewVad;
  4052. PMMSECURE_ENTRY Secure;
  4053. PEPROCESS Process;
  4054. PMMPTE PointerPxe;
  4055. PMMPTE PointerPpe;
  4056. PMMPTE PointerPde;
  4057. PMMPTE PointerPte;
  4058. PMMPTE LastPte;
  4059. ULONG Waited;
  4060. #if defined(_WIN64)
  4061. ULONG_PTR PageSize;
  4062. #else
  4063. #define PageSize PAGE_SIZE
  4064. #endif
  4065. PAGED_CODE();
  4066. if ((ULONG_PTR)Address + Size > (ULONG_PTR)MM_HIGHEST_USER_ADDRESS || (ULONG_PTR)Address + Size <= (ULONG_PTR)Address) {
  4067. return NULL;
  4068. }
  4069. Handle = NULL;
  4070. Probe = (ProbeMode == PAGE_READONLY);
  4071. Thread = PsGetCurrentThread ();
  4072. Process = PsGetCurrentProcessByThread (Thread);
  4073. StartAddress = Address;
  4074. if (AddressSpaceMutexHeld == FALSE) {
  4075. LOCK_ADDRESS_SPACE (Process);
  4076. }
  4077. //
  4078. // Check for a private committed VAD first instead of probing to avoid all
  4079. // the page faults and zeroing. If we find one, then we run the PTEs
  4080. // instead.
  4081. //
  4082. if (Size >= 64 * 1024) {
  4083. EndAddress = (ULONG_PTR)StartAddress + Size - 1;
  4084. Vad = MiLocateAddress (StartAddress);
  4085. if (Vad == NULL) {
  4086. goto Return1;
  4087. }
  4088. if ((Vad->u.VadFlags.UserPhysicalPages == 1) ||
  4089. (Vad->u.VadFlags.LargePages == 1)) {
  4090. goto Return1;
  4091. }
  4092. if (Vad->u.VadFlags.MemCommit == 0) {
  4093. goto LongWay;
  4094. }
  4095. if (Vad->u.VadFlags.PrivateMemory == 0) {
  4096. goto LongWay;
  4097. }
  4098. if (Vad->u.VadFlags.PhysicalMapping == 1) {
  4099. goto LongWay;
  4100. }
  4101. ASSERT (Vad->u.VadFlags.Protection);
  4102. if ((MI_VA_TO_VPN (StartAddress) < Vad->StartingVpn) ||
  4103. (MI_VA_TO_VPN (EndAddress) > Vad->EndingVpn)) {
  4104. goto Return1;
  4105. }
  4106. if (Vad->u.VadFlags.Protection == MM_NOACCESS) {
  4107. goto LongWay;
  4108. }
  4109. if (ProbeMode == PAGE_READONLY) {
  4110. if (Vad->u.VadFlags.Protection > MM_EXECUTE_WRITECOPY) {
  4111. goto LongWay;
  4112. }
  4113. }
  4114. else {
  4115. if (Vad->u.VadFlags.Protection != MM_READWRITE &&
  4116. Vad->u.VadFlags.Protection != MM_EXECUTE_READWRITE) {
  4117. goto LongWay;
  4118. }
  4119. }
  4120. //
  4121. // Check individual page permissions.
  4122. //
  4123. PointerPde = MiGetPdeAddress (StartAddress);
  4124. PointerPpe = MiGetPteAddress (PointerPde);
  4125. PointerPxe = MiGetPdeAddress (PointerPde);
  4126. PointerPte = MiGetPteAddress (StartAddress);
  4127. LastPte = MiGetPteAddress ((PVOID)EndAddress);
  4128. LOCK_WS_UNSAFE (Process);
  4129. do {
  4130. while (MiDoesPxeExistAndMakeValid (PointerPxe,
  4131. Process,
  4132. MM_NOIRQL,
  4133. &Waited) == FALSE) {
  4134. //
  4135. // Extended page directory parent entry is empty, go
  4136. // to the next one.
  4137. //
  4138. PointerPxe += 1;
  4139. PointerPpe = MiGetVirtualAddressMappedByPte (PointerPxe);
  4140. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  4141. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  4142. if (PointerPte > LastPte) {
  4143. UNLOCK_WS_UNSAFE (Process);
  4144. goto EditVad;
  4145. }
  4146. }
  4147. #if (_MI_PAGING_LEVELS >= 4)
  4148. Waited = 0;
  4149. #endif
  4150. while (MiDoesPpeExistAndMakeValid (PointerPpe,
  4151. Process,
  4152. MM_NOIRQL,
  4153. &Waited) == FALSE) {
  4154. //
  4155. // Page directory parent entry is empty, go to the next one.
  4156. //
  4157. PointerPpe += 1;
  4158. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  4159. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  4160. if (PointerPte > LastPte) {
  4161. UNLOCK_WS_UNSAFE (Process);
  4162. goto EditVad;
  4163. }
  4164. #if (_MI_PAGING_LEVELS >= 4)
  4165. if (MiIsPteOnPdeBoundary (PointerPpe)) {
  4166. PointerPxe = MiGetPteAddress(PointerPpe);
  4167. Waited = 1;
  4168. goto restart;
  4169. }
  4170. #endif
  4171. }
  4172. #if (_MI_PAGING_LEVELS < 4)
  4173. Waited = 0;
  4174. #endif
  4175. while (MiDoesPdeExistAndMakeValid (PointerPde,
  4176. Process,
  4177. MM_NOIRQL,
  4178. &Waited) == FALSE) {
  4179. //
  4180. // This page directory entry is empty, go to the next one.
  4181. //
  4182. PointerPde += 1;
  4183. PointerPpe = MiGetPteAddress (PointerPde);
  4184. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  4185. if (PointerPte > LastPte) {
  4186. UNLOCK_WS_UNSAFE (Process);
  4187. goto EditVad;
  4188. }
  4189. #if (_MI_PAGING_LEVELS >= 3)
  4190. if (MiIsPteOnPdeBoundary (PointerPde)) {
  4191. PointerPxe = MiGetPteAddress(PointerPpe);
  4192. Waited = 1;
  4193. break;
  4194. }
  4195. #endif
  4196. }
  4197. #if (_MI_PAGING_LEVELS >= 4)
  4198. restart:
  4199. PointerPxe = PointerPxe; // satisfy the compiler
  4200. #endif
  4201. } while (Waited != 0);
  4202. while (PointerPte <= LastPte) {
  4203. if (MiIsPteOnPdeBoundary (PointerPte)) {
  4204. PointerPde = MiGetPteAddress (PointerPte);
  4205. PointerPpe = MiGetPteAddress (PointerPde);
  4206. PointerPxe = MiGetPdeAddress (PointerPde);
  4207. do {
  4208. while (MiDoesPxeExistAndMakeValid (PointerPxe,
  4209. Process,
  4210. MM_NOIRQL,
  4211. &Waited) == FALSE) {
  4212. //
  4213. // Page directory parent entry is empty, go to the next one.
  4214. //
  4215. PointerPxe += 1;
  4216. PointerPpe = MiGetVirtualAddressMappedByPte (PointerPxe);
  4217. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  4218. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  4219. if (PointerPte > LastPte) {
  4220. UNLOCK_WS_UNSAFE (Process);
  4221. goto EditVad;
  4222. }
  4223. }
  4224. #if (_MI_PAGING_LEVELS >= 4)
  4225. Waited = 0;
  4226. #endif
  4227. while (MiDoesPpeExistAndMakeValid (PointerPpe,
  4228. Process,
  4229. MM_NOIRQL,
  4230. &Waited) == FALSE) {
  4231. //
  4232. // Page directory parent entry is empty, go to the next one.
  4233. //
  4234. PointerPpe += 1;
  4235. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  4236. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  4237. if (PointerPte > LastPte) {
  4238. UNLOCK_WS_UNSAFE (Process);
  4239. goto EditVad;
  4240. }
  4241. #if (_MI_PAGING_LEVELS >= 4)
  4242. if (MiIsPteOnPdeBoundary (PointerPpe)) {
  4243. PointerPxe = MiGetPteAddress (PointerPpe);
  4244. Waited = 1;
  4245. goto restart2;
  4246. }
  4247. #endif
  4248. }
  4249. #if (_MI_PAGING_LEVELS < 4)
  4250. Waited = 0;
  4251. #endif
  4252. while (MiDoesPdeExistAndMakeValid (PointerPde,
  4253. Process,
  4254. MM_NOIRQL,
  4255. &Waited) == FALSE) {
  4256. //
  4257. // This page directory entry is empty, go to the next one.
  4258. //
  4259. PointerPde += 1;
  4260. PointerPpe = MiGetPteAddress (PointerPde);
  4261. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  4262. if (PointerPte > LastPte) {
  4263. UNLOCK_WS_UNSAFE (Process);
  4264. goto EditVad;
  4265. }
  4266. #if (_MI_PAGING_LEVELS >= 3)
  4267. if (MiIsPteOnPdeBoundary (PointerPde)) {
  4268. PointerPxe = MiGetPteAddress (PointerPpe);
  4269. Waited = 1;
  4270. break;
  4271. }
  4272. #endif
  4273. }
  4274. #if (_MI_PAGING_LEVELS >= 4)
  4275. restart2:
  4276. PointerPxe = PointerPxe; // satisfy the compiler
  4277. #endif
  4278. } while (Waited != 0);
  4279. }
  4280. if (PointerPte->u.Long) {
  4281. UNLOCK_WS_UNSAFE (Process);
  4282. goto LongWay;
  4283. }
  4284. PointerPte += 1;
  4285. }
  4286. UNLOCK_WS_UNSAFE (Process);
  4287. }
  4288. else {
  4289. LongWay:
  4290. //
  4291. // Mark this thread as the address space mutex owner so it cannot
  4292. // sneak its stack in as the argument region and trick us into
  4293. // trying to grow it if the reference faults (as this would cause
  4294. // a deadlock since this thread already owns the address space mutex).
  4295. // Note this would have the side effect of not allowing this thread
  4296. // to fault on guard pages in other data regions while the accesses
  4297. // below are ongoing - but that could only happen in an APC and
  4298. // those are blocked right now anyway.
  4299. //
  4300. ASSERT (KeAreAllApcsDisabled () == TRUE);
  4301. ASSERT (Thread->AddressSpaceOwner == 0);
  4302. Thread->AddressSpaceOwner = 1;
  4303. #if defined(_WIN64)
  4304. if (Process->Wow64Process != NULL) {
  4305. PageSize = PAGE_SIZE_X86NT;
  4306. } else {
  4307. PageSize = PAGE_SIZE;
  4308. }
  4309. #endif
  4310. try {
  4311. if (ProbeMode == PAGE_READONLY) {
  4312. EndAddress = (ULONG_PTR)Address + Size - 1;
  4313. EndAddress = (EndAddress & ~(PageSize - 1)) + PageSize;
  4314. do {
  4315. Temp = *(volatile CHAR *)Address;
  4316. Address = (PVOID)(((ULONG_PTR)Address & ~(PageSize - 1)) + PageSize);
  4317. } while ((ULONG_PTR)Address != EndAddress);
  4318. }
  4319. else {
  4320. ProbeForWrite (Address, Size, 1);
  4321. }
  4322. } except (EXCEPTION_EXECUTE_HANDLER) {
  4323. ASSERT (KeAreAllApcsDisabled () == TRUE);
  4324. ASSERT (Thread->AddressSpaceOwner == 1);
  4325. Thread->AddressSpaceOwner = 0;
  4326. goto Return1;
  4327. }
  4328. ASSERT (KeAreAllApcsDisabled () == TRUE);
  4329. ASSERT (Thread->AddressSpaceOwner == 1);
  4330. Thread->AddressSpaceOwner = 0;
  4331. //
  4332. // Locate VAD and add in secure descriptor.
  4333. //
  4334. EndAddress = (ULONG_PTR)StartAddress + Size - 1;
  4335. Vad = MiLocateAddress (StartAddress);
  4336. if (Vad == NULL) {
  4337. goto Return1;
  4338. }
  4339. if ((Vad->u.VadFlags.UserPhysicalPages == 1) ||
  4340. (Vad->u.VadFlags.LargePages == 1)) {
  4341. goto Return1;
  4342. }
  4343. if ((MI_VA_TO_VPN (StartAddress) < Vad->StartingVpn) ||
  4344. (MI_VA_TO_VPN (EndAddress) > Vad->EndingVpn)) {
  4345. //
  4346. // Not within the section virtual address descriptor,
  4347. // return an error.
  4348. //
  4349. goto Return1;
  4350. }
  4351. }
  4352. EditVad:
  4353. //
  4354. // If this is a short or regular VAD, it needs to be reallocated as
  4355. // a large VAD. Note that a short VAD that was previously converted
  4356. // to a long VAD here will still be marked as private memory, thus to
  4357. // handle this case the NoChange bit must also be tested.
  4358. //
  4359. if (((Vad->u.VadFlags.PrivateMemory) && (Vad->u.VadFlags.NoChange == 0))
  4360. ||
  4361. (Vad->u2.VadFlags2.LongVad == 0)) {
  4362. if (Vad->u.VadFlags.PrivateMemory == 0) {
  4363. ASSERT (Vad->u2.VadFlags2.OneSecured == 0);
  4364. ASSERT (Vad->u2.VadFlags2.MultipleSecured == 0);
  4365. }
  4366. NewVad = ExAllocatePoolWithTag (NonPagedPool,
  4367. sizeof(MMVAD_LONG),
  4368. 'ldaV');
  4369. if (NewVad == NULL) {
  4370. goto Return1;
  4371. }
  4372. RtlZeroMemory (NewVad, sizeof(MMVAD_LONG));
  4373. if (Vad->u.VadFlags.PrivateMemory) {
  4374. RtlCopyMemory (NewVad, Vad, sizeof(MMVAD_SHORT));
  4375. }
  4376. else {
  4377. RtlCopyMemory (NewVad, Vad, sizeof(MMVAD));
  4378. }
  4379. NewVad->u.VadFlags.NoChange = 1;
  4380. NewVad->u2.VadFlags2.OneSecured = 1;
  4381. NewVad->u2.VadFlags2.LongVad = 1;
  4382. NewVad->u2.VadFlags2.ReadOnly = Probe;
  4383. NewVad->u3.Secured.StartVpn = (ULONG_PTR)StartAddress;
  4384. NewVad->u3.Secured.EndVpn = EndAddress;
  4385. //
  4386. // Replace the current VAD with this expanded VAD.
  4387. //
  4388. LOCK_WS_UNSAFE (Process);
  4389. VadParent = (PMMVAD) SANITIZE_PARENT_NODE (Vad->u1.Parent);
  4390. ASSERT (VadParent != NULL);
  4391. if (VadParent != Vad) {
  4392. if (VadParent->RightChild == Vad) {
  4393. VadParent->RightChild = (PMMVAD) NewVad;
  4394. }
  4395. else {
  4396. ASSERT (VadParent->LeftChild == Vad);
  4397. VadParent->LeftChild = (PMMVAD) NewVad;
  4398. }
  4399. }
  4400. else {
  4401. Process->VadRoot.BalancedRoot.RightChild = (PMMADDRESS_NODE) NewVad;
  4402. }
  4403. if (Vad->LeftChild) {
  4404. Vad->LeftChild->u1.Parent = (PMMVAD) MI_MAKE_PARENT (NewVad, Vad->LeftChild->u1.Balance);
  4405. }
  4406. if (Vad->RightChild) {
  4407. Vad->RightChild->u1.Parent = (PMMVAD) MI_MAKE_PARENT (NewVad, Vad->RightChild->u1.Balance);
  4408. }
  4409. if (Process->VadRoot.NodeHint == Vad) {
  4410. Process->VadRoot.NodeHint = (PMMVAD) NewVad;
  4411. }
  4412. if (Process->VadFreeHint == Vad) {
  4413. Process->VadFreeHint = (PMMVAD) NewVad;
  4414. }
  4415. if ((Vad->u.VadFlags.PhysicalMapping == 1) ||
  4416. (Vad->u.VadFlags.WriteWatch == 1)) {
  4417. MiPhysicalViewAdjuster (Process, Vad, (PMMVAD) NewVad);
  4418. }
  4419. UNLOCK_WS_UNSAFE (Process);
  4420. if (AddressSpaceMutexHeld == FALSE) {
  4421. UNLOCK_ADDRESS_SPACE (Process);
  4422. }
  4423. ExFreePool (Vad);
  4424. //
  4425. // Or in the low bit to denote the secure entry is in the VAD.
  4426. //
  4427. Handle = (HANDLE)((ULONG_PTR)&NewVad->u2.LongFlags2 | 0x1);
  4428. return Handle;
  4429. }
  4430. //
  4431. // This is already a large VAD, add the secure entry.
  4432. //
  4433. ASSERT (Vad->u2.VadFlags2.LongVad == 1);
  4434. if (Vad->u2.VadFlags2.OneSecured) {
  4435. //
  4436. // This VAD already is secured. Move the info out of the
  4437. // block into pool.
  4438. //
  4439. Secure = ExAllocatePoolWithTag (NonPagedPool,
  4440. sizeof (MMSECURE_ENTRY),
  4441. 'eSmM');
  4442. if (Secure == NULL) {
  4443. goto Return1;
  4444. }
  4445. ASSERT (Vad->u.VadFlags.NoChange == 1);
  4446. Vad->u2.VadFlags2.OneSecured = 0;
  4447. Vad->u2.VadFlags2.MultipleSecured = 1;
  4448. Secure->u2.LongFlags2 = (ULONG) Vad->u.LongFlags;
  4449. Secure->StartVpn = ((PMMVAD_LONG) Vad)->u3.Secured.StartVpn;
  4450. Secure->EndVpn = ((PMMVAD_LONG) Vad)->u3.Secured.EndVpn;
  4451. InitializeListHead (&((PMMVAD_LONG)Vad)->u3.List);
  4452. InsertTailList (&((PMMVAD_LONG)Vad)->u3.List, &Secure->List);
  4453. }
  4454. if (Vad->u2.VadFlags2.MultipleSecured) {
  4455. //
  4456. // This VAD already has a secured element in its list, allocate and
  4457. // add in the new secured element.
  4458. //
  4459. Secure = ExAllocatePoolWithTag (NonPagedPool,
  4460. sizeof (MMSECURE_ENTRY),
  4461. 'eSmM');
  4462. if (Secure == NULL) {
  4463. goto Return1;
  4464. }
  4465. Secure->u2.LongFlags2 = 0;
  4466. Secure->u2.VadFlags2.ReadOnly = Probe;
  4467. Secure->StartVpn = (ULONG_PTR)StartAddress;
  4468. Secure->EndVpn = EndAddress;
  4469. InsertTailList (&((PMMVAD_LONG)Vad)->u3.List, &Secure->List);
  4470. Handle = (HANDLE)Secure;
  4471. }
  4472. else {
  4473. //
  4474. // This list does not have a secure element. Put it in the VAD.
  4475. // The VAD may be either a regular VAD or a long VAD (it cannot be
  4476. // a short VAD) at this point. If it is a regular VAD, it must be
  4477. // reallocated as a long VAD before any operation can proceed so
  4478. // the secured range can be inserted.
  4479. //
  4480. Vad->u.VadFlags.NoChange = 1;
  4481. Vad->u2.VadFlags2.OneSecured = 1;
  4482. Vad->u2.VadFlags2.ReadOnly = Probe;
  4483. ((PMMVAD_LONG)Vad)->u3.Secured.StartVpn = (ULONG_PTR)StartAddress;
  4484. ((PMMVAD_LONG)Vad)->u3.Secured.EndVpn = EndAddress;
  4485. //
  4486. // Or in the low bit to denote the secure entry is in the VAD.
  4487. //
  4488. Handle = (HANDLE)((ULONG_PTR)&Vad->u2.LongFlags2 | 0x1);
  4489. }
  4490. Return1:
  4491. if (AddressSpaceMutexHeld == FALSE) {
  4492. UNLOCK_ADDRESS_SPACE (Process);
  4493. }
  4494. return Handle;
  4495. }
  4496. VOID
  4497. MmUnsecureVirtualMemory (
  4498. IN HANDLE SecureHandle
  4499. )
  4500. /*++
  4501. Routine Description:
  4502. This routine unsecures memory previously secured via a call to
  4503. MmSecureVirtualMemory.
  4504. Arguments:
  4505. SecureHandle - Supplies the handle returned in MmSecureVirtualMemory.
  4506. Return Value:
  4507. None.
  4508. Environment:
  4509. Kernel Mode.
  4510. --*/
  4511. {
  4512. MiUnsecureVirtualMemory (SecureHandle, FALSE);
  4513. }
  4514. VOID
  4515. MiUnsecureVirtualMemory (
  4516. IN HANDLE SecureHandle,
  4517. IN LOGICAL AddressSpaceMutexHeld
  4518. )
  4519. /*++
  4520. Routine Description:
  4521. This routine unsecures memory previously secured via a call to
  4522. MmSecureVirtualMemory.
  4523. Arguments:
  4524. SecureHandle - Supplies the handle returned in MmSecureVirtualMemory.
  4525. AddressSpaceMutexHeld - Supplies TRUE if the mutex is already held, FALSE
  4526. if not.
  4527. Return Value:
  4528. None.
  4529. Environment:
  4530. Kernel Mode.
  4531. --*/
  4532. {
  4533. PMMSECURE_ENTRY Secure;
  4534. PEPROCESS Process;
  4535. PMMVAD_LONG Vad;
  4536. PAGED_CODE();
  4537. Secure = (PMMSECURE_ENTRY)SecureHandle;
  4538. Process = PsGetCurrentProcess ();
  4539. if (AddressSpaceMutexHeld == FALSE) {
  4540. LOCK_ADDRESS_SPACE (Process);
  4541. }
  4542. if ((ULONG_PTR)Secure & 0x1) {
  4543. Secure = (PMMSECURE_ENTRY) ((ULONG_PTR)Secure & ~0x1);
  4544. Vad = CONTAINING_RECORD (Secure,
  4545. MMVAD_LONG,
  4546. u2.LongFlags2);
  4547. }
  4548. else {
  4549. Vad = (PMMVAD_LONG) MiLocateAddress ((PVOID)Secure->StartVpn);
  4550. }
  4551. ASSERT (Vad);
  4552. ASSERT (Vad->u.VadFlags.NoChange == 1);
  4553. ASSERT (Vad->u2.VadFlags2.LongVad == 1);
  4554. if (Vad->u2.VadFlags2.OneSecured) {
  4555. ASSERT (Secure == (PMMSECURE_ENTRY)&Vad->u2.LongFlags2);
  4556. Vad->u2.VadFlags2.OneSecured = 0;
  4557. ASSERT (Vad->u2.VadFlags2.MultipleSecured == 0);
  4558. if (Vad->u2.VadFlags2.SecNoChange == 0) {
  4559. //
  4560. // No more secure entries in this list, remove the state.
  4561. //
  4562. Vad->u.VadFlags.NoChange = 0;
  4563. }
  4564. if (AddressSpaceMutexHeld == FALSE) {
  4565. UNLOCK_ADDRESS_SPACE (Process);
  4566. }
  4567. }
  4568. else {
  4569. ASSERT (Vad->u2.VadFlags2.MultipleSecured == 1);
  4570. if (Secure == (PMMSECURE_ENTRY)&Vad->u2.LongFlags2) {
  4571. //
  4572. // This was a single block that got converted into a list.
  4573. // Reset the entry.
  4574. //
  4575. Secure = CONTAINING_RECORD (Vad->u3.List.Flink,
  4576. MMSECURE_ENTRY,
  4577. List);
  4578. }
  4579. RemoveEntryList (&Secure->List);
  4580. if (IsListEmpty (&Vad->u3.List)) {
  4581. //
  4582. // No more secure entries, reset the state.
  4583. //
  4584. Vad->u2.VadFlags2.MultipleSecured = 0;
  4585. if ((Vad->u2.VadFlags2.SecNoChange == 0) &&
  4586. (Vad->u.VadFlags.PrivateMemory == 0)) {
  4587. //
  4588. // No more secure entries in this list, remove the state
  4589. // if and only if this VAD is not private. If this VAD
  4590. // is private, removing the state NoChange flag indicates
  4591. // that this is a short VAD which it no longer is.
  4592. //
  4593. Vad->u.VadFlags.NoChange = 0;
  4594. }
  4595. }
  4596. if (AddressSpaceMutexHeld == FALSE) {
  4597. UNLOCK_ADDRESS_SPACE (Process);
  4598. }
  4599. ExFreePool (Secure);
  4600. }
  4601. return;
  4602. }
  4603. #if DBG
  4604. VOID
  4605. MiDumpConflictingVad (
  4606. IN PVOID StartingAddress,
  4607. IN PVOID EndingAddress,
  4608. IN PMMVAD Vad
  4609. )
  4610. {
  4611. if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) {
  4612. DbgPrint( "MM: [%p ... %p) conflicted with Vad %p\n",
  4613. StartingAddress, EndingAddress, Vad);
  4614. if ((Vad->u.VadFlags.PrivateMemory == 1) ||
  4615. (Vad->ControlArea == NULL)) {
  4616. return;
  4617. }
  4618. if (Vad->ControlArea->u.Flags.Image)
  4619. DbgPrint( " conflict with %Z image at [%p .. %p)\n",
  4620. &Vad->ControlArea->FilePointer->FileName,
  4621. MI_VPN_TO_VA (Vad->StartingVpn),
  4622. MI_VPN_TO_VA_ENDING (Vad->EndingVpn)
  4623. );
  4624. else
  4625. if (Vad->ControlArea->u.Flags.File)
  4626. DbgPrint( " conflict with %Z file at [%p .. %p)\n",
  4627. &Vad->ControlArea->FilePointer->FileName,
  4628. MI_VPN_TO_VA (Vad->StartingVpn),
  4629. MI_VPN_TO_VA_ENDING (Vad->EndingVpn)
  4630. );
  4631. else
  4632. DbgPrint( " conflict with section at [%p .. %p)\n",
  4633. MI_VPN_TO_VA (Vad->StartingVpn),
  4634. MI_VPN_TO_VA_ENDING (Vad->EndingVpn)
  4635. );
  4636. }
  4637. }
  4638. #endif