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

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