Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3206 lines
104 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. forksup.c
  5. Abstract:
  6. This module contains the routines which support the POSIX fork operation.
  7. Author:
  8. Lou Perazzoli (loup) 22-Jul-1989
  9. Landy Wang (landyw) 02-June-1997
  10. Revision History:
  11. --*/
  12. #include "mi.h"
  13. VOID
  14. MiUpControlAreaRefs (
  15. IN PMMVAD Vad
  16. );
  17. ULONG
  18. MiDoneWithThisPageGetAnother (
  19. IN PPFN_NUMBER PageFrameIndex,
  20. IN PMMPTE PointerPde,
  21. IN PEPROCESS CurrentProcess
  22. );
  23. ULONG
  24. MiLeaveThisPageGetAnother (
  25. OUT PPFN_NUMBER PageFrameIndex,
  26. IN PMMPTE PointerPde,
  27. IN PEPROCESS CurrentProcess
  28. );
  29. VOID
  30. MiUpForkPageShareCount (
  31. IN PMMPFN PfnForkPtePage
  32. );
  33. ULONG
  34. MiHandleForkTransitionPte (
  35. IN PMMPTE PointerPte,
  36. IN PMMPTE PointerNewPte,
  37. IN PMMCLONE_BLOCK ForkProtoPte
  38. );
  39. VOID
  40. MiDownShareCountFlushEntireTb (
  41. IN PFN_NUMBER PageFrameIndex
  42. );
  43. VOID
  44. MiBuildForkPageTable (
  45. IN PFN_NUMBER PageFrameIndex,
  46. IN PMMPTE PointerPde,
  47. IN PMMPTE PointerNewPde,
  48. IN PFN_NUMBER PdePhysicalPage,
  49. IN PMMPFN PfnPdPage,
  50. IN LOGICAL MakeValid
  51. );
  52. #define MM_FORK_SUCCEEDED 0
  53. #define MM_FORK_FAILED 1
  54. #ifdef ALLOC_PRAGMA
  55. #pragma alloc_text(PAGE,MiCloneProcessAddressSpace)
  56. #endif
  57. NTSTATUS
  58. MiCloneProcessAddressSpace (
  59. IN PEPROCESS ProcessToClone,
  60. IN PEPROCESS ProcessToInitialize
  61. )
  62. /*++
  63. Routine Description:
  64. This routine stands on its head to produce a copy of the specified
  65. process's address space in the process to initialize. This
  66. is done by examining each virtual address descriptor's inherit
  67. attributes. If the pages described by the VAD should be inherited,
  68. each PTE is examined and copied into the new address space.
  69. For private pages, fork prototype PTEs are constructed and the pages
  70. become shared, copy-on-write, between the two processes.
  71. Arguments:
  72. ProcessToClone - Supplies the process whose address space should be
  73. cloned.
  74. ProcessToInitialize - Supplies the process whose address space is to
  75. be created.
  76. Return Value:
  77. None.
  78. Environment:
  79. Kernel mode, APCs disabled. No VADs exist for the new process on entry
  80. and the new process is not on the working set expansion links list so
  81. it cannot be trimmed (or outswapped). Hence none of the pages in the
  82. new process need to be locked down.
  83. --*/
  84. {
  85. LOGICAL ChargedClonePoolQuota;
  86. PAWEINFO AweInfo;
  87. PVOID RestartKey;
  88. PFN_NUMBER PdePhysicalPage;
  89. PEPROCESS CurrentProcess;
  90. PMMPTE PdeBase;
  91. PMMCLONE_HEADER CloneHeader;
  92. PMMCLONE_BLOCK CloneProtos;
  93. PMMCLONE_DESCRIPTOR CloneDescriptor;
  94. PMM_AVL_TABLE CloneRoot;
  95. PMM_AVL_TABLE TargetCloneRoot;
  96. PFN_NUMBER RootPhysicalPage;
  97. PMMVAD NewVad;
  98. PMMVAD Vad;
  99. PMMVAD NextVad;
  100. PMMVAD *VadList;
  101. PMMVAD FirstNewVad;
  102. PMMCLONE_DESCRIPTOR *CloneList;
  103. PMMCLONE_DESCRIPTOR FirstNewClone;
  104. PMMCLONE_DESCRIPTOR Clone;
  105. PMMCLONE_DESCRIPTOR NextClone;
  106. PMMCLONE_DESCRIPTOR NewClone;
  107. ULONG Attached;
  108. ULONG CloneFailed;
  109. ULONG VadInsertFailed;
  110. WSLE_NUMBER WorkingSetIndex;
  111. PVOID VirtualAddress;
  112. NTSTATUS status;
  113. PMMPFN Pfn2;
  114. PMMPFN PfnPdPage;
  115. MMPTE TempPte;
  116. MMPTE PteContents;
  117. KAPC_STATE ApcState;
  118. ULONG i;
  119. #if defined (_X86PAE_)
  120. PMDL MdlPageDirectory;
  121. PFN_NUMBER PageDirectoryFrames[PD_PER_SYSTEM];
  122. PFN_NUMBER MdlHackPageDirectory[(sizeof(MDL)/sizeof(PFN_NUMBER)) + PD_PER_SYSTEM];
  123. #else
  124. PFN_NUMBER MdlDirPage;
  125. #endif
  126. PMMPTE PointerPte;
  127. PMMPTE PointerPde;
  128. PMMPTE PointerPpe;
  129. PMMPTE PointerPxe;
  130. PMMPTE LastPte;
  131. PMMPTE LastPde;
  132. PMMPTE PointerNewPte;
  133. PMMPTE NewPteMappedAddress;
  134. PMMPTE PointerNewPde;
  135. PMI_PHYSICAL_VIEW PhysicalView;
  136. PMI_PHYSICAL_VIEW NextPhysicalView;
  137. PMI_PHYSICAL_VIEW PhysicalViewList;
  138. ULONG PhysicalViewCount;
  139. PFN_NUMBER PageFrameIndex;
  140. PMMCLONE_BLOCK ForkProtoPte;
  141. PMMCLONE_BLOCK CloneProto;
  142. PMMCLONE_BLOCK LockedForkPte;
  143. PMMPTE ContainingPte;
  144. ULONG NumberOfForkPtes;
  145. PFN_NUMBER NumberOfPrivatePages;
  146. SIZE_T TotalPagedPoolCharge;
  147. SIZE_T TotalNonPagedPoolCharge;
  148. PMMPFN PfnForkPtePage;
  149. PVOID UsedPageTableEntries;
  150. ULONG ReleasedWorkingSetMutex;
  151. ULONG FirstTime;
  152. ULONG Waited;
  153. ULONG PpePdeOffset;
  154. PFN_NUMBER HyperPhysicalPage;
  155. #if defined (_MIALT4K_)
  156. PVOID TempAliasInformation;
  157. #endif
  158. #if (_MI_PAGING_LEVELS >= 3)
  159. PMMPTE PointerPpeLast;
  160. PFN_NUMBER PageDirFrameIndex;
  161. PVOID UsedPageDirectoryEntries;
  162. PMMPTE PointerNewPpe;
  163. PMMPTE PpeBase;
  164. PMMPFN PfnPpPage;
  165. #if (_MI_PAGING_LEVELS >= 4)
  166. PVOID UsedPageDirectoryParentEntries;
  167. PFN_NUMBER PpePhysicalPage;
  168. PFN_NUMBER PageParentFrameIndex;
  169. PMMPTE PointerNewPxe;
  170. PMMPTE PxeBase;
  171. PMMPFN PfnPxPage;
  172. PFN_NUMBER MdlDirParentPage;
  173. #endif
  174. #else
  175. PMMWSL HyperBase = NULL;
  176. PMMWSL HyperWsl;
  177. #endif
  178. PAGED_CODE();
  179. HyperPhysicalPage = ProcessToInitialize->WorkingSetPage;
  180. NumberOfForkPtes = 0;
  181. Attached = FALSE;
  182. PageFrameIndex = (PFN_NUMBER)-1;
  183. PhysicalViewList = NULL;
  184. PhysicalViewCount = 0;
  185. FirstNewVad = NULL;
  186. CloneHeader = NULL;
  187. CloneProtos = NULL;
  188. CloneDescriptor = NULL;
  189. CloneRoot = NULL;
  190. TargetCloneRoot = NULL;
  191. ChargedClonePoolQuota = FALSE;
  192. if (ProcessToClone != PsGetCurrentProcess()) {
  193. Attached = TRUE;
  194. KeStackAttachProcess (&ProcessToClone->Pcb, &ApcState);
  195. }
  196. #if defined (_X86PAE_)
  197. PointerPte = (PMMPTE) ProcessToInitialize->PaeTop;
  198. for (i = 0; i < PD_PER_SYSTEM; i += 1) {
  199. PageDirectoryFrames[i] = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
  200. PointerPte += 1;
  201. }
  202. RootPhysicalPage = PageDirectoryFrames[PD_PER_SYSTEM - 1];
  203. #else
  204. RootPhysicalPage = ProcessToInitialize->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT;
  205. #endif
  206. CurrentProcess = ProcessToClone;
  207. //
  208. // Get the working set mutex and the address creation mutex
  209. // of the process to clone. This prevents page faults while we
  210. // are examining the address map and prevents virtual address space
  211. // from being created or deleted.
  212. //
  213. LOCK_ADDRESS_SPACE (CurrentProcess);
  214. //
  215. // Make sure the address space was not deleted, if so, return an error.
  216. //
  217. if (CurrentProcess->Flags & PS_PROCESS_FLAGS_VM_DELETED) {
  218. status = STATUS_PROCESS_IS_TERMINATING;
  219. goto ErrorReturn1;
  220. }
  221. //
  222. // Check for AWE, write watch and large page regions as they are not
  223. // duplicated so fork is not allowed. Note that since this is a
  224. // readonly list walk, the address space mutex is sufficient to
  225. // synchronize properly.
  226. //
  227. if (CurrentProcess->PhysicalVadRoot != NULL) {
  228. RestartKey = NULL;
  229. #if 1
  230. //
  231. // Don't allow cloning of any processes with physical VADs of
  232. // any sort. This is to prevent drivers that map nonpaged pool
  233. // into user space from creating security/corruption holes if
  234. // the application clones because drivers wouldn't know how
  235. // to clean up (destroy) all the views prior to freeing the pool.
  236. //
  237. if (MiEnumerateGenericTableWithoutSplayingAvl (CurrentProcess->PhysicalVadRoot, &RestartKey) != NULL) {
  238. status = STATUS_INVALID_PAGE_PROTECTION;
  239. goto ErrorReturn1;
  240. }
  241. #else
  242. do {
  243. PhysicalView = (PMI_PHYSICAL_VIEW) MiEnumerateGenericTableWithoutSplayingAvl (CurrentProcess->PhysicalVadRoot, &RestartKey);
  244. if (PhysicalView == NULL) {
  245. break;
  246. }
  247. if (PhysicalView->u.LongFlags != MI_PHYSICAL_VIEW_PHYS) {
  248. status = STATUS_INVALID_PAGE_PROTECTION;
  249. goto ErrorReturn1;
  250. }
  251. if ((PhysicalView->Vad->u.VadFlags.PrivateMemory == 1) ||
  252. (PhysicalView->Vad->u2.VadFlags2.Inherit == MM_VIEW_SHARE)) {
  253. PhysicalViewCount += 1;
  254. }
  255. } while (TRUE);
  256. #endif
  257. }
  258. AweInfo = (PAWEINFO) CurrentProcess->AweInfo;
  259. if (AweInfo != NULL) {
  260. RestartKey = NULL;
  261. do {
  262. PhysicalView = (PMI_PHYSICAL_VIEW) MiEnumerateGenericTableWithoutSplayingAvl (&AweInfo->AweVadRoot, &RestartKey);
  263. if (PhysicalView == NULL) {
  264. break;
  265. }
  266. if (PhysicalView->u.LongFlags != MI_PHYSICAL_VIEW_PHYS) {
  267. status = STATUS_INVALID_PAGE_PROTECTION;
  268. goto ErrorReturn1;
  269. }
  270. } while (TRUE);
  271. }
  272. //
  273. // Attempt to acquire the needed pool before starting the
  274. // clone operation, this allows an easier failure path in
  275. // the case of insufficient system resources. The working set mutex
  276. // must be acquired (and held throughout) to protect against modifications
  277. // to the NumberOfPrivatePages field in the EPROCESS.
  278. //
  279. #if defined (_MIALT4K_)
  280. if (CurrentProcess->Wow64Process != NULL) {
  281. LOCK_ALTERNATE_TABLE_UNSAFE (CurrentProcess->Wow64Process);
  282. }
  283. #endif
  284. LOCK_WS (CurrentProcess);
  285. ASSERT (CurrentProcess->ForkInProgress == NULL);
  286. //
  287. // Indicate to the pager that the current process is being
  288. // forked. This blocks other threads in that process from
  289. // modifying clone block counts and contents as well as alternate PTEs.
  290. //
  291. CurrentProcess->ForkInProgress = PsGetCurrentThread ();
  292. #if defined (_MIALT4K_)
  293. if (CurrentProcess->Wow64Process != NULL) {
  294. UNLOCK_ALTERNATE_TABLE_UNSAFE (CurrentProcess->Wow64Process);
  295. }
  296. #endif
  297. NumberOfPrivatePages = CurrentProcess->NumberOfPrivatePages;
  298. TargetCloneRoot = ExAllocatePoolWithTag (NonPagedPool,
  299. sizeof(MM_AVL_TABLE),
  300. 'rCmM');
  301. if (TargetCloneRoot == NULL) {
  302. status = STATUS_INSUFFICIENT_RESOURCES;
  303. goto ErrorReturn2;
  304. }
  305. RtlZeroMemory (TargetCloneRoot, sizeof(MM_AVL_TABLE));
  306. TargetCloneRoot->BalancedRoot.u1.Parent = MI_MAKE_PARENT (&TargetCloneRoot->BalancedRoot, 0);
  307. //
  308. // Only allocate a clone root for the calling process if he doesn't
  309. // already have one (ie: this is his first fork call). Note that if
  310. // the allocation succeeds, the root table remains until the process
  311. // exits regardless of whether the fork succeeds.
  312. //
  313. if (CurrentProcess->CloneRoot == NULL) {
  314. CloneRoot = ExAllocatePoolWithTag (NonPagedPool,
  315. sizeof(MM_AVL_TABLE),
  316. 'rCmM');
  317. if (CloneRoot == NULL) {
  318. status = STATUS_INSUFFICIENT_RESOURCES;
  319. goto ErrorReturn2;
  320. }
  321. RtlZeroMemory (CloneRoot, sizeof(MM_AVL_TABLE));
  322. CloneRoot->BalancedRoot.u1.Parent = MI_MAKE_PARENT (&CloneRoot->BalancedRoot, 0);
  323. CurrentProcess->CloneRoot = CloneRoot;
  324. }
  325. CloneProtos = ExAllocatePoolWithTag (PagedPool, sizeof(MMCLONE_BLOCK) *
  326. NumberOfPrivatePages,
  327. 'lCmM');
  328. if (CloneProtos == NULL) {
  329. status = STATUS_INSUFFICIENT_RESOURCES;
  330. goto ErrorReturn2;
  331. }
  332. CloneHeader = ExAllocatePoolWithTag (NonPagedPool,
  333. sizeof(MMCLONE_HEADER),
  334. 'hCmM');
  335. if (CloneHeader == NULL) {
  336. status = STATUS_INSUFFICIENT_RESOURCES;
  337. goto ErrorReturn2;
  338. }
  339. CloneDescriptor = ExAllocatePoolWithTag (NonPagedPool,
  340. sizeof(MMCLONE_DESCRIPTOR),
  341. 'dCmM');
  342. if (CloneDescriptor == NULL) {
  343. status = STATUS_INSUFFICIENT_RESOURCES;
  344. goto ErrorReturn2;
  345. }
  346. //
  347. // Charge the current process the quota for the paged and nonpaged
  348. // global structures. This consists of the array of clone blocks
  349. // in paged pool and the clone header in non-paged pool.
  350. //
  351. status = PsChargeProcessPagedPoolQuota (CurrentProcess,
  352. sizeof(MMCLONE_BLOCK) * NumberOfPrivatePages);
  353. if (!NT_SUCCESS(status)) {
  354. //
  355. // Unable to charge quota for the clone blocks.
  356. //
  357. goto ErrorReturn2;
  358. }
  359. status = PsChargeProcessNonPagedPoolQuota (CurrentProcess,
  360. sizeof(MMCLONE_HEADER));
  361. if (!NT_SUCCESS(status)) {
  362. //
  363. // Unable to charge quota for the clone header.
  364. //
  365. PsReturnProcessPagedPoolQuota (CurrentProcess,
  366. sizeof(MMCLONE_BLOCK) * NumberOfPrivatePages);
  367. goto ErrorReturn2;
  368. }
  369. ChargedClonePoolQuota = TRUE;
  370. Vad = MiGetFirstVad (CurrentProcess);
  371. VadList = &FirstNewVad;
  372. if (PhysicalViewCount != 0) {
  373. PMM_AVL_TABLE PhysicalVadRoot;
  374. PhysicalVadRoot = ProcessToInitialize->PhysicalVadRoot;
  375. //
  376. // The address space mutex synchronizes the allocation of the
  377. // EPROCESS PhysicalVadRoot but is not needed here because no one
  378. // can be manipulating the target process except this thread.
  379. // This table root is not deleted until the process exits.
  380. //
  381. if (PhysicalVadRoot == NULL) {
  382. PhysicalVadRoot = (PMM_AVL_TABLE) ExAllocatePoolWithTag (
  383. NonPagedPool,
  384. sizeof (MM_AVL_TABLE),
  385. MI_PHYSICAL_VIEW_ROOT_KEY);
  386. if (PhysicalVadRoot == NULL) {
  387. status = STATUS_INSUFFICIENT_RESOURCES;
  388. goto ErrorReturn2;
  389. }
  390. RtlZeroMemory (PhysicalVadRoot, sizeof (MM_AVL_TABLE));
  391. ASSERT (PhysicalVadRoot->NumberGenericTableElements == 0);
  392. PhysicalVadRoot->BalancedRoot.u1.Parent = &PhysicalVadRoot->BalancedRoot;
  393. MiInsertPhysicalVadRoot (ProcessToInitialize, PhysicalVadRoot);
  394. }
  395. i = PhysicalViewCount;
  396. do {
  397. PhysicalView = (PMI_PHYSICAL_VIEW) ExAllocatePoolWithTag (
  398. NonPagedPool,
  399. sizeof(MI_PHYSICAL_VIEW),
  400. MI_PHYSICAL_VIEW_KEY);
  401. if (PhysicalView == NULL) {
  402. status = STATUS_INSUFFICIENT_RESOURCES;
  403. goto ErrorReturn2;
  404. }
  405. PhysicalView->u1.Parent = (PMMADDRESS_NODE) PhysicalViewList;
  406. PhysicalViewList = PhysicalView;
  407. i -= 1;
  408. } while (i != 0);
  409. }
  410. while (Vad != NULL) {
  411. //
  412. // If the VAD does not go to the child, ignore it.
  413. //
  414. if ((Vad->u.VadFlags.UserPhysicalPages == 0) &&
  415. (Vad->u.VadFlags.LargePages == 0) &&
  416. ((Vad->u.VadFlags.PrivateMemory == 1) ||
  417. (Vad->u2.VadFlags2.Inherit == MM_VIEW_SHARE))) {
  418. NewVad = ExAllocatePoolWithTag (NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
  419. if (NewVad == NULL) {
  420. //
  421. // Unable to allocate pool for all the VADs. Deallocate
  422. // all VADs and other pool obtained so far.
  423. //
  424. *VadList = NULL;
  425. status = STATUS_INSUFFICIENT_RESOURCES;
  426. goto ErrorReturn2;
  427. }
  428. RtlZeroMemory (NewVad, sizeof(MMVAD_LONG));
  429. #if defined (_MIALT4K_)
  430. if (((Vad->u.VadFlags.PrivateMemory) && (Vad->u.VadFlags.NoChange == 0))
  431. ||
  432. (Vad->u2.VadFlags2.LongVad == 0)) {
  433. NOTHING;
  434. }
  435. else if (((PMMVAD_LONG)Vad)->AliasInformation != NULL) {
  436. //
  437. // This VAD has aliased VADs which are going to be duplicated
  438. // into the clone's address space, but the alias list must
  439. // be explicitly copied.
  440. //
  441. ((PMMVAD_LONG)NewVad)->AliasInformation = MiDuplicateAliasVadList (Vad);
  442. if (((PMMVAD_LONG)NewVad)->AliasInformation == NULL) {
  443. ExFreePool (NewVad);
  444. *VadList = NULL;
  445. status = STATUS_INSUFFICIENT_RESOURCES;
  446. goto ErrorReturn2;
  447. }
  448. }
  449. #endif
  450. *VadList = NewVad;
  451. VadList = &NewVad->u1.Parent;
  452. }
  453. Vad = MiGetNextVad (Vad);
  454. }
  455. //
  456. // Terminate list of VADs for new process.
  457. //
  458. *VadList = NULL;
  459. //
  460. // Initializing UsedPageTableEntries is not needed for correctness, but
  461. // without it the compiler cannot compile this code W4 to check
  462. // for use of uninitialized variables.
  463. //
  464. UsedPageTableEntries = NULL;
  465. PdeBase = NULL;
  466. #if (_MI_PAGING_LEVELS >= 3)
  467. //
  468. // Initializing these is not needed for correctness, but
  469. // without it the compiler cannot compile this code W4 to check
  470. // for use of uninitialized variables.
  471. //
  472. PageDirFrameIndex = 0;
  473. UsedPageDirectoryEntries = NULL;
  474. PpeBase = NULL;
  475. #if (_MI_PAGING_LEVELS >= 4)
  476. PxeBase = NULL;
  477. PageParentFrameIndex = 0;
  478. UsedPageDirectoryParentEntries = NULL;
  479. #endif
  480. //
  481. // Map the (extended) page directory parent page into the system address
  482. // space.
  483. //
  484. PpeBase = (PMMPTE) MiMapSinglePage (NULL,
  485. RootPhysicalPage,
  486. MmCached,
  487. HighPagePriority);
  488. if (PpeBase == NULL) {
  489. status = STATUS_INSUFFICIENT_RESOURCES;
  490. goto ErrorReturn2;
  491. }
  492. PfnPpPage = MI_PFN_ELEMENT (RootPhysicalPage);
  493. #if (_MI_PAGING_LEVELS >= 4)
  494. //
  495. // The PxeBase is going to map the real top-level. For 4 level
  496. // architectures, the PpeBase above is mapping the wrong page, but
  497. // it doesn't matter because the initial value is never used - it
  498. // just serves as a way to obtain a mapping PTE and will be repointed
  499. // correctly before it is ever used.
  500. //
  501. PxeBase = (PMMPTE) MiMapSinglePage (NULL,
  502. RootPhysicalPage,
  503. MmCached,
  504. HighPagePriority);
  505. if (PxeBase == NULL) {
  506. MiUnmapSinglePage (PpeBase);
  507. status = STATUS_INSUFFICIENT_RESOURCES;
  508. goto ErrorReturn2;
  509. }
  510. PfnPxPage = MI_PFN_ELEMENT (RootPhysicalPage);
  511. MdlDirParentPage = RootPhysicalPage;
  512. #endif
  513. #endif
  514. //
  515. // Initialize a page directory map so it can be
  516. // unlocked in the loop and the end of the loop without
  517. // any testing to see if has a valid value the first time through.
  518. // Note this is a dummy map for 64-bit systems and a real one for 32-bit.
  519. //
  520. #if !defined (_X86PAE_)
  521. MdlDirPage = RootPhysicalPage;
  522. PdePhysicalPage = RootPhysicalPage;
  523. PdeBase = (PMMPTE) MiMapSinglePage (NULL,
  524. MdlDirPage,
  525. MmCached,
  526. HighPagePriority);
  527. #else
  528. //
  529. // All 4 page directory pages need to be mapped for PAE so the heavyweight
  530. // mapping must be used.
  531. //
  532. MdlPageDirectory = (PMDL)&MdlHackPageDirectory[0];
  533. MmInitializeMdl (MdlPageDirectory,
  534. (PVOID)PDE_BASE,
  535. PD_PER_SYSTEM * PAGE_SIZE);
  536. MdlPageDirectory->MdlFlags |= MDL_PAGES_LOCKED;
  537. RtlCopyMemory (MdlPageDirectory + 1,
  538. PageDirectoryFrames,
  539. PD_PER_SYSTEM * sizeof (PFN_NUMBER));
  540. PdePhysicalPage = RootPhysicalPage;
  541. PdeBase = (PMMPTE) MmMapLockedPagesSpecifyCache (MdlPageDirectory,
  542. KernelMode,
  543. MmCached,
  544. NULL,
  545. FALSE,
  546. HighPagePriority);
  547. #endif
  548. if (PdeBase == NULL) {
  549. status = STATUS_INSUFFICIENT_RESOURCES;
  550. goto ErrorReturn3;
  551. }
  552. PfnPdPage = MI_PFN_ELEMENT (RootPhysicalPage);
  553. #if (_MI_PAGING_LEVELS < 3)
  554. //
  555. // Map hyperspace so target UsedPageTable entries can be incremented.
  556. //
  557. HyperBase = (PMMWSL)MiMapSinglePage (NULL,
  558. HyperPhysicalPage,
  559. MmCached,
  560. HighPagePriority);
  561. if (HyperBase == NULL) {
  562. status = STATUS_INSUFFICIENT_RESOURCES;
  563. goto ErrorReturn3;
  564. }
  565. //
  566. // MmWorkingSetList is not page aligned when booted /3GB so account
  567. // for that here when established the used page table entry pointer.
  568. //
  569. HyperWsl = (PMMWSL) ((PCHAR)HyperBase + BYTE_OFFSET(MmWorkingSetList));
  570. #endif
  571. //
  572. // Map the hyperspace page (any cached page would serve equally well)
  573. // to acquire a mapping PTE now (prior to starting through the loop) -
  574. // this way we guarantee forward progress regardless of resources once
  575. // the loop is entered.
  576. //
  577. NewPteMappedAddress = (PMMPTE) MiMapSinglePage (NULL,
  578. HyperPhysicalPage,
  579. MmCached,
  580. HighPagePriority);
  581. if (NewPteMappedAddress == NULL) {
  582. status = STATUS_INSUFFICIENT_RESOURCES;
  583. goto ErrorReturn3;
  584. }
  585. PointerNewPte = NewPteMappedAddress;
  586. //
  587. // Build a new clone prototype PTE block and descriptor, note that
  588. // each prototype PTE has a reference count following it.
  589. //
  590. ForkProtoPte = CloneProtos;
  591. LockedForkPte = ForkProtoPte;
  592. MiLockPagedAddress (LockedForkPte);
  593. CloneHeader->NumberOfPtes = (ULONG)NumberOfPrivatePages;
  594. CloneHeader->NumberOfProcessReferences = 1;
  595. CloneHeader->ClonePtes = CloneProtos;
  596. CloneDescriptor->StartingVpn = (ULONG_PTR)CloneProtos;
  597. CloneDescriptor->EndingVpn = (ULONG_PTR)((ULONG_PTR)CloneProtos +
  598. NumberOfPrivatePages *
  599. sizeof(MMCLONE_BLOCK));
  600. CloneDescriptor->EndingVpn -= 1;
  601. CloneDescriptor->NumberOfReferences = 0;
  602. CloneDescriptor->FinalNumberOfReferences = 0;
  603. CloneDescriptor->NumberOfPtes = (ULONG)NumberOfPrivatePages;
  604. CloneDescriptor->CloneHeader = CloneHeader;
  605. CloneDescriptor->PagedPoolQuotaCharge = sizeof(MMCLONE_BLOCK) *
  606. NumberOfPrivatePages;
  607. //
  608. // Insert the clone descriptor for this fork operation into the
  609. // process which was cloned.
  610. //
  611. MiInsertClone (CurrentProcess, CloneDescriptor);
  612. //
  613. // Examine each virtual address descriptor and create the
  614. // proper structures for the new process.
  615. //
  616. Vad = MiGetFirstVad (CurrentProcess);
  617. NewVad = FirstNewVad;
  618. while (Vad != NULL) {
  619. //
  620. // Examine the VAD to determine its type and inheritance
  621. // attribute.
  622. //
  623. if ((Vad->u.VadFlags.UserPhysicalPages == 0) &&
  624. (Vad->u.VadFlags.LargePages == 0) &&
  625. ((Vad->u.VadFlags.PrivateMemory == 1) ||
  626. (Vad->u2.VadFlags2.Inherit == MM_VIEW_SHARE))) {
  627. //
  628. // The virtual address descriptor should be shared in the
  629. // forked process.
  630. //
  631. // Make a copy of the VAD for the new process, the new VADs
  632. // are preallocated and linked together through the parent
  633. // field.
  634. //
  635. NextVad = NewVad->u1.Parent;
  636. if (Vad->u.VadFlags.PrivateMemory == 1) {
  637. *(PMMVAD_SHORT)NewVad = *(PMMVAD_SHORT)Vad;
  638. NewVad->u.VadFlags.NoChange = 0;
  639. }
  640. else {
  641. if (Vad->u2.VadFlags2.LongVad == 0) {
  642. *NewVad = *Vad;
  643. }
  644. else {
  645. #if defined (_MIALT4K_)
  646. //
  647. // The VADs duplication earlier in this routine keeps both
  648. // the current process' VAD tree and the new process' VAD
  649. // list ordered. ASSERT on this below.
  650. //
  651. #if DBG
  652. if (((PMMVAD_LONG)Vad)->AliasInformation == NULL) {
  653. ASSERT (((PMMVAD_LONG)NewVad)->AliasInformation == NULL);
  654. }
  655. else {
  656. ASSERT (((PMMVAD_LONG)NewVad)->AliasInformation != NULL);
  657. }
  658. #endif
  659. TempAliasInformation = ((PMMVAD_LONG)NewVad)->AliasInformation;
  660. #endif
  661. *(PMMVAD_LONG)NewVad = *(PMMVAD_LONG)Vad;
  662. #if defined (_MIALT4K_)
  663. ((PMMVAD_LONG)NewVad)->AliasInformation = TempAliasInformation;
  664. #endif
  665. if (Vad->u2.VadFlags2.ExtendableFile == 1) {
  666. KeAcquireGuardedMutexUnsafe (&MmSectionBasedMutex);
  667. ASSERT (Vad->ControlArea->Segment->ExtendInfo != NULL);
  668. Vad->ControlArea->Segment->ExtendInfo->ReferenceCount += 1;
  669. KeReleaseGuardedMutexUnsafe (&MmSectionBasedMutex);
  670. }
  671. }
  672. }
  673. NewVad->u2.VadFlags2.LongVad = 1;
  674. if (NewVad->u.VadFlags.NoChange) {
  675. if ((NewVad->u2.VadFlags2.OneSecured) ||
  676. (NewVad->u2.VadFlags2.MultipleSecured)) {
  677. //
  678. // Eliminate these as the memory was secured
  679. // only in this process, not in the new one.
  680. //
  681. NewVad->u2.VadFlags2.OneSecured = 0;
  682. NewVad->u2.VadFlags2.MultipleSecured = 0;
  683. ((PMMVAD_LONG) NewVad)->u3.List.Flink = NULL;
  684. ((PMMVAD_LONG) NewVad)->u3.List.Blink = NULL;
  685. }
  686. if (NewVad->u2.VadFlags2.SecNoChange == 0) {
  687. NewVad->u.VadFlags.NoChange = 0;
  688. }
  689. }
  690. NewVad->u1.Parent = NextVad;
  691. //
  692. // If the VAD refers to a section, up the view count for that
  693. // section. This requires the PFN lock to be held.
  694. //
  695. if ((Vad->u.VadFlags.PrivateMemory == 0) &&
  696. (Vad->ControlArea != NULL)) {
  697. if ((Vad->u.VadFlags.Protection & MM_READWRITE) &&
  698. (Vad->ControlArea->FilePointer != NULL) &&
  699. (Vad->ControlArea->u.Flags.Image == 0)) {
  700. InterlockedIncrement ((PLONG)&Vad->ControlArea->Segment->WritableUserReferences);
  701. }
  702. //
  703. // Increment the count of the number of views for the
  704. // section object. This requires the PFN lock to be held.
  705. //
  706. MiUpControlAreaRefs (Vad);
  707. }
  708. if (Vad->u.VadFlags.PhysicalMapping == 1) {
  709. PhysicalView = PhysicalViewList;
  710. ASSERT (PhysicalViewCount != 0);
  711. ASSERT (PhysicalView != NULL);
  712. PhysicalViewCount -= 1;
  713. PhysicalViewList = (PMI_PHYSICAL_VIEW) PhysicalView->u1.Parent;
  714. PhysicalView->Vad = NewVad;
  715. PhysicalView->u.LongFlags = MI_PHYSICAL_VIEW_PHYS;
  716. PhysicalView->StartingVpn = Vad->StartingVpn;
  717. PhysicalView->EndingVpn = Vad->EndingVpn;
  718. MiPhysicalViewInserter (ProcessToInitialize, PhysicalView);
  719. }
  720. //
  721. // Examine each PTE and create the appropriate PTE for the
  722. // new process.
  723. //
  724. PointerPde = NULL; // Needless, but keeps W4 happy
  725. PointerPte = MiGetPteAddress (MI_VPN_TO_VA (Vad->StartingVpn));
  726. LastPte = MiGetPteAddress (MI_VPN_TO_VA (Vad->EndingVpn));
  727. FirstTime = TRUE;
  728. do {
  729. //
  730. // For each PTE contained in the VAD check the page table
  731. // page, and if non-zero, make the appropriate modifications
  732. // to copy the PTE to the new process.
  733. //
  734. if ((FirstTime) || MiIsPteOnPdeBoundary (PointerPte)) {
  735. PointerPxe = MiGetPpeAddress (PointerPte);
  736. PointerPpe = MiGetPdeAddress (PointerPte);
  737. PointerPde = MiGetPteAddress (PointerPte);
  738. do {
  739. #if (_MI_PAGING_LEVELS >= 4)
  740. while (!MiDoesPxeExistAndMakeValid (PointerPxe,
  741. CurrentProcess,
  742. MM_NOIRQL,
  743. &Waited)) {
  744. //
  745. // Extended page directory parent is empty,
  746. // go to the next one.
  747. //
  748. PointerPxe += 1;
  749. PointerPpe = MiGetVirtualAddressMappedByPte (PointerPxe);
  750. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  751. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  752. if (PointerPte > LastPte) {
  753. //
  754. // All done with this VAD, exit loop.
  755. //
  756. goto AllDone;
  757. }
  758. }
  759. #endif
  760. Waited = 0;
  761. while (!MiDoesPpeExistAndMakeValid (PointerPpe,
  762. CurrentProcess,
  763. MM_NOIRQL,
  764. &Waited)) {
  765. //
  766. // Page directory parent is empty, go to the next one.
  767. //
  768. PointerPpe += 1;
  769. if (MiIsPteOnPdeBoundary (PointerPpe)) {
  770. PointerPxe = MiGetPteAddress (PointerPpe);
  771. Waited = 1;
  772. break;
  773. }
  774. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  775. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  776. if (PointerPte > LastPte) {
  777. //
  778. // All done with this VAD, exit loop.
  779. //
  780. goto AllDone;
  781. }
  782. }
  783. if (Waited != 0) {
  784. continue;
  785. }
  786. while (!MiDoesPdeExistAndMakeValid (PointerPde,
  787. CurrentProcess,
  788. MM_NOIRQL,
  789. &Waited)) {
  790. //
  791. // This page directory is empty, go to the next one.
  792. //
  793. PointerPde += 1;
  794. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  795. if (PointerPte > LastPte) {
  796. //
  797. // All done with this VAD, exit loop.
  798. //
  799. goto AllDone;
  800. }
  801. #if (_MI_PAGING_LEVELS >= 3)
  802. if (MiIsPteOnPdeBoundary (PointerPde)) {
  803. PointerPpe = MiGetPteAddress (PointerPde);
  804. PointerPxe = MiGetPdeAddress (PointerPde);
  805. Waited = 1;
  806. break;
  807. }
  808. #endif
  809. }
  810. } while (Waited != 0);
  811. FirstTime = FALSE;
  812. #if (_MI_PAGING_LEVELS >= 4)
  813. //
  814. // Calculate the address of the PXE in the new process's
  815. // extended page directory parent page.
  816. //
  817. PointerNewPxe = &PxeBase[MiGetPpeOffset(PointerPte)];
  818. if (PointerNewPxe->u.Long == 0) {
  819. //
  820. // No physical page has been allocated yet, get a page
  821. // and map it in as a valid page. This will become
  822. // a page directory parent page for the new process.
  823. //
  824. // Note that unlike page table pages which are left
  825. // in transition, page directory parent pages (and page
  826. // directory pages) are left valid and hence
  827. // no share count decrement is done.
  828. //
  829. ReleasedWorkingSetMutex =
  830. MiLeaveThisPageGetAnother (&PageParentFrameIndex,
  831. PointerPxe,
  832. CurrentProcess);
  833. MI_ZERO_USED_PAGETABLE_ENTRIES (MI_PFN_ELEMENT(PageParentFrameIndex));
  834. if (ReleasedWorkingSetMutex) {
  835. //
  836. // Ensure the PDE (and any table above it) are still
  837. // resident.
  838. //
  839. MiMakePdeExistAndMakeValid (PointerPde,
  840. CurrentProcess,
  841. MM_NOIRQL);
  842. }
  843. //
  844. // Hand initialize this PFN as normal initialization
  845. // would do it for the process whose context we are
  846. // attached to.
  847. //
  848. // The PFN lock must be held while initializing the
  849. // frame to prevent those scanning the database for
  850. // free frames from taking it after we fill in the
  851. // u2 field.
  852. //
  853. MiBuildForkPageTable (PageParentFrameIndex,
  854. PointerPxe,
  855. PointerNewPxe,
  856. RootPhysicalPage,
  857. PfnPxPage,
  858. TRUE);
  859. //
  860. // Map the new page directory page into the system
  861. // portion of the address space. Note that hyperspace
  862. // cannot be used as other operations (allocating
  863. // nonpaged pool at DPC level) could cause the
  864. // hyperspace page being used to be reused.
  865. //
  866. MdlDirParentPage = PageParentFrameIndex;
  867. ASSERT (PpeBase != NULL);
  868. PpeBase = (PMMPTE) MiMapSinglePage (PpeBase,
  869. MdlDirParentPage,
  870. MmCached,
  871. HighPagePriority);
  872. PpePhysicalPage = PageParentFrameIndex;
  873. PfnPpPage = MI_PFN_ELEMENT (PpePhysicalPage);
  874. UsedPageDirectoryParentEntries = (PVOID) PfnPpPage;
  875. }
  876. else {
  877. ASSERT (PointerNewPxe->u.Hard.Valid == 1);
  878. PpePhysicalPage = MI_GET_PAGE_FRAME_FROM_PTE (PointerNewPxe);
  879. //
  880. // If we are switching from one page directory parent
  881. // frame to another and the last one is one that we
  882. // freshly allocated, the last one's reference count
  883. // must be decremented now that we're done with it.
  884. //
  885. // Note that at least one target PXE has already been
  886. // initialized for this codepath to execute.
  887. //
  888. ASSERT (PageParentFrameIndex == MdlDirParentPage);
  889. if (MdlDirParentPage != PpePhysicalPage) {
  890. ASSERT (MdlDirParentPage != (PFN_NUMBER)-1);
  891. PageParentFrameIndex = PpePhysicalPage;
  892. MdlDirParentPage = PageParentFrameIndex;
  893. ASSERT (PpeBase != NULL);
  894. PpeBase = (PMMPTE) MiMapSinglePage (PpeBase,
  895. MdlDirParentPage,
  896. MmCached,
  897. HighPagePriority);
  898. PointerNewPpe = PpeBase;
  899. PfnPpPage = MI_PFN_ELEMENT (PpePhysicalPage);
  900. UsedPageDirectoryParentEntries = (PVOID)PfnPpPage;
  901. }
  902. }
  903. #endif
  904. #if (_MI_PAGING_LEVELS >= 3)
  905. //
  906. // Calculate the address of the PPE in the new process's
  907. // page directory parent page.
  908. //
  909. PointerNewPpe = &PpeBase[MiGetPdeOffset(PointerPte)];
  910. if (PointerNewPpe->u.Long == 0) {
  911. //
  912. // No physical page has been allocated yet, get a page
  913. // and map it in as a valid page. This will
  914. // become a page directory page for the new process.
  915. //
  916. // Note that unlike page table pages which are left
  917. // in transition, page directory pages are left valid
  918. // and hence no share count decrement is done.
  919. //
  920. ReleasedWorkingSetMutex =
  921. MiLeaveThisPageGetAnother (&PageDirFrameIndex,
  922. PointerPpe,
  923. CurrentProcess);
  924. MI_ZERO_USED_PAGETABLE_ENTRIES (MI_PFN_ELEMENT(PageDirFrameIndex));
  925. if (ReleasedWorkingSetMutex) {
  926. //
  927. // Ensure the PDE (and any table above it) are still
  928. // resident.
  929. //
  930. MiMakePdeExistAndMakeValid (PointerPde,
  931. CurrentProcess,
  932. MM_NOIRQL);
  933. }
  934. //
  935. // Hand initialize this PFN as normal initialization
  936. // would do it for the process whose context we are
  937. // attached to.
  938. //
  939. // The PFN lock must be held while initializing the
  940. // frame to prevent those scanning the database for
  941. // free frames from taking it after we fill in the
  942. // u2 field.
  943. //
  944. MiBuildForkPageTable (PageDirFrameIndex,
  945. PointerPpe,
  946. PointerNewPpe,
  947. #if (_MI_PAGING_LEVELS >= 4)
  948. PpePhysicalPage,
  949. #else
  950. RootPhysicalPage,
  951. #endif
  952. PfnPpPage,
  953. TRUE);
  954. #if (_MI_PAGING_LEVELS >= 4)
  955. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryParentEntries);
  956. #endif
  957. //
  958. // Map the new page directory page into the system
  959. // portion of the address space. Note that hyperspace
  960. // cannot be used as other operations (allocating
  961. // nonpaged pool at DPC level) could cause the
  962. // hyperspace page being used to be reused.
  963. //
  964. MdlDirPage = PageDirFrameIndex;
  965. ASSERT (PdeBase != NULL);
  966. PdeBase = (PMMPTE) MiMapSinglePage (PdeBase,
  967. MdlDirPage,
  968. MmCached,
  969. HighPagePriority);
  970. PointerNewPde = PdeBase;
  971. PdePhysicalPage = PageDirFrameIndex;
  972. PfnPdPage = MI_PFN_ELEMENT (PdePhysicalPage);
  973. UsedPageDirectoryEntries = (PVOID)PfnPdPage;
  974. }
  975. else {
  976. ASSERT (PointerNewPpe->u.Hard.Valid == 1 ||
  977. PointerNewPpe->u.Soft.Transition == 1);
  978. if (PointerNewPpe->u.Hard.Valid == 1) {
  979. PdePhysicalPage = MI_GET_PAGE_FRAME_FROM_PTE (PointerNewPpe);
  980. }
  981. else {
  982. PdePhysicalPage = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerNewPpe);
  983. }
  984. //
  985. // If we are switching from one page directory frame to
  986. // another and the last one is one that we freshly
  987. // allocated, the last one's reference count must be
  988. // decremented now that we're done with it.
  989. //
  990. // Note that at least one target PPE has already been
  991. // initialized for this codepath to execute.
  992. //
  993. ASSERT (PageDirFrameIndex == MdlDirPage);
  994. if (MdlDirPage != PdePhysicalPage) {
  995. ASSERT (MdlDirPage != (PFN_NUMBER)-1);
  996. PageDirFrameIndex = PdePhysicalPage;
  997. MdlDirPage = PageDirFrameIndex;
  998. ASSERT (PdeBase != NULL);
  999. PdeBase = (PMMPTE) MiMapSinglePage (PdeBase,
  1000. MdlDirPage,
  1001. MmCached,
  1002. HighPagePriority);
  1003. PointerNewPde = PdeBase;
  1004. PfnPdPage = MI_PFN_ELEMENT (PdePhysicalPage);
  1005. UsedPageDirectoryEntries = (PVOID)PfnPdPage;
  1006. }
  1007. }
  1008. #endif
  1009. //
  1010. // Calculate the address of the PDE in the new process's
  1011. // page directory page.
  1012. //
  1013. #if defined (_X86PAE_)
  1014. //
  1015. // All four PAE page directory frames are mapped virtually
  1016. // contiguous and so the PpePdeOffset can (and must) be
  1017. // safely used here.
  1018. //
  1019. PpePdeOffset = MiGetPdeIndex(MiGetVirtualAddressMappedByPte(PointerPte));
  1020. #else
  1021. PpePdeOffset = MiGetPdeOffset(MiGetVirtualAddressMappedByPte(PointerPte));
  1022. #endif
  1023. PointerNewPde = &PdeBase[PpePdeOffset];
  1024. if (PointerNewPde->u.Long == 0) {
  1025. //
  1026. // No physical page has been allocated yet, get a page
  1027. // and map it in as a transition page. This will
  1028. // become a page table page for the new process.
  1029. //
  1030. ReleasedWorkingSetMutex =
  1031. MiDoneWithThisPageGetAnother (&PageFrameIndex,
  1032. PointerPde,
  1033. CurrentProcess);
  1034. #if (_MI_PAGING_LEVELS >= 3)
  1035. MI_ZERO_USED_PAGETABLE_ENTRIES (MI_PFN_ELEMENT(PageFrameIndex));
  1036. #endif
  1037. if (ReleasedWorkingSetMutex) {
  1038. //
  1039. // Ensure the PDE (and any table above it) are still
  1040. // resident.
  1041. //
  1042. MiMakePdeExistAndMakeValid (PointerPde,
  1043. CurrentProcess,
  1044. MM_NOIRQL);
  1045. }
  1046. //
  1047. // Hand initialize this PFN as normal initialization
  1048. // would do it for the process whose context we are
  1049. // attached to.
  1050. //
  1051. // The PFN lock must be held while initializing the
  1052. // frame to prevent those scanning the database for
  1053. // free frames from taking it after we fill in the
  1054. // u2 field.
  1055. //
  1056. #if defined (_X86PAE_)
  1057. PdePhysicalPage = PageDirectoryFrames[MiGetPdPteOffset(MiGetVirtualAddressMappedByPte(PointerPte))];
  1058. PfnPdPage = MI_PFN_ELEMENT (PdePhysicalPage);
  1059. #endif
  1060. MiBuildForkPageTable (PageFrameIndex,
  1061. PointerPde,
  1062. PointerNewPde,
  1063. PdePhysicalPage,
  1064. PfnPdPage,
  1065. FALSE);
  1066. #if (_MI_PAGING_LEVELS >= 3)
  1067. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryEntries);
  1068. #endif
  1069. //
  1070. // Map the new page table page into the system portion
  1071. // of the address space. Note that hyperspace
  1072. // cannot be used as other operations (allocating
  1073. // nonpaged pool at DPC level) could cause the
  1074. // hyperspace page being used to be reused.
  1075. //
  1076. ASSERT (NewPteMappedAddress != NULL);
  1077. PointerNewPte = (PMMPTE) MiMapSinglePage (NewPteMappedAddress,
  1078. PageFrameIndex,
  1079. MmCached,
  1080. HighPagePriority);
  1081. ASSERT (PointerNewPte != NULL);
  1082. }
  1083. //
  1084. // Calculate the address of the new PTE to build.
  1085. // Note that FirstTime could be true, yet the page
  1086. // table page already built.
  1087. //
  1088. PointerNewPte = (PMMPTE)((ULONG_PTR)PAGE_ALIGN(PointerNewPte) |
  1089. BYTE_OFFSET (PointerPte));
  1090. #if (_MI_PAGING_LEVELS >= 3)
  1091. UsedPageTableEntries = (PVOID)MI_PFN_ELEMENT((PFN_NUMBER)PointerNewPde->u.Hard.PageFrameNumber);
  1092. #else
  1093. #if !defined (_X86PAE_)
  1094. UsedPageTableEntries = (PVOID)&HyperWsl->UsedPageTableEntries
  1095. [MiGetPteOffset( PointerPte )];
  1096. #else
  1097. UsedPageTableEntries = (PVOID)&HyperWsl->UsedPageTableEntries
  1098. [MiGetPdeIndex(MiGetVirtualAddressMappedByPte(PointerPte))];
  1099. #endif
  1100. #endif
  1101. }
  1102. //
  1103. // Make the fork prototype PTE location resident.
  1104. //
  1105. if (PAGE_ALIGN (ForkProtoPte) != PAGE_ALIGN (LockedForkPte)) {
  1106. MiUnlockPagedAddress (LockedForkPte, FALSE);
  1107. LockedForkPte = ForkProtoPte;
  1108. MiLockPagedAddress (LockedForkPte);
  1109. }
  1110. MiMakeSystemAddressValid (PointerPte, CurrentProcess);
  1111. PteContents = *PointerPte;
  1112. //
  1113. // Check each PTE.
  1114. //
  1115. if (PteContents.u.Long == 0) {
  1116. NOTHING;
  1117. }
  1118. else if (PteContents.u.Hard.Valid == 1) {
  1119. //
  1120. // Valid.
  1121. //
  1122. if (Vad->u.VadFlags.PhysicalMapping == 1) {
  1123. //
  1124. // A PTE just went from not present, not transition to
  1125. // present. The share count and valid count must be
  1126. // updated in the new page table page which contains
  1127. // this PTE.
  1128. //
  1129. ASSERT (PageFrameIndex != (PFN_NUMBER)-1);
  1130. Pfn2 = MI_PFN_ELEMENT (PageFrameIndex);
  1131. Pfn2->u2.ShareCount += 1;
  1132. //
  1133. // Another zeroed PTE is being made non-zero.
  1134. //
  1135. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
  1136. PointerPte += 1;
  1137. PointerNewPte += 1;
  1138. continue;
  1139. }
  1140. Pfn2 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
  1141. VirtualAddress = MiGetVirtualAddressMappedByPte (PointerPte);
  1142. WorkingSetIndex = MiLocateWsle (VirtualAddress,
  1143. MmWorkingSetList,
  1144. Pfn2->u1.WsIndex);
  1145. ASSERT (WorkingSetIndex != WSLE_NULL_INDEX);
  1146. if (Pfn2->u3.e1.PrototypePte == 1) {
  1147. //
  1148. // This is a prototype PTE. The PFN database does
  1149. // not contain the contents of this PTE it contains
  1150. // the contents of the prototype PTE. This PTE must
  1151. // be reconstructed to contain a pointer to the
  1152. // prototype PTE.
  1153. //
  1154. // The working set list entry contains information about
  1155. // how to reconstruct the PTE.
  1156. //
  1157. if (MmWsle[WorkingSetIndex].u1.e1.SameProtectAsProto
  1158. == 0) {
  1159. //
  1160. // The protection for the prototype PTE is in the
  1161. // WSLE.
  1162. //
  1163. TempPte.u.Long = 0;
  1164. TempPte.u.Soft.Protection =
  1165. MI_GET_PROTECTION_FROM_WSLE(&MmWsle[WorkingSetIndex]);
  1166. TempPte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED;
  1167. }
  1168. else {
  1169. //
  1170. // The protection is in the prototype PTE.
  1171. //
  1172. TempPte.u.Long = MiProtoAddressForPte (
  1173. Pfn2->PteAddress);
  1174. }
  1175. TempPte.u.Proto.Prototype = 1;
  1176. MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
  1177. //
  1178. // A PTE is now non-zero, increment the used page
  1179. // table entries counter.
  1180. //
  1181. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
  1182. //
  1183. // Check to see if this is a fork prototype PTE,
  1184. // and if it is increment the reference count
  1185. // which is in the longword following the PTE.
  1186. //
  1187. if (MiLocateCloneAddress (CurrentProcess, (PVOID)Pfn2->PteAddress) !=
  1188. NULL) {
  1189. //
  1190. // The reference count field, or the prototype PTE
  1191. // for that matter may not be in the working set.
  1192. //
  1193. CloneProto = (PMMCLONE_BLOCK)Pfn2->PteAddress;
  1194. ASSERT (CloneProto->CloneRefCount >= 1);
  1195. InterlockedIncrement (&CloneProto->CloneRefCount);
  1196. if (PAGE_ALIGN (ForkProtoPte) !=
  1197. PAGE_ALIGN (LockedForkPte)) {
  1198. MiUnlockPagedAddress (LockedForkPte, FALSE);
  1199. LockedForkPte = ForkProtoPte;
  1200. MiLockPagedAddress (LockedForkPte);
  1201. }
  1202. MiMakeSystemAddressValid (PointerPte,
  1203. CurrentProcess);
  1204. }
  1205. }
  1206. else {
  1207. //
  1208. // This is a private page, create a fork prototype PTE
  1209. // which becomes the "prototype" PTE for this page.
  1210. // The protection is the same as that in the prototype
  1211. // PTE so the WSLE does not need to be updated.
  1212. //
  1213. MI_MAKE_VALID_PTE_WRITE_COPY (PointerPte);
  1214. KeFlushSingleTb (VirtualAddress, FALSE);
  1215. ForkProtoPte->ProtoPte = *PointerPte;
  1216. ForkProtoPte->CloneRefCount = 2;
  1217. //
  1218. // Transform the PFN element to reference this new fork
  1219. // prototype PTE.
  1220. //
  1221. Pfn2->PteAddress = &ForkProtoPte->ProtoPte;
  1222. Pfn2->u3.e1.PrototypePte = 1;
  1223. ContainingPte = MiGetPteAddress(&ForkProtoPte->ProtoPte);
  1224. if (ContainingPte->u.Hard.Valid == 0) {
  1225. #if (_MI_PAGING_LEVELS < 3)
  1226. if (!NT_SUCCESS(MiCheckPdeForPagedPool (&ForkProtoPte->ProtoPte))) {
  1227. #endif
  1228. KeBugCheckEx (MEMORY_MANAGEMENT,
  1229. 0x61940,
  1230. (ULONG_PTR)&ForkProtoPte->ProtoPte,
  1231. (ULONG_PTR)ContainingPte->u.Long,
  1232. (ULONG_PTR)MiGetVirtualAddressMappedByPte(&ForkProtoPte->ProtoPte));
  1233. #if (_MI_PAGING_LEVELS < 3)
  1234. }
  1235. #endif
  1236. }
  1237. Pfn2->u4.PteFrame = MI_GET_PAGE_FRAME_FROM_PTE (ContainingPte);
  1238. //
  1239. // Increment the share count for the page containing the
  1240. // fork prototype PTEs as we have just placed a valid
  1241. // PTE into the page.
  1242. //
  1243. PfnForkPtePage = MI_PFN_ELEMENT (
  1244. ContainingPte->u.Hard.PageFrameNumber );
  1245. MiUpForkPageShareCount (PfnForkPtePage);
  1246. //
  1247. // Change the protection in the PFN database to COPY
  1248. // on write, if writable.
  1249. //
  1250. MI_MAKE_PROTECT_WRITE_COPY (Pfn2->OriginalPte);
  1251. //
  1252. // Put the protection into the WSLE and mark the WSLE
  1253. // to indicate that the protection field for the PTE
  1254. // is the same as the prototype PTE.
  1255. //
  1256. MmWsle[WorkingSetIndex].u1.e1.Protection =
  1257. MI_GET_PROTECTION_FROM_SOFT_PTE(&Pfn2->OriginalPte);
  1258. MmWsle[WorkingSetIndex].u1.e1.SameProtectAsProto = 1;
  1259. TempPte.u.Long = MiProtoAddressForPte (Pfn2->PteAddress);
  1260. TempPte.u.Proto.Prototype = 1;
  1261. MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
  1262. //
  1263. // A PTE is now non-zero, increment the used page
  1264. // table entries counter.
  1265. //
  1266. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
  1267. //
  1268. // One less private page (it's now shared).
  1269. //
  1270. CurrentProcess->NumberOfPrivatePages -= 1;
  1271. ForkProtoPte += 1;
  1272. NumberOfForkPtes += 1;
  1273. }
  1274. }
  1275. else if (PteContents.u.Soft.Prototype == 1) {
  1276. //
  1277. // Prototype PTE, check to see if this is a fork
  1278. // prototype PTE already. Note that if COW is set,
  1279. // the PTE can just be copied (fork compatible format).
  1280. //
  1281. MI_WRITE_INVALID_PTE (PointerNewPte, PteContents);
  1282. //
  1283. // A PTE is now non-zero, increment the used page
  1284. // table entries counter.
  1285. //
  1286. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
  1287. //
  1288. // Check to see if this is a fork prototype PTE,
  1289. // and if it is increment the reference count
  1290. // which is in the longword following the PTE.
  1291. //
  1292. CloneProto = (PMMCLONE_BLOCK)(ULONG_PTR)MiPteToProto(PointerPte);
  1293. if (MiLocateCloneAddress (CurrentProcess, (PVOID)CloneProto) != NULL) {
  1294. //
  1295. // The reference count field, or the prototype PTE
  1296. // for that matter may not be in the working set.
  1297. //
  1298. ASSERT (CloneProto->CloneRefCount >= 1);
  1299. InterlockedIncrement (&CloneProto->CloneRefCount);
  1300. if (PAGE_ALIGN (ForkProtoPte) !=
  1301. PAGE_ALIGN (LockedForkPte)) {
  1302. MiUnlockPagedAddress (LockedForkPte, FALSE);
  1303. LockedForkPte = ForkProtoPte;
  1304. MiLockPagedAddress (LockedForkPte);
  1305. }
  1306. MiMakeSystemAddressValid (PointerPte, CurrentProcess);
  1307. }
  1308. }
  1309. else if (PteContents.u.Soft.Transition == 1) {
  1310. //
  1311. // Transition.
  1312. //
  1313. if (MiHandleForkTransitionPte (PointerPte,
  1314. PointerNewPte,
  1315. ForkProtoPte)) {
  1316. //
  1317. // PTE is no longer transition, try again.
  1318. //
  1319. continue;
  1320. }
  1321. //
  1322. // A PTE is now non-zero, increment the used page
  1323. // table entries counter.
  1324. //
  1325. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
  1326. //
  1327. // One less private page (it's now shared).
  1328. //
  1329. CurrentProcess->NumberOfPrivatePages -= 1;
  1330. ForkProtoPte += 1;
  1331. NumberOfForkPtes += 1;
  1332. }
  1333. else {
  1334. //
  1335. // Page file format (may be demand zero).
  1336. //
  1337. if (IS_PTE_NOT_DEMAND_ZERO (PteContents)) {
  1338. if (PteContents.u.Soft.Protection == MM_DECOMMIT) {
  1339. //
  1340. // This is a decommitted PTE, just move it
  1341. // over to the new process. Don't increment
  1342. // the count of private pages.
  1343. //
  1344. MI_WRITE_INVALID_PTE (PointerNewPte, PteContents);
  1345. }
  1346. else {
  1347. //
  1348. // The PTE is not demand zero, move the PTE to
  1349. // a fork prototype PTE and make this PTE and
  1350. // the new processes PTE refer to the fork
  1351. // prototype PTE.
  1352. //
  1353. ForkProtoPte->ProtoPte = PteContents;
  1354. //
  1355. // Make the protection write-copy if writable.
  1356. //
  1357. MI_MAKE_PROTECT_WRITE_COPY (ForkProtoPte->ProtoPte);
  1358. ForkProtoPte->CloneRefCount = 2;
  1359. TempPte.u.Long =
  1360. MiProtoAddressForPte (&ForkProtoPte->ProtoPte);
  1361. TempPte.u.Proto.Prototype = 1;
  1362. MI_WRITE_INVALID_PTE (PointerPte, TempPte);
  1363. MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
  1364. //
  1365. // One less private page (it's now shared).
  1366. //
  1367. CurrentProcess->NumberOfPrivatePages -= 1;
  1368. ForkProtoPte += 1;
  1369. NumberOfForkPtes += 1;
  1370. }
  1371. }
  1372. else {
  1373. //
  1374. // The page is demand zero, make the new process's
  1375. // page demand zero.
  1376. //
  1377. MI_WRITE_INVALID_PTE (PointerNewPte, PteContents);
  1378. }
  1379. //
  1380. // A PTE is now non-zero, increment the used page
  1381. // table entries counter.
  1382. //
  1383. MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
  1384. }
  1385. PointerPte += 1;
  1386. PointerNewPte += 1;
  1387. } while (PointerPte <= LastPte);
  1388. AllDone:
  1389. NewVad = NewVad->u1.Parent;
  1390. }
  1391. Vad = MiGetNextVad (Vad);
  1392. } // end while for VADs
  1393. ASSERT (PhysicalViewCount == 0);
  1394. //
  1395. // Unlock paged pool page.
  1396. //
  1397. MiUnlockPagedAddress (LockedForkPte, FALSE);
  1398. //
  1399. // Unmap the PD Page and hyper space page.
  1400. //
  1401. #if (_MI_PAGING_LEVELS >= 4)
  1402. MiUnmapSinglePage (PxeBase);
  1403. #endif
  1404. #if (_MI_PAGING_LEVELS >= 3)
  1405. MiUnmapSinglePage (PpeBase);
  1406. #endif
  1407. #if !defined (_X86PAE_)
  1408. MiUnmapSinglePage (PdeBase);
  1409. #else
  1410. MmUnmapLockedPages (PdeBase, MdlPageDirectory);
  1411. #endif
  1412. #if (_MI_PAGING_LEVELS < 3)
  1413. MiUnmapSinglePage (HyperBase);
  1414. #endif
  1415. MiUnmapSinglePage (NewPteMappedAddress);
  1416. //
  1417. // Make the count of private pages match between the two processes.
  1418. //
  1419. ASSERT ((SPFN_NUMBER)CurrentProcess->NumberOfPrivatePages >= 0);
  1420. ProcessToInitialize->NumberOfPrivatePages =
  1421. CurrentProcess->NumberOfPrivatePages;
  1422. ASSERT (NumberOfForkPtes <= CloneDescriptor->NumberOfPtes);
  1423. if (NumberOfForkPtes != 0) {
  1424. //
  1425. // The number of fork PTEs is non-zero, set the values
  1426. // into the structures.
  1427. //
  1428. CloneHeader->NumberOfPtes = NumberOfForkPtes;
  1429. CloneDescriptor->NumberOfReferences = NumberOfForkPtes;
  1430. CloneDescriptor->FinalNumberOfReferences = NumberOfForkPtes;
  1431. CloneDescriptor->NumberOfPtes = NumberOfForkPtes;
  1432. }
  1433. else {
  1434. //
  1435. // There were no fork PTEs created. Remove the clone descriptor
  1436. // from this process and clean up the related structures.
  1437. //
  1438. MiRemoveClone (CurrentProcess, CloneDescriptor);
  1439. UNLOCK_WS (CurrentProcess);
  1440. ExFreePool (CloneDescriptor->CloneHeader->ClonePtes);
  1441. ExFreePool (CloneDescriptor->CloneHeader);
  1442. //
  1443. // Return the pool for the global structures referenced by the
  1444. // clone descriptor.
  1445. //
  1446. PsReturnProcessPagedPoolQuota (CurrentProcess,
  1447. CloneDescriptor->PagedPoolQuotaCharge);
  1448. PsReturnProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMCLONE_HEADER));
  1449. ExFreePool (CloneDescriptor);
  1450. LOCK_WS (CurrentProcess);
  1451. }
  1452. //
  1453. // As we have updated many PTEs to clear dirty bits, flush the
  1454. // TB cache. Note that this was not done every time we changed
  1455. // a valid PTE so other threads could be modifying the address
  1456. // space without causing copy on writes. Too bad, because an app
  1457. // that is not synchronizing itself is going to have coherency problems
  1458. // anyway. Note that this cannot cause any system page corruption because
  1459. // the address space mutex was (and is) still held throughout and is
  1460. // not released until after we flush the TB now.
  1461. //
  1462. MiDownShareCountFlushEntireTb (PageFrameIndex);
  1463. PageFrameIndex = (PFN_NUMBER)-1;
  1464. //
  1465. // Copy the clone descriptors from this process to the new process.
  1466. //
  1467. Clone = MiGetFirstClone (CurrentProcess);
  1468. CloneList = &FirstNewClone;
  1469. CloneFailed = FALSE;
  1470. while (Clone != NULL) {
  1471. //
  1472. // Increment the count of processes referencing this clone block.
  1473. //
  1474. ASSERT (Clone->CloneHeader->NumberOfProcessReferences >= 1);
  1475. InterlockedIncrement (&Clone->CloneHeader->NumberOfProcessReferences);
  1476. do {
  1477. NewClone = ExAllocatePoolWithTag (NonPagedPool,
  1478. sizeof( MMCLONE_DESCRIPTOR),
  1479. 'dCmM');
  1480. if (NewClone != NULL) {
  1481. break;
  1482. }
  1483. //
  1484. // There are insufficient resources to continue this operation,
  1485. // however, to properly clean up at this point, all the
  1486. // clone headers must be allocated, so when the cloned process
  1487. // is deleted, the clone headers will be found. If the pool
  1488. // is not readily available, loop periodically trying for it.
  1489. // Force the clone operation to fail so the pool will soon be
  1490. // released.
  1491. //
  1492. // Release the working set mutex so this process can be trimmed
  1493. // and reacquire after the delay.
  1494. //
  1495. UNLOCK_WS (CurrentProcess);
  1496. CloneFailed = TRUE;
  1497. status = STATUS_INSUFFICIENT_RESOURCES;
  1498. KeDelayExecutionThread (KernelMode,
  1499. FALSE,
  1500. (PLARGE_INTEGER)&MmShortTime);
  1501. LOCK_WS (CurrentProcess);
  1502. } while (TRUE);
  1503. *NewClone = *Clone;
  1504. //
  1505. // Carefully update the FinalReferenceCount as this forking thread
  1506. // may have begun while a faulting thread is waiting in
  1507. // MiDecrementCloneBlockReference for the clone PTEs to inpage.
  1508. // In this case, the ReferenceCount has been decremented but the
  1509. // FinalReferenceCount hasn't been yet. When the faulter awakes, he
  1510. // will automatically take care of this process, but we must fix up
  1511. // the child process now. Otherwise the clone descriptor, clone header
  1512. // and clone PTE pool allocations will leak and so will the charged
  1513. // quota.
  1514. //
  1515. if (NewClone->FinalNumberOfReferences > NewClone->NumberOfReferences) {
  1516. NewClone->FinalNumberOfReferences = NewClone->NumberOfReferences;
  1517. }
  1518. *CloneList = NewClone;
  1519. CloneList = (PMMCLONE_DESCRIPTOR *)&NewClone->u1.Parent;
  1520. Clone = MiGetNextClone (Clone);
  1521. }
  1522. *CloneList = NULL;
  1523. #if defined (_MIALT4K_)
  1524. if (CurrentProcess->Wow64Process != NULL) {
  1525. //
  1526. // Copy the alternate table entries now.
  1527. //
  1528. MiDuplicateAlternateTable (CurrentProcess, ProcessToInitialize);
  1529. }
  1530. #endif
  1531. ASSERT (CurrentProcess->ForkInProgress == PsGetCurrentThread ());
  1532. CurrentProcess->ForkInProgress = NULL;
  1533. //
  1534. // Release the working set mutex and the address creation mutex from
  1535. // the current process as all the necessary information is now
  1536. // captured.
  1537. //
  1538. UNLOCK_WS (CurrentProcess);
  1539. UNLOCK_ADDRESS_SPACE (CurrentProcess);
  1540. //
  1541. // Attach to the process to initialize and insert the vad and clone
  1542. // descriptors into the tree.
  1543. //
  1544. if (Attached) {
  1545. KeUnstackDetachProcess (&ApcState);
  1546. Attached = FALSE;
  1547. }
  1548. if (PsGetCurrentProcess() != ProcessToInitialize) {
  1549. Attached = TRUE;
  1550. KeStackAttachProcess (&ProcessToInitialize->Pcb, &ApcState);
  1551. }
  1552. CurrentProcess = ProcessToInitialize;
  1553. //
  1554. // We are now in the context of the new process, build the
  1555. // VAD list and the clone list.
  1556. //
  1557. Vad = FirstNewVad;
  1558. VadInsertFailed = FALSE;
  1559. LOCK_WS (CurrentProcess);
  1560. #if (_MI_PAGING_LEVELS >= 3)
  1561. //
  1562. // Update the WSLEs for the page directories that were added.
  1563. //
  1564. PointerPpe = MiGetPpeAddress (0);
  1565. PointerPpeLast = MiGetPpeAddress (MM_HIGHEST_USER_ADDRESS);
  1566. PointerPxe = MiGetPxeAddress (0);
  1567. while (PointerPpe <= PointerPpeLast) {
  1568. #if (_MI_PAGING_LEVELS >= 4)
  1569. while (PointerPxe->u.Long == 0) {
  1570. PointerPxe += 1;
  1571. PointerPpe = MiGetVirtualAddressMappedByPte (PointerPxe);
  1572. if (PointerPpe > PointerPpeLast) {
  1573. goto WslesFinished;
  1574. }
  1575. }
  1576. //
  1577. // Update the WSLE for this page directory parent page (if we haven't
  1578. // already done it in this loop).
  1579. //
  1580. ASSERT (PointerPxe->u.Hard.Valid == 1);
  1581. PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPxe);
  1582. PfnPdPage = MI_PFN_ELEMENT (PageFrameIndex);
  1583. if (PfnPdPage->u1.Event == NULL) {
  1584. do {
  1585. WorkingSetIndex = MiAddValidPageToWorkingSet (PointerPpe,
  1586. PointerPxe,
  1587. PfnPdPage,
  1588. 0);
  1589. if (WorkingSetIndex != 0) {
  1590. break;
  1591. }
  1592. KeDelayExecutionThread (KernelMode,
  1593. FALSE,
  1594. (PLARGE_INTEGER)&Mm30Milliseconds);
  1595. } while (TRUE);
  1596. }
  1597. #endif
  1598. if (PointerPpe->u.Long != 0) {
  1599. ASSERT (PointerPpe->u.Hard.Valid == 1);
  1600. PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPpe);
  1601. PfnPdPage = MI_PFN_ELEMENT (PageFrameIndex);
  1602. ASSERT (PfnPdPage->u1.Event == NULL);
  1603. do {
  1604. WorkingSetIndex = MiAddValidPageToWorkingSet (MiGetVirtualAddressMappedByPte (PointerPpe),
  1605. PointerPpe,
  1606. PfnPdPage,
  1607. 0);
  1608. if (WorkingSetIndex != 0) {
  1609. break;
  1610. }
  1611. KeDelayExecutionThread (KernelMode,
  1612. FALSE,
  1613. (PLARGE_INTEGER)&Mm30Milliseconds);
  1614. } while (TRUE);
  1615. }
  1616. PointerPpe += 1;
  1617. #if (_MI_PAGING_LEVELS >= 4)
  1618. if (MiIsPteOnPdeBoundary (PointerPpe)) {
  1619. PointerPxe += 1;
  1620. ASSERT (PointerPxe == MiGetPteAddress (PointerPpe));
  1621. }
  1622. #endif
  1623. }
  1624. #if (_MI_PAGING_LEVELS >= 4)
  1625. WslesFinished:
  1626. #endif
  1627. #endif
  1628. if (CurrentProcess->PhysicalVadRoot != NULL) {
  1629. RestartKey = NULL;
  1630. do {
  1631. PhysicalView = (PMI_PHYSICAL_VIEW) MiEnumerateGenericTableWithoutSplayingAvl (CurrentProcess->PhysicalVadRoot, &RestartKey);
  1632. if (PhysicalView == NULL) {
  1633. break;
  1634. }
  1635. ASSERT (PhysicalView->u.LongFlags == MI_PHYSICAL_VIEW_PHYS);
  1636. PointerPde = MiGetPdeAddress (MI_VPN_TO_VA (PhysicalView->StartingVpn));
  1637. LastPde = MiGetPdeAddress (MI_VPN_TO_VA (PhysicalView->EndingVpn));
  1638. do {
  1639. //
  1640. // The PDE entry must still be in transition (they all are),
  1641. // but we guaranteed that the page table page itself is still
  1642. // resident because we've incremented the sharecount by the
  1643. // number of physical mappings the page table page contains.
  1644. //
  1645. // The only reason the PDE would be valid here is if we've
  1646. // already processed a different physical view that shares
  1647. // the same page table page.
  1648. //
  1649. // Increment it once more here (to account for itself), make
  1650. // the PDE valid and insert it into the working set list.
  1651. //
  1652. if (PointerPde->u.Hard.Valid == 0) {
  1653. PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPde);
  1654. Pfn2 = MI_PFN_ELEMENT (PageFrameIndex);
  1655. //
  1656. // There can be no I/O in progress on this page, it cannot
  1657. // be trimmed and no one else can be accessing it, so the
  1658. // PFN lock is not needed to increment the share count here.
  1659. //
  1660. Pfn2->u2.ShareCount += 1;
  1661. MI_MAKE_TRANSITION_PTE_VALID (TempPte, PointerPde);
  1662. MI_SET_PTE_DIRTY (TempPte);
  1663. MI_WRITE_VALID_PTE (PointerPde, TempPte);
  1664. ASSERT (Pfn2->u1.Event == NULL);
  1665. do {
  1666. WorkingSetIndex = MiAddValidPageToWorkingSet (MiGetVirtualAddressMappedByPte (PointerPde),
  1667. PointerPde,
  1668. Pfn2,
  1669. 0);
  1670. if (WorkingSetIndex != 0) {
  1671. break;
  1672. }
  1673. KeDelayExecutionThread (KernelMode,
  1674. FALSE,
  1675. (PLARGE_INTEGER)&Mm30Milliseconds);
  1676. } while (TRUE);
  1677. }
  1678. PointerPde += 1;
  1679. } while (PointerPde <= LastPde);
  1680. } while (TRUE);
  1681. }
  1682. while (Vad != NULL) {
  1683. NextVad = Vad->u1.Parent;
  1684. if (VadInsertFailed) {
  1685. Vad->u.VadFlags.CommitCharge = MM_MAX_COMMIT;
  1686. }
  1687. status = MiInsertVad (Vad);
  1688. if (!NT_SUCCESS(status)) {
  1689. //
  1690. // Charging quota for the VAD failed, set the
  1691. // remaining quota fields in this VAD and all
  1692. // subsequent VADs to zero so the VADs can be
  1693. // inserted and later deleted.
  1694. //
  1695. VadInsertFailed = TRUE;
  1696. //
  1697. // Do the loop again for this VAD.
  1698. //
  1699. continue;
  1700. }
  1701. //
  1702. // Update the current virtual size.
  1703. //
  1704. CurrentProcess->VirtualSize += PAGE_SIZE +
  1705. ((Vad->EndingVpn - Vad->StartingVpn) >> PAGE_SHIFT);
  1706. Vad = NextVad;
  1707. }
  1708. UNLOCK_WS (CurrentProcess);
  1709. //
  1710. // Update the peak virtual size.
  1711. //
  1712. CurrentProcess->PeakVirtualSize = CurrentProcess->VirtualSize;
  1713. CurrentProcess->CloneRoot = TargetCloneRoot;
  1714. Clone = FirstNewClone;
  1715. TotalPagedPoolCharge = 0;
  1716. TotalNonPagedPoolCharge = 0;
  1717. while (Clone != NULL) {
  1718. NextClone = (PMMCLONE_DESCRIPTOR) Clone->u1.Parent;
  1719. MiInsertClone (CurrentProcess, Clone);
  1720. //
  1721. // Calculate the paged pool and non-paged pool to charge for these
  1722. // operations.
  1723. //
  1724. TotalPagedPoolCharge += Clone->PagedPoolQuotaCharge;
  1725. TotalNonPagedPoolCharge += sizeof(MMCLONE_HEADER);
  1726. Clone = NextClone;
  1727. }
  1728. if (CloneFailed || VadInsertFailed) {
  1729. PS_SET_BITS (&CurrentProcess->Flags, PS_PROCESS_FLAGS_FORK_FAILED);
  1730. if (Attached) {
  1731. KeUnstackDetachProcess (&ApcState);
  1732. }
  1733. return status;
  1734. }
  1735. status = PsChargeProcessPagedPoolQuota (CurrentProcess,
  1736. TotalPagedPoolCharge);
  1737. if (!NT_SUCCESS(status)) {
  1738. PS_SET_BITS (&CurrentProcess->Flags, PS_PROCESS_FLAGS_FORK_FAILED);
  1739. if (Attached) {
  1740. KeUnstackDetachProcess (&ApcState);
  1741. }
  1742. return status;
  1743. }
  1744. status = PsChargeProcessNonPagedPoolQuota (CurrentProcess,
  1745. TotalNonPagedPoolCharge);
  1746. if (!NT_SUCCESS(status)) {
  1747. PsReturnProcessPagedPoolQuota (CurrentProcess, TotalPagedPoolCharge);
  1748. PS_SET_BITS (&CurrentProcess->Flags, PS_PROCESS_FLAGS_FORK_FAILED);
  1749. if (Attached) {
  1750. KeUnstackDetachProcess (&ApcState);
  1751. }
  1752. return status;
  1753. }
  1754. ASSERT ((ProcessToClone->Flags & PS_PROCESS_FLAGS_FORK_FAILED) == 0);
  1755. ASSERT ((CurrentProcess->Flags & PS_PROCESS_FLAGS_FORK_FAILED) == 0);
  1756. if (Attached) {
  1757. KeUnstackDetachProcess (&ApcState);
  1758. }
  1759. return STATUS_SUCCESS;
  1760. //
  1761. // Error returns.
  1762. //
  1763. ErrorReturn3:
  1764. #if (_MI_PAGING_LEVELS >= 4)
  1765. if (PxeBase != NULL) {
  1766. MiUnmapSinglePage (PxeBase);
  1767. }
  1768. #endif
  1769. #if (_MI_PAGING_LEVELS >= 3)
  1770. if (PpeBase != NULL) {
  1771. MiUnmapSinglePage (PpeBase);
  1772. }
  1773. if (PdeBase != NULL) {
  1774. MiUnmapSinglePage (PdeBase);
  1775. }
  1776. #else
  1777. if (HyperBase != NULL) {
  1778. MiUnmapSinglePage (HyperBase);
  1779. }
  1780. if (PdeBase != NULL) {
  1781. #if !defined (_X86PAE_)
  1782. MiUnmapSinglePage (PdeBase);
  1783. #else
  1784. MmUnmapLockedPages (PdeBase, MdlPageDirectory);
  1785. #endif
  1786. }
  1787. #endif
  1788. ErrorReturn2:
  1789. CurrentProcess->ForkInProgress = NULL;
  1790. UNLOCK_WS (CurrentProcess);
  1791. if (ChargedClonePoolQuota == TRUE) {
  1792. PsReturnProcessPagedPoolQuota (CurrentProcess, sizeof(MMCLONE_BLOCK) *
  1793. NumberOfPrivatePages);
  1794. PsReturnProcessNonPagedPoolQuota (CurrentProcess, sizeof(MMCLONE_HEADER));
  1795. }
  1796. PhysicalView = PhysicalViewList;
  1797. while (PhysicalView != NULL) {
  1798. NextPhysicalView = (PMI_PHYSICAL_VIEW) PhysicalView->u1.Parent;
  1799. ExFreePool (PhysicalView);
  1800. PhysicalView = NextPhysicalView;
  1801. }
  1802. NewVad = FirstNewVad;
  1803. while (NewVad != NULL) {
  1804. Vad = NewVad->u1.Parent;
  1805. ExFreePool (NewVad);
  1806. NewVad = Vad;
  1807. }
  1808. if (CloneDescriptor != NULL) {
  1809. ExFreePool (CloneDescriptor);
  1810. }
  1811. if (CloneHeader != NULL) {
  1812. ExFreePool (CloneHeader);
  1813. }
  1814. if (CloneProtos != NULL) {
  1815. ExFreePool (CloneProtos);
  1816. }
  1817. ErrorReturn1:
  1818. UNLOCK_ADDRESS_SPACE (CurrentProcess);
  1819. if (TargetCloneRoot != NULL) {
  1820. ExFreePool (TargetCloneRoot);
  1821. }
  1822. ASSERT ((CurrentProcess->Flags & PS_PROCESS_FLAGS_FORK_FAILED) == 0);
  1823. if (Attached) {
  1824. KeUnstackDetachProcess (&ApcState);
  1825. }
  1826. return status;
  1827. }
  1828. ULONG
  1829. MiDecrementCloneBlockReference (
  1830. IN PMMCLONE_DESCRIPTOR CloneDescriptor,
  1831. IN PMMCLONE_BLOCK CloneBlock,
  1832. IN PEPROCESS CurrentProcess,
  1833. IN KIRQL OldIrql
  1834. )
  1835. /*++
  1836. Routine Description:
  1837. This routine decrements the reference count field of a "fork prototype
  1838. PTE" (clone-block). If the reference count becomes zero, the reference
  1839. count for the clone-descriptor is decremented and if that becomes zero,
  1840. it is deallocated and the number of processes count for the clone header is
  1841. decremented. If the number of processes count becomes zero, the clone
  1842. header is deallocated.
  1843. Arguments:
  1844. CloneDescriptor - Supplies the clone descriptor which describes the
  1845. clone block.
  1846. CloneBlock - Supplies the clone block to decrement the reference count of.
  1847. CurrentProcess - Supplies the current process.
  1848. OldIrql - Supplies the IRQL the caller acquired the PFN lock at.
  1849. Return Value:
  1850. TRUE if the working set mutex was released, FALSE if it was not.
  1851. Environment:
  1852. Kernel mode, APCs disabled, address creation mutex, working set mutex
  1853. and PFN lock held.
  1854. --*/
  1855. {
  1856. PMMCLONE_HEADER CloneHeader;
  1857. ULONG MutexReleased;
  1858. MMPTE CloneContents;
  1859. PMMPFN Pfn3;
  1860. PMMPFN Pfn4;
  1861. LONG NewCount;
  1862. LOGICAL WsHeldSafe;
  1863. ASSERT (CurrentProcess == PsGetCurrentProcess ());
  1864. MutexReleased = FALSE;
  1865. //
  1866. // Note carefully : the clone descriptor count is decremented *BEFORE*
  1867. // dereferencing the pagable clone PTEs. This is because the working
  1868. // set mutex is released and reacquired if the clone PTEs need to be made
  1869. // resident for the dereference. And this opens a window where a fork
  1870. // could begin. This thread will wait for the fork to finish, but the
  1871. // fork will copy the clone descriptors (including this one) and get a
  1872. // stale descriptor reference count (too high by one) as our decrement
  1873. // will only occur in our descriptor and not the forked one.
  1874. //
  1875. // Decrementing the clone descriptor count *BEFORE* potentially
  1876. // releasing the working set mutex solves this entire problem.
  1877. //
  1878. // Note that after the decrement, the clone descriptor can
  1879. // only be referenced here if the count dropped to exactly zero. (If it
  1880. // was nonzero, some other thread may drive it to zero and free it in the
  1881. // gap where we release locks to inpage the clone block).
  1882. //
  1883. CloneDescriptor->NumberOfReferences -= 1;
  1884. ASSERT (CloneDescriptor->NumberOfReferences >= 0);
  1885. if (CloneDescriptor->NumberOfReferences == 0) {
  1886. //
  1887. // There are no longer any PTEs in this process which refer
  1888. // to the fork prototype PTEs for this clone descriptor.
  1889. // Remove the CloneDescriptor now so a fork won't see it either.
  1890. //
  1891. UNLOCK_PFN (OldIrql);
  1892. //
  1893. // MiRemoveClone and its callees are pagable so release the PFN
  1894. // lock now.
  1895. //
  1896. MiRemoveClone (CurrentProcess, CloneDescriptor);
  1897. MutexReleased = TRUE;
  1898. LOCK_PFN (OldIrql);
  1899. }
  1900. //
  1901. // Now process the clone PTE block and any other descriptor cleanup that
  1902. // may be needed.
  1903. //
  1904. MutexReleased = MiMakeSystemAddressValidPfnWs (CloneBlock, CurrentProcess, OldIrql);
  1905. while ((CurrentProcess->ForkInProgress != NULL) &&
  1906. (CurrentProcess->ForkInProgress != PsGetCurrentThread ())) {
  1907. UNLOCK_PFN (OldIrql);
  1908. MiWaitForForkToComplete (CurrentProcess);
  1909. LOCK_PFN (OldIrql);
  1910. MiMakeSystemAddressValidPfnWs (CloneBlock, CurrentProcess, OldIrql);
  1911. MutexReleased = TRUE;
  1912. }
  1913. NewCount = InterlockedDecrement (&CloneBlock->CloneRefCount);
  1914. ASSERT (NewCount >= 0);
  1915. if (NewCount == 0) {
  1916. CloneContents = CloneBlock->ProtoPte;
  1917. if (CloneContents.u.Long != 0) {
  1918. //
  1919. // The last reference to a fork prototype PTE has been removed.
  1920. // Deallocate any page file space and the transition page, if any.
  1921. //
  1922. ASSERT (CloneContents.u.Hard.Valid == 0);
  1923. //
  1924. // Assert that the PTE is not in subsection format (doesn't point
  1925. // to a file).
  1926. //
  1927. ASSERT (CloneContents.u.Soft.Prototype == 0);
  1928. if (CloneContents.u.Soft.Transition == 1) {
  1929. //
  1930. // Prototype PTE in transition, put the page on the free list.
  1931. //
  1932. Pfn3 = MI_PFN_ELEMENT (CloneContents.u.Trans.PageFrameNumber);
  1933. Pfn4 = MI_PFN_ELEMENT (Pfn3->u4.PteFrame);
  1934. MI_SET_PFN_DELETED (Pfn3);
  1935. MiDecrementShareCount (Pfn4, Pfn3->u4.PteFrame);
  1936. //
  1937. // Check the reference count for the page, if the reference
  1938. // count is zero and the page is not on the freelist,
  1939. // move the page to the free list, if the reference
  1940. // count is not zero, ignore this page.
  1941. // When the reference count goes to zero, it will be placed
  1942. // on the free list.
  1943. //
  1944. if ((Pfn3->u3.e2.ReferenceCount == 0) &&
  1945. (Pfn3->u3.e1.PageLocation != FreePageList)) {
  1946. MiUnlinkPageFromList (Pfn3);
  1947. MiReleasePageFileSpace (Pfn3->OriginalPte);
  1948. MiInsertPageInFreeList (MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&CloneContents));
  1949. }
  1950. }
  1951. else {
  1952. if (IS_PTE_NOT_DEMAND_ZERO (CloneContents)) {
  1953. MiReleasePageFileSpace (CloneContents);
  1954. }
  1955. }
  1956. }
  1957. }
  1958. //
  1959. // Decrement the final number of references to the clone descriptor. The
  1960. // decrement of the NumberOfReferences above serves to decide
  1961. // whether to remove the clone descriptor from the process tree so that
  1962. // a wait on a paged out clone PTE block doesn't let a fork copy the
  1963. // descriptor while it is half-changed.
  1964. //
  1965. // The FinalNumberOfReferences serves as a way to distinguish which
  1966. // thread (multiple threads may have collided waiting for the inpage
  1967. // of the clone PTE block) is the last one to wake up from the wait as
  1968. // only this one (it may not be the same one who drove NumberOfReferences
  1969. // to zero) can finally free the pool safely.
  1970. //
  1971. CloneDescriptor->FinalNumberOfReferences -= 1;
  1972. ASSERT (CloneDescriptor->FinalNumberOfReferences >= 0);
  1973. if (CloneDescriptor->FinalNumberOfReferences == 0) {
  1974. UNLOCK_PFN (OldIrql);
  1975. //
  1976. // There are no longer any PTEs in this process which refer
  1977. // to the fork prototype PTEs for this clone descriptor.
  1978. // Decrement the process reference count in the CloneHeader.
  1979. //
  1980. //
  1981. // The working set lock may have been acquired safely or unsafely
  1982. // by our caller. Handle both cases here and below.
  1983. //
  1984. UNLOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
  1985. MutexReleased = TRUE;
  1986. CloneHeader = CloneDescriptor->CloneHeader;
  1987. NewCount = InterlockedDecrement (&CloneHeader->NumberOfProcessReferences);
  1988. ASSERT (NewCount >= 0);
  1989. //
  1990. // If the count is zero, there are no more processes pointing
  1991. // to this fork header so blow it away.
  1992. //
  1993. if (NewCount == 0) {
  1994. #if DBG
  1995. ULONG i;
  1996. CloneBlock = CloneHeader->ClonePtes;
  1997. for (i = 0; i < CloneHeader->NumberOfPtes; i += 1) {
  1998. if (CloneBlock->CloneRefCount != 0) {
  1999. DbgBreakPoint ();
  2000. }
  2001. CloneBlock += 1;
  2002. }
  2003. #endif
  2004. ExFreePool (CloneHeader->ClonePtes);
  2005. ExFreePool (CloneHeader);
  2006. }
  2007. //
  2008. // Return the pool for the global structures referenced by the
  2009. // clone descriptor.
  2010. //
  2011. if ((CurrentProcess->Flags & PS_PROCESS_FLAGS_FORK_FAILED) == 0) {
  2012. //
  2013. // Fork succeeded so return quota that was taken out earlier.
  2014. //
  2015. PsReturnProcessPagedPoolQuota (CurrentProcess,
  2016. CloneDescriptor->PagedPoolQuotaCharge);
  2017. PsReturnProcessNonPagedPoolQuota (CurrentProcess,
  2018. sizeof(MMCLONE_HEADER));
  2019. }
  2020. ExFreePool (CloneDescriptor);
  2021. //
  2022. // The working set lock may have been acquired safely or unsafely
  2023. // by our caller. Reacquire it in the same manner our caller did.
  2024. //
  2025. LOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
  2026. LOCK_PFN (OldIrql);
  2027. }
  2028. return MutexReleased;
  2029. }
  2030. LOGICAL
  2031. MiWaitForForkToComplete (
  2032. IN PEPROCESS CurrentProcess
  2033. )
  2034. /*++
  2035. Routine Description:
  2036. This routine waits for the current process to complete a fork operation.
  2037. Arguments:
  2038. CurrentProcess - Supplies the current process value.
  2039. Return Value:
  2040. TRUE if the mutex was released and reacquired to wait. FALSE if not.
  2041. Environment:
  2042. Kernel mode, APCs disabled, working set mutex held.
  2043. --*/
  2044. {
  2045. LOGICAL WsHeldSafe;
  2046. //
  2047. // A fork operation is in progress and the count of clone-blocks
  2048. // and other structures may not be changed. Release the working
  2049. // set mutex and wait for the address creation mutex which governs the
  2050. // fork operation.
  2051. //
  2052. if (CurrentProcess->ForkInProgress == PsGetCurrentThread()) {
  2053. return FALSE;
  2054. }
  2055. //
  2056. // The working set mutex may have been acquired safely or unsafely
  2057. // by our caller. Handle both cases here and below, carefully making sure
  2058. // that the OldIrql left in the WS mutex on return is the same as on entry.
  2059. //
  2060. // Note it is ok to drop to PASSIVE or APC level here as long as it is
  2061. // not lower than our caller was at. Using the WorkingSetMutex whose irql
  2062. // field was initialized by our caller ensures that the proper irql
  2063. // environment is maintained (ie: the caller may be blocking APCs
  2064. // deliberately).
  2065. //
  2066. UNLOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
  2067. //
  2068. // Acquire the address creation mutex as this can only succeed when the
  2069. // forking thread is done in MiCloneProcessAddressSpace. Thus, acquiring
  2070. // this mutex doesn't stop another thread from starting another fork, but
  2071. // it does serve as a way to know the current fork is done (enough).
  2072. //
  2073. LOCK_ADDRESS_SPACE (CurrentProcess);
  2074. UNLOCK_ADDRESS_SPACE (CurrentProcess);
  2075. //
  2076. // The working set lock may have been acquired safely or unsafely
  2077. // by our caller. Reacquire it in the same manner our caller did.
  2078. //
  2079. LOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
  2080. return TRUE;
  2081. }
  2082. VOID
  2083. MiUpControlAreaRefs (
  2084. IN PMMVAD Vad
  2085. )
  2086. {
  2087. KIRQL OldIrql;
  2088. PCONTROL_AREA ControlArea;
  2089. PSUBSECTION FirstSubsection;
  2090. PSUBSECTION LastSubsection;
  2091. ControlArea = Vad->ControlArea;
  2092. LOCK_PFN (OldIrql);
  2093. ControlArea->NumberOfMappedViews += 1;
  2094. ControlArea->NumberOfUserReferences += 1;
  2095. if ((ControlArea->u.Flags.Image == 0) &&
  2096. (ControlArea->FilePointer != NULL) &&
  2097. (ControlArea->u.Flags.PhysicalMemory == 0)) {
  2098. FirstSubsection = MiLocateSubsection (Vad, Vad->StartingVpn);
  2099. //
  2100. // Note LastSubsection may be NULL for extendable VADs when
  2101. // the EndingVpn is past the end of the section. In this
  2102. // case, all the subsections can be safely incremented.
  2103. //
  2104. // Note also that the reference must succeed because each
  2105. // subsection's prototype PTEs are guaranteed to already
  2106. // exist by virtue of the fact that the creating process
  2107. // already has this VAD currently mapping them.
  2108. //
  2109. LastSubsection = MiLocateSubsection (Vad, Vad->EndingVpn);
  2110. while (FirstSubsection != LastSubsection) {
  2111. MiReferenceSubsection ((PMSUBSECTION) FirstSubsection);
  2112. FirstSubsection = FirstSubsection->NextSubsection;
  2113. }
  2114. if (LastSubsection != NULL) {
  2115. MiReferenceSubsection ((PMSUBSECTION) LastSubsection);
  2116. }
  2117. }
  2118. UNLOCK_PFN (OldIrql);
  2119. return;
  2120. }
  2121. ULONG
  2122. MiDoneWithThisPageGetAnother (
  2123. IN PPFN_NUMBER PageFrameIndex,
  2124. IN PMMPTE PointerPde,
  2125. IN PEPROCESS CurrentProcess
  2126. )
  2127. {
  2128. PMMPFN Pfn1;
  2129. KIRQL OldIrql;
  2130. ULONG ReleasedMutex;
  2131. UNREFERENCED_PARAMETER (PointerPde);
  2132. ReleasedMutex = FALSE;
  2133. if (*PageFrameIndex != (PFN_NUMBER)-1) {
  2134. //
  2135. // Decrement the share count of the last page which
  2136. // we operated on.
  2137. //
  2138. Pfn1 = MI_PFN_ELEMENT (*PageFrameIndex);
  2139. LOCK_PFN (OldIrql);
  2140. MiDecrementShareCount (Pfn1, *PageFrameIndex);
  2141. }
  2142. else {
  2143. LOCK_PFN (OldIrql);
  2144. }
  2145. if (MmAvailablePages < MM_HIGH_LIMIT) {
  2146. ReleasedMutex = MiEnsureAvailablePageOrWait (CurrentProcess, NULL, OldIrql);
  2147. }
  2148. *PageFrameIndex = MiRemoveZeroPage (
  2149. MI_PAGE_COLOR_PTE_PROCESS (PointerPde,
  2150. &CurrentProcess->NextPageColor));
  2151. //
  2152. // Temporarily mark the page as bad so that contiguous memory allocators
  2153. // won't steal it when we release the PFN lock below. This also prevents
  2154. // the MiIdentifyPfn code from trying to identify it as we haven't filled
  2155. // in all the fields yet.
  2156. //
  2157. Pfn1 = MI_PFN_ELEMENT (*PageFrameIndex);
  2158. Pfn1->u3.e1.PageLocation = BadPageList;
  2159. UNLOCK_PFN (OldIrql);
  2160. return ReleasedMutex;
  2161. }
  2162. ULONG
  2163. MiLeaveThisPageGetAnother (
  2164. OUT PPFN_NUMBER PageFrameIndex,
  2165. IN PMMPTE PointerPde,
  2166. IN PEPROCESS CurrentProcess
  2167. )
  2168. {
  2169. KIRQL OldIrql;
  2170. ULONG ReleasedMutex;
  2171. PMMPFN Pfn1;
  2172. UNREFERENCED_PARAMETER (PointerPde);
  2173. ReleasedMutex = FALSE;
  2174. LOCK_PFN (OldIrql);
  2175. if (MmAvailablePages < MM_HIGH_LIMIT) {
  2176. ReleasedMutex = MiEnsureAvailablePageOrWait (CurrentProcess, NULL, OldIrql);
  2177. }
  2178. *PageFrameIndex = MiRemoveZeroPage (
  2179. MI_PAGE_COLOR_PTE_PROCESS (PointerPde,
  2180. &CurrentProcess->NextPageColor));
  2181. //
  2182. // Temporarily mark the page as bad so that contiguous memory allocators
  2183. // won't steal it when we release the PFN lock below. This also prevents
  2184. // the MiIdentifyPfn code from trying to identify it as we haven't filled
  2185. // in all the fields yet.
  2186. //
  2187. Pfn1 = MI_PFN_ELEMENT (*PageFrameIndex);
  2188. Pfn1->u3.e1.PageLocation = BadPageList;
  2189. UNLOCK_PFN (OldIrql);
  2190. return ReleasedMutex;
  2191. }
  2192. ULONG
  2193. MiHandleForkTransitionPte (
  2194. IN PMMPTE PointerPte,
  2195. IN PMMPTE PointerNewPte,
  2196. IN PMMCLONE_BLOCK ForkProtoPte
  2197. )
  2198. {
  2199. KIRQL OldIrql;
  2200. PMMPFN Pfn2;
  2201. PMMPFN Pfn3;
  2202. MMPTE PteContents;
  2203. PMMPTE ContainingPte;
  2204. PFN_NUMBER PageTablePage;
  2205. MMPTE TempPte;
  2206. PMMPFN PfnForkPtePage;
  2207. LOCK_PFN (OldIrql);
  2208. //
  2209. // Now that we have the PFN lock which prevents pages from
  2210. // leaving the transition state, examine the PTE again to
  2211. // ensure that it is still transition.
  2212. //
  2213. PteContents = *PointerPte;
  2214. if ((PteContents.u.Soft.Transition == 0) ||
  2215. (PteContents.u.Soft.Prototype == 1)) {
  2216. //
  2217. // The PTE is no longer in transition... do this loop again.
  2218. //
  2219. UNLOCK_PFN (OldIrql);
  2220. return TRUE;
  2221. }
  2222. //
  2223. // The PTE is still in transition, handle like a valid PTE.
  2224. //
  2225. Pfn2 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber);
  2226. //
  2227. // Assertion that PTE is not in prototype PTE format.
  2228. //
  2229. ASSERT (Pfn2->u3.e1.PrototypePte != 1);
  2230. //
  2231. // This is a private page in transition state,
  2232. // create a fork prototype PTE
  2233. // which becomes the "prototype" PTE for this page.
  2234. //
  2235. ForkProtoPte->ProtoPte = PteContents;
  2236. //
  2237. // Make the protection write-copy if writable.
  2238. //
  2239. MI_MAKE_PROTECT_WRITE_COPY (ForkProtoPte->ProtoPte);
  2240. ForkProtoPte->CloneRefCount = 2;
  2241. //
  2242. // Transform the PFN element to reference this new fork
  2243. // prototype PTE.
  2244. //
  2245. //
  2246. // Decrement the share count for the page table
  2247. // page which contains the PTE as it is no longer
  2248. // valid or in transition.
  2249. //
  2250. Pfn2->PteAddress = &ForkProtoPte->ProtoPte;
  2251. Pfn2->u3.e1.PrototypePte = 1;
  2252. //
  2253. // Make original PTE copy on write.
  2254. //
  2255. MI_MAKE_PROTECT_WRITE_COPY (Pfn2->OriginalPte);
  2256. ContainingPte = MiGetPteAddress (&ForkProtoPte->ProtoPte);
  2257. if (ContainingPte->u.Hard.Valid == 0) {
  2258. #if (_MI_PAGING_LEVELS < 3)
  2259. if (!NT_SUCCESS(MiCheckPdeForPagedPool (&ForkProtoPte->ProtoPte))) {
  2260. #endif
  2261. KeBugCheckEx (MEMORY_MANAGEMENT,
  2262. 0x61940,
  2263. (ULONG_PTR)&ForkProtoPte->ProtoPte,
  2264. (ULONG_PTR)ContainingPte->u.Long,
  2265. (ULONG_PTR)MiGetVirtualAddressMappedByPte(&ForkProtoPte->ProtoPte));
  2266. #if (_MI_PAGING_LEVELS < 3)
  2267. }
  2268. #endif
  2269. }
  2270. PageTablePage = Pfn2->u4.PteFrame;
  2271. Pfn2->u4.PteFrame = MI_GET_PAGE_FRAME_FROM_PTE (ContainingPte);
  2272. //
  2273. // Increment the share count for the page containing
  2274. // the fork prototype PTEs as we have just placed
  2275. // a transition PTE into the page.
  2276. //
  2277. PfnForkPtePage = MI_PFN_ELEMENT (ContainingPte->u.Hard.PageFrameNumber);
  2278. PfnForkPtePage->u2.ShareCount += 1;
  2279. TempPte.u.Long = MiProtoAddressForPte (Pfn2->PteAddress);
  2280. TempPte.u.Proto.Prototype = 1;
  2281. #if 0
  2282. //
  2283. // Note that NOACCESS transition PTEs must be treated specially -
  2284. // they cannot just be made prototype PTEs with the same protection
  2285. // as the prototype PTE in the clone block - rather they must explicitly
  2286. // put NO_ACCESS into the hardware PTE because faults always treat
  2287. // prototype PTEs as having accessible permissions (because they are
  2288. // typically shared amongst various processes with differing process
  2289. // protections).
  2290. //
  2291. //
  2292. // This cannot be enabled unless fault lookups walk the entire clone
  2293. // tree looking for an address match (it's not sorted like VAD tree).
  2294. //
  2295. if (PteContents.u.Soft.Protection & MM_GUARD_PAGE) {
  2296. TempPte.u.Long = 0;
  2297. TempPte.u.Soft.Protection = PteContents.u.Soft.Protection;
  2298. TempPte.u.Soft.PageFileHigh = MI_PTE_CLONE_LOOKUP_NEEDED;
  2299. }
  2300. #endif
  2301. MI_WRITE_INVALID_PTE (PointerPte, TempPte);
  2302. MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
  2303. //
  2304. // Decrement the share count for the page table
  2305. // page which contains the PTE as it is no longer
  2306. // valid or in transition.
  2307. //
  2308. Pfn3 = MI_PFN_ELEMENT (PageTablePage);
  2309. MiDecrementShareCount (Pfn3, PageTablePage);
  2310. UNLOCK_PFN (OldIrql);
  2311. return FALSE;
  2312. }
  2313. VOID
  2314. MiDownShareCountFlushEntireTb (
  2315. IN PFN_NUMBER PageFrameIndex
  2316. )
  2317. {
  2318. PMMPFN Pfn1;
  2319. KIRQL OldIrql;
  2320. if (PageFrameIndex != (PFN_NUMBER)-1) {
  2321. //
  2322. // Decrement the share count of the last page which
  2323. // we operated on.
  2324. //
  2325. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  2326. LOCK_PFN (OldIrql);
  2327. MiDecrementShareCount (Pfn1, PageFrameIndex);
  2328. }
  2329. else {
  2330. LOCK_PFN (OldIrql);
  2331. }
  2332. KeFlushProcessTb (FALSE);
  2333. UNLOCK_PFN (OldIrql);
  2334. return;
  2335. }
  2336. VOID
  2337. MiUpForkPageShareCount (
  2338. IN PMMPFN PfnForkPtePage
  2339. )
  2340. {
  2341. KIRQL OldIrql;
  2342. LOCK_PFN (OldIrql);
  2343. PfnForkPtePage->u2.ShareCount += 1;
  2344. UNLOCK_PFN (OldIrql);
  2345. return;
  2346. }
  2347. VOID
  2348. MiBuildForkPageTable (
  2349. IN PFN_NUMBER PageFrameIndex,
  2350. IN PMMPTE PointerPde,
  2351. IN PMMPTE PointerNewPde,
  2352. IN PFN_NUMBER PdePhysicalPage,
  2353. IN PMMPFN PfnPdPage,
  2354. IN LOGICAL MakeValid
  2355. )
  2356. {
  2357. KIRQL OldIrql;
  2358. PMMPFN Pfn1;
  2359. #if (_MI_PAGING_LEVELS >= 3)
  2360. MMPTE TempPpe;
  2361. #endif
  2362. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  2363. //
  2364. // The PFN lock must be held while initializing the
  2365. // frame to prevent those scanning the database for free
  2366. // frames from taking it after we fill in the u2 field.
  2367. //
  2368. LOCK_PFN (OldIrql);
  2369. Pfn1->OriginalPte = DemandZeroPde;
  2370. Pfn1->u2.ShareCount = 1;
  2371. Pfn1->u3.e2.ReferenceCount = 1;
  2372. Pfn1->PteAddress = PointerPde;
  2373. MI_SET_MODIFIED (Pfn1, 1, 0x10);
  2374. Pfn1->u3.e1.PageLocation = ActiveAndValid;
  2375. Pfn1->u3.e1.CacheAttribute = MiCached;
  2376. Pfn1->u4.PteFrame = PdePhysicalPage;
  2377. //
  2378. // Increment the share count for the page containing
  2379. // this PTE as the PTE is in transition.
  2380. //
  2381. PfnPdPage->u2.ShareCount += 1;
  2382. UNLOCK_PFN (OldIrql);
  2383. if (MakeValid == TRUE) {
  2384. #if (_MI_PAGING_LEVELS >= 3)
  2385. //
  2386. // Put the PPE into the valid state as it will point at a page
  2387. // directory page that is valid (not transition) when the fork is
  2388. // complete. All the page table pages will be in transition, but
  2389. // the page directories cannot be as they contain the PTEs for the
  2390. // page tables.
  2391. //
  2392. TempPpe = ValidPdePde;
  2393. MI_MAKE_VALID_PTE (TempPpe,
  2394. PageFrameIndex,
  2395. MM_READWRITE,
  2396. PointerPde);
  2397. MI_SET_PTE_DIRTY (TempPpe);
  2398. //
  2399. // Make the PTE owned by user mode.
  2400. //
  2401. MI_SET_OWNER_IN_PTE (PointerNewPde, UserMode);
  2402. MI_WRITE_VALID_PTE (PointerNewPde, TempPpe);
  2403. #endif
  2404. }
  2405. else {
  2406. //
  2407. // Put the PDE into the transition state as it is not
  2408. // really mapped and decrement share count does not
  2409. // put private pages into transition, only prototypes.
  2410. //
  2411. MI_WRITE_INVALID_PTE (PointerNewPde, TransitionPde);
  2412. //
  2413. // Make the PTE owned by user mode.
  2414. //
  2415. MI_SET_OWNER_IN_PTE (PointerNewPde, UserMode);
  2416. PointerNewPde->u.Trans.PageFrameNumber = PageFrameIndex;
  2417. }
  2418. return;
  2419. }