00109 :
00110
00111 This routine stands on its head to produce a copy of
the specified
00112 process's address space in
the process to initialize. This
00113
is done by examining each
virtual address descriptor's inherit
00114 attributes. If
the pages described by
the VAD should be inherited,
00115 each PTE
is examined and copied into
the new address space.
00116
00117 For
private pages, fork prototype PTEs are constructed and
the pages
00118 become shared, copy-on-write, between
the two processes.
00119
00120
00121 Arguments:
00122
00123 ProcessToClone - Supplies
the process whose address space should be
00124 cloned.
00125
00126 ProcessToInitialize - Supplies
the process whose address space
is to
00127 be created.
00128
00129 RootPhysicalPage - Supplies
the physical page number of
the top level
00130 page (parent on 64-bit systems) directory
00131 of
the process to initialize.
00132
00133 HyperPhysicalPage - Supplies
the physical page number of
the page table
00134 page which maps hyperspace
for the process to
00135 initialize. This
is only needed
for 32-bit systems.
00136
00137 Return Value:
00138
00139 None.
00140
00141 Environment:
00142
00143 Kernel mode, APCs disabled.
00144
00145 --*/
00146
00147 {
00148 PFN_NUMBER PpePhysicalPage;
00149 PFN_NUMBER PdePhysicalPage;
00150
PEPROCESS CurrentProcess;
00151
PMMPTE PdeBase;
00152
PMMCLONE_HEADER CloneHeader;
00153
PMMCLONE_BLOCK CloneProtos;
00154
PMMCLONE_DESCRIPTOR CloneDescriptor;
00155
PMMVAD NewVad;
00156
PMMVAD Vad;
00157
PMMVAD NextVad;
00158
PMMVAD *VadList;
00159
PMMVAD FirstNewVad;
00160
PMMCLONE_DESCRIPTOR *CloneList;
00161
PMMCLONE_DESCRIPTOR FirstNewClone;
00162
PMMCLONE_DESCRIPTOR Clone;
00163
PMMCLONE_DESCRIPTOR NextClone;
00164
PMMCLONE_DESCRIPTOR NewClone;
00165 ULONG Attached;
00166 ULONG CloneFailed;
00167 ULONG VadInsertFailed;
00168
WSLE_NUMBER WorkingSetIndex;
00169 PVOID VirtualAddress;
00170
NTSTATUS status;
00171
PMMPFN Pfn2;
00172
PMMPFN PfnPdPage;
00173
MMPTE TempPte;
00174
MMPTE PteContents;
00175
#if defined (_X86PAE_)
00176
PMDL MdlPageDirectory;
00177 PPFN_NUMBER MdlPageFrames;
00178 PFN_NUMBER PageDirectoryFrames[PD_PER_SYSTEM];
00179 PFN_NUMBER MdlHackPageDirectory[(
sizeof(
MDL)/
sizeof(PFN_NUMBER)) + PD_PER_SYSTEM];
00180
#endif
00181
PFN_NUMBER MdlPage;
00182 PFN_NUMBER MdlDirPage;
00183
PMMPTE PointerPte;
00184
PMMPTE PointerPde;
00185
PMMPTE PointerPpe;
00186
PMMPTE LastPte;
00187
PMMPTE PointerNewPte;
00188
PMMPTE NewPteMappedAddress;
00189
PMMPTE PointerNewPde;
00190 PLIST_ENTRY NextEntry;
00191
PMI_PHYSICAL_VIEW PhysicalView;
00192 PFN_NUMBER PageFrameIndex;
00193 PFN_NUMBER PageDirFrameIndex;
00194
PMMCLONE_BLOCK ForkProtoPte;
00195
PMMCLONE_BLOCK CloneProto;
00196
PMMCLONE_BLOCK LockedForkPte;
00197
PMMPTE ContainingPte;
00198 ULONG NumberOfForkPtes;
00199 PFN_NUMBER NumberOfPrivatePages;
00200 PFN_NUMBER PageTablePage;
00201 SIZE_T TotalPagedPoolCharge;
00202 SIZE_T TotalNonPagedPoolCharge;
00203
PMMPFN PfnForkPtePage;
00204 PVOID UsedPageTableEntries;
00205 ULONG ReleasedWorkingSetMutex;
00206 ULONG FirstTime;
00207 ULONG Waited;
00208 ULONG i;
00209 ULONG PpePdeOffset;
00210
#if defined (_WIN64)
00211
PVOID UsedPageDirectoryEntries;
00212
PMMPTE PointerNewPpe;
00213
PMMPTE PpeBase;
00214
PMMPFN PfnPpPage;
00215
#else
00216
PMMWSL HyperBase;
00217
#endif
00218
00219 PageTablePage = 2;
00220 NumberOfForkPtes = 0;
00221 Attached =
FALSE;
00222 PageFrameIndex = (PFN_NUMBER)-1;
00223 PageDirFrameIndex = (PFN_NUMBER)-1;
00224
00225
#if DBG
00226
if (MmDebug &
MM_DBG_FORK) {
00227
DbgPrint(
"beginning clone operation process to clone = %lx\n",
00228 ProcessToClone);
00229 }
00230
#endif //DBG
00231
00232
PAGED_CODE();
00233
00234
if (ProcessToClone !=
PsGetCurrentProcess()) {
00235 Attached =
TRUE;
00236
KeAttachProcess (&ProcessToClone->Pcb);
00237 }
00238
00239
#if defined (_X86PAE_)
00240
MiRetrievePageDirectoryFrames (RootPhysicalPage, PageDirectoryFrames);
00241
#endif
00242
00243 CurrentProcess = ProcessToClone;
00244
00245
00246
00247
00248
00249
00250
00251
00252
LOCK_ADDRESS_SPACE (CurrentProcess);
00253
00254
00255
00256
00257
00258
00259
if (CurrentProcess->
Vm.
u.Flags.WriteWatch == 1) {
00260 status = STATUS_INVALID_PAGE_PROTECTION;
00261
goto ErrorReturn1;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270 NextEntry = CurrentProcess->
PhysicalVadList.Flink;
00271
while (NextEntry != &CurrentProcess->
PhysicalVadList) {
00272
00273 PhysicalView = CONTAINING_RECORD(NextEntry,
00274
MI_PHYSICAL_VIEW,
00275 ListEntry);
00276
00277
if (PhysicalView->
Vad->
u.VadFlags.UserPhysicalPages == 1) {
00278 status = STATUS_INVALID_PAGE_PROTECTION;
00279
goto ErrorReturn1;
00280 }
00281
00282 NextEntry = NextEntry->Flink;
00283 }
00284
00285
00286
00287
00288
00289
if (CurrentProcess->
AddressSpaceDeleted != 0) {
00290 status = STATUS_PROCESS_IS_TERMINATING;
00291
goto ErrorReturn1;
00292 }
00293
00294
00295
00296
00297
00298
00299
00300 NumberOfPrivatePages = CurrentProcess->
NumberOfPrivatePages;
00301
00302 CloneProtos =
ExAllocatePoolWithTag (PagedPool,
sizeof(
MMCLONE_BLOCK) *
00303 NumberOfPrivatePages,
00304 'lCmM');
00305
if (CloneProtos ==
NULL) {
00306 status = STATUS_INSUFFICIENT_RESOURCES;
00307
goto ErrorReturn1;
00308 }
00309
00310 CloneHeader =
ExAllocatePoolWithTag (NonPagedPool,
00311
sizeof(
MMCLONE_HEADER),
00312 ' mM');
00313
if (CloneHeader ==
NULL) {
00314 status = STATUS_INSUFFICIENT_RESOURCES;
00315
goto ErrorReturn2;
00316 }
00317
00318 CloneDescriptor =
ExAllocatePoolWithTag (NonPagedPool,
00319
sizeof(
MMCLONE_DESCRIPTOR),
00320 ' mM');
00321
if (CloneDescriptor ==
NULL) {
00322 status = STATUS_INSUFFICIENT_RESOURCES;
00323
goto ErrorReturn3;
00324 }
00325
00326 Vad =
MiGetFirstVad (CurrentProcess);
00327 VadList = &FirstNewVad;
00328
00329
while (Vad != (
PMMVAD)
NULL) {
00330
00331
00332
00333
00334
00335
if ((Vad->
u.VadFlags.UserPhysicalPages == 0) &&
00336
00337 ((Vad->
u.VadFlags.PrivateMemory == 1) ||
00338 (Vad->
u2.VadFlags2.Inherit ==
MM_VIEW_SHARE))) {
00339
00340 NewVad =
ExAllocatePoolWithTag (NonPagedPool,
sizeof(
MMVAD), ' daV');
00341
00342
if (NewVad ==
NULL) {
00343
00344
00345
00346
00347
00348
00349 *VadList = (
PMMVAD)
NULL;
00350 status = STATUS_INSUFFICIENT_RESOURCES;
00351
goto ErrorReturn4;
00352 }
00353 *VadList = NewVad;
00354 VadList = &NewVad->
Parent;
00355 }
00356 Vad =
MiGetNextVad (Vad);
00357 }
00358
00359
00360
00361
00362
00363 *VadList = (
PMMVAD)
NULL;
00364
00365
00366
00367
00368
00369
00370
00371
try {
00372
PsChargePoolQuota (CurrentProcess, PagedPool,
sizeof(
MMCLONE_BLOCK) *
00373 NumberOfPrivatePages);
00374 PageTablePage = 1;
00375
PsChargePoolQuota (CurrentProcess, NonPagedPool,
sizeof(
MMCLONE_HEADER));
00376 PageTablePage = 0;
00377
00378 } except (EXCEPTION_EXECUTE_HANDLER) {
00379
00380
00381
00382
00383
00384 status = GetExceptionCode();
00385
goto ErrorReturn4;
00386 }
00387
00388
LOCK_WS (CurrentProcess);
00389
00390
ASSERT (CurrentProcess->
ForkInProgress == NULL);
00391
00392
00393
00394
00395
00396
00397
00398 CurrentProcess->
ForkInProgress =
PsGetCurrentThread();
00399
00400
#if defined (_WIN64)
00401
00402
00403
00404
00405
00406
00407
00408
00409
MiUpPfnReferenceCount (RootPhysicalPage, 3);
00410
00411
00412
00413
00414
00415
00416
00417 PpeBase = (
PMMPTE)
MiMapSinglePage (NULL,
00418 RootPhysicalPage,
00419 MmCached,
00420 HighPagePriority);
00421
00422
if (PpeBase ==
NULL) {
00423
MiDownPfnReferenceCount (RootPhysicalPage, 3);
00424 CurrentProcess->
ForkInProgress =
NULL;
00425
UNLOCK_WS (CurrentProcess);
00426 status = STATUS_INSUFFICIENT_RESOURCES;
00427
goto ErrorReturn4;
00428 }
00429
00430 PfnPpPage =
MI_PFN_ELEMENT (RootPhysicalPage);
00431
00432
#else
00433
00434
#if !defined (_X86PAE_)
00435
MiUpPfnReferenceCount (RootPhysicalPage, 1);
00436
#endif
00437
00438
#endif
00439
00440
00441
00442
00443
00444
00445
00446
00447
#if !defined (_X86PAE_)
00448
00449 MdlDirPage = RootPhysicalPage;
00450
00451 PdePhysicalPage = RootPhysicalPage;
00452
00453 PdeBase = (
PMMPTE)
MiMapSinglePage (NULL,
00454 MdlDirPage,
00455 MmCached,
00456 HighPagePriority);
00457
00458
if (PdeBase ==
NULL) {
00459
#if defined (_WIN64)
00460
MiDownPfnReferenceCount (RootPhysicalPage, 3);
00461
MiUnmapSinglePage (PpeBase);
00462
#else
00463
MiDownPfnReferenceCount (RootPhysicalPage, 1);
00464
#endif
00465
CurrentProcess->
ForkInProgress =
NULL;
00466
UNLOCK_WS (CurrentProcess);
00467 status = STATUS_INSUFFICIENT_RESOURCES;
00468
goto ErrorReturn4;
00469 }
00470
00471
#else
00472
00473
00474
00475
00476
00477
00478 MdlPageDirectory = (
PMDL)&MdlHackPageDirectory[0];
00479
00480
MmInitializeMdl(MdlPageDirectory, (PVOID)PDE_BASE, PD_PER_SYSTEM * PAGE_SIZE);
00481 MdlPageDirectory->
MdlFlags |=
MDL_PAGES_LOCKED;
00482
00483 MdlPageFrames = (PPFN_NUMBER)(MdlPageDirectory + 1);
00484
00485
for (i = 0; i < PD_PER_SYSTEM; i += 1) {
00486 *(MdlPageFrames + i) = PageDirectoryFrames[i];
00487
MiUpPfnReferenceCount (PageDirectoryFrames[i], 1);
00488 }
00489
00490 PdePhysicalPage = RootPhysicalPage;
00491
00492 PdeBase = (
PMMPTE)
MmMapLockedPagesSpecifyCache (MdlPageDirectory,
00493 KernelMode,
00494 MmCached,
00495 NULL,
00496 FALSE,
00497 HighPagePriority);
00498
00499
if (PdeBase ==
NULL) {
00500
for (i = 0; i < PD_PER_SYSTEM; i += 1) {
00501
MiDownPfnReferenceCount (PageDirectoryFrames[i], 1);
00502 }
00503 CurrentProcess->
ForkInProgress =
NULL;
00504
UNLOCK_WS (CurrentProcess);
00505 status = STATUS_INSUFFICIENT_RESOURCES;
00506
goto ErrorReturn4;
00507 }
00508
00509
#endif
00510
00511 PfnPdPage =
MI_PFN_ELEMENT (RootPhysicalPage);
00512
00513
#if !defined (_WIN64)
00514
00515
00516
00517
00518
00519
MiUpPfnReferenceCount (HyperPhysicalPage, 2);
00520
00521 HyperBase = (
PMMWSL)
MiMapSinglePage (NULL,
00522 HyperPhysicalPage,
00523 MmCached,
00524 HighPagePriority);
00525
00526
if (HyperBase ==
NULL) {
00527
MiDownPfnReferenceCount (HyperPhysicalPage, 2);
00528
#if !defined (_X86PAE_)
00529
MiDownPfnReferenceCount (RootPhysicalPage, 1);
00530
MiUnmapSinglePage (PdeBase);
00531
#else
00532
for (i = 0; i < PD_PER_SYSTEM; i += 1) {
00533
MiDownPfnReferenceCount (PageDirectoryFrames[i], 1);
00534 }
00535
MmUnmapLockedPages (PdeBase, MdlPageDirectory);
00536
#endif
00537
CurrentProcess->
ForkInProgress =
NULL;
00538
UNLOCK_WS (CurrentProcess);
00539 status = STATUS_INSUFFICIENT_RESOURCES;
00540
goto ErrorReturn4;
00541 }
00542
#endif
00543
00544
00545
00546
00547
00548
00549
00550
#if defined (_WIN64)
00551
MdlPage = RootPhysicalPage;
00552
#else
00553
MdlPage = HyperPhysicalPage;
00554
#endif
00555
00556 NewPteMappedAddress = (
PMMPTE)
MiMapSinglePage (NULL,
00557 MdlPage,
00558 MmCached,
00559 HighPagePriority);
00560
00561
if (NewPteMappedAddress ==
NULL) {
00562
00563
#if defined (_WIN64)
00564
00565
MiDownPfnReferenceCount (RootPhysicalPage, 3);
00566
MiUnmapSinglePage (PpeBase);
00567
MiUnmapSinglePage (PdeBase);
00568
00569
#else
00570
MiDownPfnReferenceCount (HyperPhysicalPage, 2);
00571
MiUnmapSinglePage (HyperBase);
00572
#if !defined (_X86PAE_)
00573
MiDownPfnReferenceCount (RootPhysicalPage, 1);
00574
MiUnmapSinglePage (PdeBase);
00575
#else
00576
for (i = 0; i < PD_PER_SYSTEM; i += 1) {
00577
MiDownPfnReferenceCount (PageDirectoryFrames[i], 1);
00578 }
00579
MmUnmapLockedPages (PdeBase, MdlPageDirectory);
00580
#endif
00581
00582
#endif
00583
00584 CurrentProcess->
ForkInProgress =
NULL;
00585
UNLOCK_WS (CurrentProcess);
00586 status = STATUS_INSUFFICIENT_RESOURCES;
00587
goto ErrorReturn4;
00588 }
00589
00590 PointerNewPte = NewPteMappedAddress;
00591
00592
00593
00594
00595
00596
00597 ForkProtoPte = CloneProtos;
00598
00599 LockedForkPte = ForkProtoPte;
00600
MiLockPagedAddress (LockedForkPte, FALSE);
00601
00602 CloneHeader->
NumberOfPtes = (ULONG)NumberOfPrivatePages;
00603 CloneHeader->
NumberOfProcessReferences = 1;
00604 CloneHeader->
ClonePtes = CloneProtos;
00605
00606
00607
00608 CloneDescriptor->
StartingVpn = (ULONG_PTR)CloneProtos;
00609 CloneDescriptor->
EndingVpn = (ULONG_PTR)((ULONG_PTR)CloneProtos +
00610 NumberOfPrivatePages *
00611
sizeof(
MMCLONE_BLOCK));
00612 CloneDescriptor->
NumberOfReferences = 0;
00613 CloneDescriptor->
NumberOfPtes = (ULONG)NumberOfPrivatePages;
00614 CloneDescriptor->
CloneHeader = CloneHeader;
00615 CloneDescriptor->
PagedPoolQuotaCharge =
sizeof(
MMCLONE_BLOCK) *
00616 NumberOfPrivatePages;
00617
00618
00619
00620
00621
00622
00623
MiInsertClone (CloneDescriptor);
00624
00625
00626
00627
00628
00629
00630 Vad =
MiGetFirstVad (CurrentProcess);
00631 NewVad = FirstNewVad;
00632
00633
while (Vad != (
PMMVAD)
NULL) {
00634
00635
00636
00637
00638
00639
00640
if ((Vad->
u.VadFlags.UserPhysicalPages == 0) &&
00641
00642 ((Vad->
u.VadFlags.PrivateMemory == 1) ||
00643 (Vad->
u2.VadFlags2.Inherit ==
MM_VIEW_SHARE))) {
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656 NextVad = NewVad->
Parent;
00657
00658
00659
if (Vad->
u.VadFlags.PrivateMemory == 1) {
00660 *(
PMMVAD_SHORT)NewVad = *(
PMMVAD_SHORT)Vad;
00661 NewVad->
u.VadFlags.NoChange = 0;
00662 }
else {
00663 *NewVad = *Vad;
00664 }
00665
00666
if (NewVad->
u.VadFlags.NoChange) {
00667
if ((NewVad->
u2.VadFlags2.OneSecured) ||
00668 (NewVad->
u2.VadFlags2.MultipleSecured)) {
00669
00670
00671
00672
00673
00674
00675 NewVad->
u2.VadFlags2.OneSecured = 0;
00676 NewVad->
u2.VadFlags2.MultipleSecured = 0;
00677 NewVad->
u2.VadFlags2.StoredInVad = 0;
00678 NewVad->
u3.List.Flink =
NULL;
00679 NewVad->
u3.List.Blink =
NULL;
00680 }
00681
if (NewVad->
u2.VadFlags2.SecNoChange == 0) {
00682 NewVad->
u.VadFlags.NoChange = 0;
00683 }
00684 }
00685 NewVad->
Parent = NextVad;
00686
00687
00688
00689
00690
00691
00692
if ((Vad->
u.VadFlags.PrivateMemory == 0) &&
00693 (Vad->
ControlArea != (
PCONTROL_AREA)
NULL)) {
00694
00695
00696
00697
00698
00699
00700
MiUpControlAreaRefs (Vad->
ControlArea);
00701 }
00702
00703
00704
00705
00706
00707
00708 PointerPde =
MiGetPdeAddress (MI_VPN_TO_VA (Vad->
StartingVpn));
00709 PointerPte = (
volatile PMMPTE)
MiGetPteAddress (
00710 MI_VPN_TO_VA (Vad->
StartingVpn));
00711 LastPte =
MiGetPteAddress (MI_VPN_TO_VA (Vad->
EndingVpn));
00712 FirstTime =
TRUE;
00713
00714
while ((
PMMPTE)PointerPte <= LastPte) {
00715
00716
00717
00718
00719
00720
00721
00722
if ((FirstTime) ||
MiIsPteOnPdeBoundary (PointerPte)) {
00723
00724 PointerPpe =
MiGetPdeAddress (PointerPte);
00725 PointerPde =
MiGetPteAddress (PointerPte);
00726
00727
do {
00728
00729
while (!
MiDoesPpeExistAndMakeValid (PointerPpe,
00730 CurrentProcess,
00731 FALSE,
00732 &Waited)) {
00733
00734
00735
00736
00737
00738 PointerPpe += 1;
00739 PointerPde =
MiGetVirtualAddressMappedByPte (PointerPpe);
00740 PointerPte =
MiGetVirtualAddressMappedByPte (PointerPde);
00741
00742
if ((
PMMPTE)PointerPte > LastPte) {
00743
00744
00745
00746
00747
00748
goto AllDone;
00749 }
00750 }
00751
00752 Waited = 0;
00753
00754
while (!
MiDoesPdeExistAndMakeValid (PointerPde,
00755 CurrentProcess,
00756 FALSE,
00757 &Waited)) {
00758
00759
00760
00761
00762
00763 PointerPde += 1;
00764 PointerPte =
MiGetVirtualAddressMappedByPte (PointerPde);
00765
00766
if ((
PMMPTE)PointerPte > LastPte) {
00767
00768
00769
00770
00771
00772
goto AllDone;
00773 }
00774
#if defined (_WIN64)
00775
if (
MiIsPteOnPdeBoundary (PointerPde)) {
00776 PointerPpe =
MiGetPteAddress (PointerPde);
00777 Waited = 1;
00778
break;
00779 }
00780
#endif
00781
}
00782
00783 }
while (Waited != 0);
00784
00785 FirstTime =
FALSE;
00786
00787
#if defined (_WIN64)
00788
00789
00790
00791
00792
00793 PointerNewPpe = &PpeBase[
MiGetPdeOffset(PointerPte)];
00794
00795
if (PointerNewPpe->
u.Long == 0) {
00796
00797
00798
00799
00800
00801
00802
00803 ReleasedWorkingSetMutex =
00804
MiDoneWithThisPageGetAnother (&PageDirFrameIndex,
00805 PointerPpe,
00806 CurrentProcess);
00807
00808 MI_ZERO_USED_PAGETABLE_ENTRIES (
MI_PFN_ELEMENT(PageDirFrameIndex));
00809
00810
if (ReleasedWorkingSetMutex) {
00811
00812
do {
00813
00814
MiDoesPpeExistAndMakeValid (PointerPpe,
00815 CurrentProcess,
00816 FALSE,
00817 &Waited);
00818
00819 Waited = 0;
00820
00821
MiDoesPdeExistAndMakeValid (PointerPde,
00822 CurrentProcess,
00823 FALSE,
00824 &Waited);
00825 }
while (Waited != 0);
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
MiBuildForkPageTable (PageDirFrameIndex,
00840 PointerPpe,
00841 PointerNewPpe,
00842 RootPhysicalPage,
00843 PfnPpPage);
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
MiDownPfnReferenceCount (MdlDirPage, 1);
00854
00855 MdlDirPage = PageDirFrameIndex;
00856
00857
ASSERT (PdeBase != NULL);
00858
00859 PdeBase = (
PMMPTE)
MiMapSinglePage (PdeBase,
00860 MdlDirPage,
00861 MmCached,
00862 HighPagePriority);
00863
00864
MiUpPfnReferenceCount (MdlDirPage, 1);
00865
00866 PointerNewPde = PdeBase;
00867 }
00868
else {
00869
ASSERT (PointerNewPpe->
u.Hard.Valid == 1 ||
00870 PointerNewPpe->
u.Soft.Transition == 1);
00871
00872
if (PointerNewPpe->
u.Hard.Valid == 1) {
00873 PageDirFrameIndex =
MI_GET_PAGE_FRAME_FROM_PTE (PointerNewPpe);
00874 }
00875
else {
00876 PageDirFrameIndex =
MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerNewPpe);
00877 }
00878 }
00879
00880
00881
00882
00883
00884
00885
00886 PointerNewPde = (
PMMPTE)((ULONG_PTR)
PAGE_ALIGN(PointerNewPde) |
00887
BYTE_OFFSET (PointerPde));
00888
00889 PdePhysicalPage = PageDirFrameIndex;
00890
00891 PfnPdPage =
MI_PFN_ELEMENT (PdePhysicalPage);
00892
00893 UsedPageDirectoryEntries = (PVOID)PfnPdPage;
00894
#endif
00895
00896
00897
00898
00899
00900
00901 PpePdeOffset =
MiGetPpePdeOffset(
MiGetVirtualAddressMappedByPte(PointerPte));
00902 PointerNewPde = &PdeBase[PpePdeOffset];
00903
00904
if (PointerNewPde->
u.Long == 0) {
00905
00906
00907
00908
00909
00910
00911
00912 ReleasedWorkingSetMutex =
00913
MiDoneWithThisPageGetAnother (&PageFrameIndex,
00914 PointerPde,
00915 CurrentProcess);
00916
00917
if (ReleasedWorkingSetMutex) {
00918
00919
do {
00920
00921
MiDoesPpeExistAndMakeValid (PointerPpe,
00922 CurrentProcess,
00923 FALSE,
00924 &Waited);
00925
00926 Waited = 0;
00927
00928
MiDoesPdeExistAndMakeValid (PointerPde,
00929 CurrentProcess,
00930 FALSE,
00931 &Waited);
00932 }
while (Waited != 0);
00933 }
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
#if defined (_X86PAE_)
00947
PdePhysicalPage = PageDirectoryFrames[MiGetPdPteOffset(
MiGetVirtualAddressMappedByPte(PointerPte))];
00948 PfnPdPage =
MI_PFN_ELEMENT (PdePhysicalPage);
00949
#endif
00950
00951
MiBuildForkPageTable (PageFrameIndex,
00952 PointerPde,
00953 PointerNewPde,
00954 PdePhysicalPage,
00955 PfnPdPage);
00956
00957
#if defined (_WIN64)
00958
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryEntries);
00959
#endif
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
ASSERT (NewPteMappedAddress != NULL);
00970
00971
MiDownPfnReferenceCount (MdlPage, 1);
00972
00973 MdlPage = PageFrameIndex;
00974
00975 PointerNewPte = (
PMMPTE)
MiMapSinglePage (NewPteMappedAddress,
00976 MdlPage,
00977 MmCached,
00978 HighPagePriority);
00979
00980
ASSERT (PointerNewPte != NULL);
00981
00982
MiUpPfnReferenceCount (MdlPage, 1);
00983 }
00984
00985
00986
00987
00988
00989
00990
00991 PointerNewPte = (
PMMPTE)((ULONG_PTR)
PAGE_ALIGN(PointerNewPte) |
00992
BYTE_OFFSET (PointerPte));
00993
00994
#ifdef _WIN64
00995
UsedPageTableEntries = (PVOID)
MI_PFN_ELEMENT((PFN_NUMBER)PointerNewPde->
u.Hard.PageFrameNumber);
00996
#else
00997
#if !defined (_X86PAE_)
00998
UsedPageTableEntries = (PVOID)&HyperBase->
UsedPageTableEntries
00999 [
MiGetPteOffset( PointerPte )];
01000
#else
01001
UsedPageTableEntries = (PVOID)&HyperBase->
UsedPageTableEntries
01002 [
MiGetPpePdeOffset(
MiGetVirtualAddressMappedByPte(PointerPte))];
01003
#endif
01004
#endif
01005
01006 }
01007
01008
01009
01010
01011
01012
if (
PAGE_ALIGN (ForkProtoPte) !=
PAGE_ALIGN (LockedForkPte)) {
01013
MiUnlockPagedAddress (LockedForkPte, FALSE);
01014 LockedForkPte = ForkProtoPte;
01015
MiLockPagedAddress (LockedForkPte, FALSE);
01016 }
01017
01018
MiMakeSystemAddressValid (PointerPte, CurrentProcess);
01019
01020 PteContents = *PointerPte;
01021
01022
01023
01024
01025
01026
if (PteContents.
u.Long == 0) {
01027 NOTHING;
01028
01029 }
else if (PteContents.
u.Hard.Valid == 1) {
01030
01031
01032
01033
01034
01035 Pfn2 =
MI_PFN_ELEMENT (PteContents.
u.Hard.PageFrameNumber);
01036 VirtualAddress =
MiGetVirtualAddressMappedByPte (PointerPte);
01037 WorkingSetIndex =
MiLocateWsle (VirtualAddress,
01038 MmWorkingSetList,
01039 Pfn2->
u1.WsIndex);
01040
01041
ASSERT (WorkingSetIndex != WSLE_NULL_INDEX);
01042
01043
if (Pfn2->
u3.e1.PrototypePte == 1) {
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
if (
MmWsle[WorkingSetIndex].
u1.e1.SameProtectAsProto
01061 == 0) {
01062
01063
01064
01065
01066
01067
01068 TempPte.
u.Long = 0;
01069 TempPte.
u.Soft.Protection =
01070
MI_GET_PROTECTION_FROM_WSLE(&MmWsle[WorkingSetIndex]);
01071 TempPte.
u.Soft.PageFileHigh =
MI_PTE_LOOKUP_NEEDED;
01072
01073 }
else {
01074
01075
01076
01077
01078
01079 TempPte.
u.Long =
MiProtoAddressForPte (
01080 Pfn2->
PteAddress);
01081
01082
01083 }
01084
01085 TempPte.
u.Proto.Prototype = 1;
01086
MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
01087
01088
01089
01090
01091
01092
01093
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
01094
01095
01096
01097
01098
01099
01100
01101
if (
MiLocateCloneAddress ((PVOID)Pfn2->
PteAddress) !=
01102 (
PMMCLONE_DESCRIPTOR)
NULL) {
01103
01104
01105
01106
01107
01108
01109 CloneProto = (
PMMCLONE_BLOCK)Pfn2->
PteAddress;
01110
01111
MiUpCloneProtoRefCount (CloneProto,
01112 CurrentProcess);
01113
01114
if (
PAGE_ALIGN (ForkProtoPte) !=
01115
PAGE_ALIGN (LockedForkPte)) {
01116
MiUnlockPagedAddress (LockedForkPte, FALSE);
01117 LockedForkPte = ForkProtoPte;
01118
MiLockPagedAddress (LockedForkPte, FALSE);
01119 }
01120
01121
MiMakeSystemAddressValid (PointerPte,
01122 CurrentProcess);
01123 }
01124
01125 }
else {
01126
01127
01128
01129
01130
01131
01132
01133
01134
MI_MAKE_VALID_PTE_WRITE_COPY (PointerPte);
01135
01136 ForkProtoPte->ProtoPte = *PointerPte;
01137 ForkProtoPte->CloneRefCount = 2;
01138
01139
01140
01141
01142
01143
01144 Pfn2->
PteAddress = &ForkProtoPte->ProtoPte;
01145 Pfn2->
u3.e1.PrototypePte = 1;
01146
01147 ContainingPte =
MiGetPteAddress(&ForkProtoPte->ProtoPte);
01148
if (ContainingPte->
u.Hard.Valid == 0) {
01149
#if !defined (_WIN64)
01150
if (!
NT_SUCCESS(MiCheckPdeForPagedPool (&ForkProtoPte->ProtoPte))) {
01151
#endif
01152
KeBugCheckEx (MEMORY_MANAGEMENT,
01153 0x61940,
01154 (ULONG_PTR)&ForkProtoPte->ProtoPte,
01155 (ULONG_PTR)ContainingPte->
u.Long,
01156 (ULONG_PTR)
MiGetVirtualAddressMappedByPte(&ForkProtoPte->ProtoPte));
01157
#if !defined (_WIN64)
01158
}
01159
#endif
01160
}
01161 Pfn2->
PteFrame =
MI_GET_PAGE_FRAME_FROM_PTE (ContainingPte);
01162
01163
01164
01165
01166
01167
01168
01169
01170 PfnForkPtePage =
MI_PFN_ELEMENT (
01171 ContainingPte->
u.Hard.PageFrameNumber );
01172
01173
MiUpForkPageShareCount (PfnForkPtePage);
01174
01175
01176
01177
01178
01179
01180
MI_MAKE_PROTECT_WRITE_COPY (Pfn2->
OriginalPte);
01181
01182
01183
01184
01185
01186
01187
01188
MmWsle[WorkingSetIndex].
u1.e1.Protection =
01189
MI_GET_PROTECTION_FROM_SOFT_PTE(&Pfn2->
OriginalPte);
01190
01191
MmWsle[WorkingSetIndex].
u1.e1.SameProtectAsProto = 1;
01192
01193 TempPte.
u.Long =
MiProtoAddressForPte (Pfn2->
PteAddress);
01194 TempPte.
u.Proto.Prototype = 1;
01195
MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
01196
01197
01198
01199
01200
01201
01202
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
01203
01204
01205
01206
01207
01208 CurrentProcess->
NumberOfPrivatePages -= 1;
01209
01210 ForkProtoPte += 1;
01211 NumberOfForkPtes += 1;
01212
01213 }
01214
01215 }
else if (PteContents.
u.Soft.Prototype == 1) {
01216
01217
01218
01219
01220
01221
01222
01223
MI_WRITE_INVALID_PTE (PointerNewPte, PteContents);
01224
01225
01226
01227
01228
01229
01230
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
01231
01232
01233
01234
01235
01236
01237
01238 CloneProto = (
PMMCLONE_BLOCK)(
MiPteToProto(PointerPte));
01239
01240
if (
MiLocateCloneAddress ((PVOID)CloneProto) !=
01241 (
PMMCLONE_DESCRIPTOR)
NULL) {
01242
01243
01244
01245
01246
01247
01248
MiUpCloneProtoRefCount (CloneProto,
01249 CurrentProcess);
01250
01251
if (
PAGE_ALIGN (ForkProtoPte) !=
01252
PAGE_ALIGN (LockedForkPte)) {
01253
MiUnlockPagedAddress (LockedForkPte, FALSE);
01254 LockedForkPte = ForkProtoPte;
01255
MiLockPagedAddress (LockedForkPte, FALSE);
01256 }
01257
01258
MiMakeSystemAddressValid (PointerPte,
01259 CurrentProcess);
01260 }
01261
01262 }
else if (PteContents.
u.Soft.Transition == 1) {
01263
01264
01265
01266
01267
01268
if (
MiHandleForkTransitionPte (PointerPte,
01269 PointerNewPte,
01270 ForkProtoPte)) {
01271
01272
01273
01274
01275
continue;
01276 }
01277
01278
01279
01280
01281
01282
01283
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
01284
01285
01286
01287
01288
01289 CurrentProcess->
NumberOfPrivatePages -= 1;
01290
01291 ForkProtoPte += 1;
01292 NumberOfForkPtes += 1;
01293
01294 }
else {
01295
01296
01297
01298
01299
01300
if (
IS_PTE_NOT_DEMAND_ZERO (PteContents)) {
01301
01302
if (PteContents.
u.Soft.Protection ==
MM_DECOMMIT) {
01303
01304
01305
01306
01307
01308
01309
01310
MI_WRITE_INVALID_PTE (PointerNewPte, PteContents);
01311 }
else {
01312
01313
01314
01315
01316
01317
01318
01319
01320 ForkProtoPte->ProtoPte = PteContents;
01321
01322
01323
01324
01325
01326
MI_MAKE_PROTECT_WRITE_COPY (ForkProtoPte->ProtoPte);
01327
01328 ForkProtoPte->CloneRefCount = 2;
01329
01330 TempPte.
u.Long =
01331
MiProtoAddressForPte (&ForkProtoPte->ProtoPte);
01332
01333 TempPte.
u.Proto.Prototype = 1;
01334
01335
MI_WRITE_INVALID_PTE (PointerPte, TempPte);
01336
MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
01337
01338
01339
01340
01341
01342 CurrentProcess->
NumberOfPrivatePages -= 1;
01343
01344 ForkProtoPte += 1;
01345 NumberOfForkPtes += 1;
01346 }
01347 }
else {
01348
01349
01350
01351
01352
01353
01354
MI_WRITE_INVALID_PTE (PointerNewPte, PteContents);
01355 }
01356
01357
01358
01359
01360
01361
01362
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries);
01363 }
01364
01365 PointerPte += 1;
01366 PointerNewPte += 1;
01367
01368 }
01369 AllDone:
01370 NewVad = NewVad->
Parent;
01371 }
01372 Vad =
MiGetNextVad (Vad);
01373
01374 }
01375
01376
01377
01378
01379
01380
MiUnlockPagedAddress (LockedForkPte, FALSE);
01381
01382
01383
01384
01385
01386
#if defined (_WIN64)
01387
MiUnmapSinglePage (PpeBase);
01388
#endif
01389
01390
#if !defined (_X86PAE_)
01391
MiUnmapSinglePage (PdeBase);
01392
#else
01393
MmUnmapLockedPages (PdeBase, MdlPageDirectory);
01394
#endif
01395
01396
#if !defined (_WIN64)
01397
MiUnmapSinglePage (HyperBase);
01398
#endif
01399
01400
MiUnmapSinglePage (NewPteMappedAddress);
01401
01402
#if defined (_WIN64)
01403
MiDownPfnReferenceCount (RootPhysicalPage, 1);
01404
#endif
01405
01406
#if defined (_X86PAE_)
01407
for (i = 0; i < PD_PER_SYSTEM; i += 1) {
01408
MiDownPfnReferenceCount (PageDirectoryFrames[i], 1);
01409 }
01410
#else
01411
MiDownPfnReferenceCount (MdlDirPage, 1);
01412
#endif
01413
01414
#if !defined (_WIN64)
01415
MiDownPfnReferenceCount (HyperPhysicalPage, 1);
01416
#endif
01417
01418
MiDownPfnReferenceCount (MdlPage, 1);
01419
01420
01421
01422
01423
01424
ASSERT ((SPFN_NUMBER)CurrentProcess->
NumberOfPrivatePages >= 0);
01425
01426 ProcessToInitialize->NumberOfPrivatePages =
01427 CurrentProcess->
NumberOfPrivatePages;
01428
01429
ASSERT (NumberOfForkPtes <= CloneDescriptor->NumberOfPtes);
01430
01431
if (NumberOfForkPtes != 0) {
01432
01433
01434
01435
01436
01437
01438 CloneHeader->
NumberOfPtes = NumberOfForkPtes;
01439 CloneDescriptor->
NumberOfReferences = NumberOfForkPtes;
01440 CloneDescriptor->
NumberOfPtes = NumberOfForkPtes;
01441
01442 }
else {
01443
01444
01445
01446
01447
01448
01449
01450
01451
MiRemoveClone (CloneDescriptor);
01452
01453
UNLOCK_WS (CurrentProcess);
01454
01455
ExFreePool (CloneDescriptor->
CloneHeader->
ClonePtes);
01456
01457
ExFreePool (CloneDescriptor->
CloneHeader);
01458
01459
01460
01461
01462
01463
01464
PsReturnPoolQuota (CurrentProcess,
01465 PagedPool,
01466 CloneDescriptor->
PagedPoolQuotaCharge);
01467
01468
PsReturnPoolQuota (CurrentProcess, NonPagedPool,
sizeof(
MMCLONE_HEADER));
01469
01470
ExFreePool (CloneDescriptor);
01471
01472
LOCK_WS (CurrentProcess);
01473 }
01474
01475
MiDownShareCountFlushEntireTb (PageFrameIndex);
01476
01477
#if defined (_WIN64)
01478
MiDownShareCountFlushEntireTb (PageDirFrameIndex);
01479
#endif
01480
01481 PageFrameIndex = (PFN_NUMBER)-1;
01482 PageDirFrameIndex = (PFN_NUMBER)-1;
01483
01484
01485
01486
01487
01488 Clone =
MiGetFirstClone ();
01489 CloneList = &FirstNewClone;
01490 CloneFailed =
FALSE;
01491
01492
while (Clone != (
PMMCLONE_DESCRIPTOR)
NULL) {
01493
01494
01495
01496
01497
01498
MiUpCloneProcessRefCount (Clone);
01499
01500
do {
01501 NewClone =
ExAllocatePoolWithTag (NonPagedPool,
01502
sizeof(
MMCLONE_DESCRIPTOR),
01503 ' mM');
01504
01505
if (NewClone !=
NULL) {
01506
break;
01507 }
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519 CloneFailed =
TRUE;
01520 status = STATUS_INSUFFICIENT_RESOURCES;
01521
01522
KeDelayExecutionThread (KernelMode,
01523 FALSE,
01524 (PLARGE_INTEGER)&MmShortTime);
01525
continue;
01526 }
while (
TRUE);
01527
01528 *NewClone = *Clone;
01529
01530 *CloneList = NewClone;
01531 CloneList = &NewClone->
Parent;
01532 Clone =
MiGetNextClone (Clone);
01533 }
01534
01535 *CloneList = (
PMMCLONE_DESCRIPTOR)
NULL;
01536
01537
01538
01539
01540
01541
01542
01543
UNLOCK_WS (CurrentProcess);
01544
01545 CurrentProcess->
ForkInProgress =
NULL;
01546
01547
UNLOCK_ADDRESS_SPACE (CurrentProcess);
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
if (Attached) {
01563
KeDetachProcess ();
01564 Attached =
FALSE;
01565 }
01566
01567
if (
PsGetCurrentProcess() != ProcessToInitialize) {
01568 Attached =
TRUE;
01569
KeAttachProcess (&ProcessToInitialize->Pcb);
01570 }
01571
01572 CurrentProcess = ProcessToInitialize;
01573
01574
01575
01576
01577
01578
01579 Vad = FirstNewVad;
01580 VadInsertFailed =
FALSE;
01581
01582
LOCK_WS (CurrentProcess);
01583
01584
while (Vad != (
PMMVAD)
NULL) {
01585
01586 NextVad = Vad->
Parent;
01587
01588
try {
01589
01590
if (VadInsertFailed) {
01591 Vad->
u.VadFlags.CommitCharge =
MM_MAX_COMMIT;
01592 }
01593
01594
MiInsertVad (Vad);
01595
01596 } except (EXCEPTION_EXECUTE_HANDLER) {
01597
01598
01599
01600
01601
01602
01603
01604
01605 VadInsertFailed =
TRUE;
01606 status = GetExceptionCode();
01607
01608
01609
01610
01611
01612
continue;
01613 }
01614
01615
01616
01617
01618
01619 CurrentProcess->
VirtualSize +=
PAGE_SIZE +
01620 ((Vad->
EndingVpn - Vad->
StartingVpn) >>
PAGE_SHIFT);
01621
01622 Vad = NextVad;
01623 }
01624
01625
UNLOCK_WS (CurrentProcess);
01626
01627
01628
01629
01630
01631
01632 CurrentProcess->
PeakVirtualSize = CurrentProcess->
VirtualSize;
01633
01634 Clone = FirstNewClone;
01635 TotalPagedPoolCharge = 0;
01636 TotalNonPagedPoolCharge = 0;
01637
01638
while (Clone != (
PMMCLONE_DESCRIPTOR)
NULL) {
01639
01640 NextClone = Clone->
Parent;
01641
MiInsertClone (Clone);
01642
01643
01644
01645
01646
01647
01648 TotalPagedPoolCharge += Clone->
PagedPoolQuotaCharge;
01649 TotalNonPagedPoolCharge +=
sizeof(
MMCLONE_HEADER);
01650
01651 Clone = NextClone;
01652 }
01653
01654
if (CloneFailed || VadInsertFailed) {
01655
01656 CurrentProcess->
ForkWasSuccessful =
MM_FORK_FAILED;
01657
01658
if (Attached) {
01659
KeDetachProcess ();
01660 }
01661 KdPrint((
"MMFORK: vad insert failed\n"));
01662
01663
return status;
01664 }
01665
01666
try {
01667
01668 PageTablePage = 1;
01669
PsChargePoolQuota (CurrentProcess, PagedPool, TotalPagedPoolCharge);
01670 PageTablePage = 0;
01671
PsChargePoolQuota (CurrentProcess, NonPagedPool, TotalNonPagedPoolCharge);
01672
01673 } except (EXCEPTION_EXECUTE_HANDLER) {
01674
01675
if (PageTablePage == 0) {
01676
PsReturnPoolQuota (CurrentProcess, PagedPool, TotalPagedPoolCharge);
01677 }
01678 KdPrint((
"MMFORK: pool quota failed\n"));
01679
01680 CurrentProcess->
ForkWasSuccessful =
MM_FORK_FAILED;
01681
01682
if (Attached) {
01683
KeDetachProcess ();
01684 }
01685
return GetExceptionCode();
01686 }
01687
01688
ASSERT (ProcessToClone->ForkWasSuccessful == MM_FORK_SUCCEEDED);
01689
ASSERT (CurrentProcess->
ForkWasSuccessful == MM_FORK_SUCCEEDED);
01690
01691
if (Attached) {
01692
KeDetachProcess ();
01693 }
01694
01695
#if DBG
01696
if (MmDebug &
MM_DBG_FORK) {
01697
DbgPrint(
"ending clone operation process to clone = %lx\n",
01698 ProcessToClone);
01699 }
01700
#endif //DBG
01701
01702
return STATUS_SUCCESS;
01703
01704
01705
01706
01707
01708 ErrorReturn4:
01709
if (PageTablePage == 2) {
01710 NOTHING;
01711 }
01712
else if (PageTablePage == 1) {
01713
PsReturnPoolQuota (CurrentProcess, PagedPool,
sizeof(
MMCLONE_BLOCK) *
01714 NumberOfPrivatePages);
01715 }
01716
else {
01717
ASSERT (PageTablePage == 0);
01718
PsReturnPoolQuota (CurrentProcess, PagedPool,
sizeof(
MMCLONE_BLOCK) *
01719 NumberOfPrivatePages);
01720
PsReturnPoolQuota (CurrentProcess, NonPagedPool,
sizeof(
MMCLONE_HEADER));
01721 }
01722
01723 NewVad = FirstNewVad;
01724
while (NewVad !=
NULL) {
01725 Vad = NewVad->
Parent;
01726
ExFreePool (NewVad);
01727 NewVad = Vad;
01728 }
01729
01730
ExFreePool (CloneDescriptor);
01731 ErrorReturn3:
01732
ExFreePool (CloneHeader);
01733 ErrorReturn2:
01734
ExFreePool (CloneProtos);
01735 ErrorReturn1:
01736
UNLOCK_ADDRESS_SPACE (CurrentProcess);
01737
ASSERT (CurrentProcess->
ForkWasSuccessful == MM_FORK_SUCCEEDED);
01738
if (Attached) {
01739
KeDetachProcess ();
01740 }
01741
return status;
01742 }