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.

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