00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
#include "mi.h"
00023
00024
VOID
00025
MiUpPfnReferenceCount (
00026 IN PFN_NUMBER Page,
00027 IN USHORT Count
00028 );
00029
00030
VOID
00031
MiDownPfnReferenceCount (
00032 IN PFN_NUMBER Page,
00033 IN USHORT Count
00034 );
00035
00036
VOID
00037
MiUpControlAreaRefs (
00038 IN
PCONTROL_AREA ControlArea
00039 );
00040
00041 ULONG
00042
MiDoneWithThisPageGetAnother (
00043 IN PPFN_NUMBER PageFrameIndex,
00044 IN
PMMPTE PointerPde,
00045 IN
PEPROCESS CurrentProcess
00046 );
00047
00048
VOID
00049
MiUpForkPageShareCount(
00050 IN
PMMPFN PfnForkPtePage
00051 );
00052
00053
VOID
00054
MiUpCloneProcessRefCount (
00055 IN
PMMCLONE_DESCRIPTOR Clone
00056 );
00057
00058
VOID
00059
MiUpCloneProtoRefCount (
00060 IN
PMMCLONE_BLOCK CloneProto,
00061 IN
PEPROCESS CurrentProcess
00062 );
00063
00064 ULONG
00065
MiHandleForkTransitionPte (
00066 IN
PMMPTE PointerPte,
00067 IN
PMMPTE PointerNewPte,
00068 IN
PMMCLONE_BLOCK ForkProtoPte
00069 );
00070
00071
VOID
00072
MiDownShareCountFlushEntireTb (
00073 IN PFN_NUMBER PageFrameIndex
00074 );
00075
00076
VOID
00077
MiBuildForkPageTable(
00078 IN PFN_NUMBER PageFrameIndex,
00079 IN
PMMPTE PointerPde,
00080 IN
PMMPTE PointerNewPde,
00081 IN PFN_NUMBER PdePhysicalPage,
00082 IN
PMMPFN PfnPdPage
00083 );
00084
00085
VOID
00086
MiRetrievePageDirectoryFrames(
00087 IN PFN_NUMBER RootPhysicalPage,
00088 OUT PPFN_NUMBER PageDirectoryFrames
00089 );
00090
00091 #define MM_FORK_SUCCEEDED 0
00092 #define MM_FORK_FAILED 1
00093
00094
#ifdef ALLOC_PRAGMA
00095
#pragma alloc_text(PAGE,MiCloneProcessAddressSpace)
00096
#endif
00097
00098
00099
NTSTATUS
00100 MiCloneProcessAddressSpace (
00101 IN
PEPROCESS ProcessToClone,
00102 IN
PEPROCESS ProcessToInitialize,
00103 IN PFN_NUMBER RootPhysicalPage,
00104 IN PFN_NUMBER HyperPhysicalPage
00105 )
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
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 }
01743
01744 ULONG
01745 MiDecrementCloneBlockReference (
01746 IN
PMMCLONE_DESCRIPTOR CloneDescriptor,
01747 IN
PMMCLONE_BLOCK CloneBlock,
01748 IN
PEPROCESS CurrentProcess
01749 )
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781 {
01782
01783 ULONG MutexReleased;
01784
MMPTE CloneContents;
01785
PMMPFN Pfn3;
01786 KIRQL OldIrql;
01787 LONG NewCount;
01788 LOGICAL WsHeldSafe;
01789
01790 MutexReleased =
FALSE;
01791 OldIrql =
APC_LEVEL;
01792
01793 MutexReleased =
MiMakeSystemAddressValidPfnWs (CloneBlock, CurrentProcess);
01794
01795
while (CurrentProcess->ForkInProgress) {
01796
MiWaitForForkToComplete (CurrentProcess);
01797
MiMakeSystemAddressValidPfnWs (CloneBlock, CurrentProcess);
01798 MutexReleased =
TRUE;
01799 }
01800
01801 CloneBlock->CloneRefCount -= 1;
01802 NewCount = CloneBlock->CloneRefCount;
01803
01804
ASSERT (NewCount >= 0);
01805
01806
if (NewCount == 0) {
01807 CloneContents = CloneBlock->ProtoPte;
01808 }
else {
01809 CloneContents =
ZeroPte;
01810 }
01811
01812
if ((NewCount == 0) && (CloneContents.
u.Long != 0)) {
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
ASSERT (CloneContents.
u.Hard.Valid == 0);
01826
01827
01828
01829
01830
01831
01832
ASSERT (CloneContents.
u.Soft.Prototype == 0);
01833
01834
if (CloneContents.
u.Soft.Transition == 1) {
01835
01836
01837
01838
01839
01840
01841 Pfn3 =
MI_PFN_ELEMENT (CloneContents.
u.Trans.PageFrameNumber);
01842
MI_SET_PFN_DELETED (Pfn3);
01843
01844
MiDecrementShareCount (Pfn3->
PteFrame);
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
if ((Pfn3->
u3.e2.ReferenceCount == 0) &&
01856 (Pfn3->
u3.e1.PageLocation !=
FreePageList)) {
01857
01858
MiUnlinkPageFromList (Pfn3);
01859
MiReleasePageFileSpace (Pfn3->
OriginalPte);
01860
MiInsertPageInList (
MmPageLocationList[
FreePageList],
01861
MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&CloneContents));
01862 }
01863 }
else {
01864
01865
if (
IS_PTE_NOT_DEMAND_ZERO (CloneContents)) {
01866
MiReleasePageFileSpace (CloneContents);
01867 }
01868 }
01869 }
01870
01871
01872
01873
01874
01875
01876 CloneDescriptor->NumberOfReferences -= 1;
01877
01878
if (CloneDescriptor->NumberOfReferences == 0) {
01879
01880
01881
01882
01883
01884
01885
01886
01887 CloneDescriptor->CloneHeader->NumberOfProcessReferences -= 1;
01888
01889
MiRemoveClone (CloneDescriptor);
01890
01891
if (CloneDescriptor->CloneHeader->NumberOfProcessReferences == 0) {
01892
01893
01894
01895
01896
01897
01898
UNLOCK_PFN (OldIrql);
01899
01900
01901
01902
01903
01904
01905
UNLOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
01906
01907 MutexReleased =
TRUE;
01908
01909
01910
#if DBG
01911
{
01912
01913 ULONG i;
01914
PMMCLONE_BLOCK OldCloneBlock;
01915
01916 OldCloneBlock = CloneDescriptor->CloneHeader->ClonePtes;
01917
for (i = 0; i < CloneDescriptor->CloneHeader->NumberOfPtes; i += 1) {
01918
if (OldCloneBlock->
CloneRefCount != 0) {
01919
DbgPrint(
"fork block with non zero ref count %lx %lx %lx\n",
01920 OldCloneBlock, CloneDescriptor,
01921 CloneDescriptor->CloneHeader);
01922
KeBugCheckEx (MEMORY_MANAGEMENT, 1, 0, 0, 0);
01923 }
01924 }
01925
01926
if (MmDebug &
MM_DBG_FORK) {
01927
DbgPrint(
"removing clone header at address %lx\n",
01928 CloneDescriptor->CloneHeader);
01929 }
01930
01931 }
01932
#endif //DBG
01933
01934
ExFreePool (CloneDescriptor->CloneHeader->ClonePtes);
01935
01936
ExFreePool (CloneDescriptor->CloneHeader);
01937
01938
01939
01940
01941
01942
01943
LOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
01944
01945
LOCK_PFN (OldIrql);
01946 }
01947
01948
#if DBG
01949
if (MmDebug &
MM_DBG_FORK) {
01950
DbgPrint(
"removing clone descriptor at address %lx\n",CloneDescriptor);
01951 }
01952
#endif //DBG
01953
01954
01955
01956
01957
01958
01959
UNLOCK_PFN (OldIrql);
01960
01961
if (CurrentProcess->ForkWasSuccessful ==
MM_FORK_SUCCEEDED) {
01962
01963
PsReturnPoolQuota (CurrentProcess,
01964
PagedPool,
01965 CloneDescriptor->PagedPoolQuotaCharge);
01966
01967
PsReturnPoolQuota (CurrentProcess,
01968
NonPagedPool,
01969
sizeof(
MMCLONE_HEADER));
01970 }
01971
01972
ExFreePool (CloneDescriptor);
01973
LOCK_PFN (OldIrql);
01974 }
01975
01976
return MutexReleased;
01977 }
01978
01979
VOID
01980 MiWaitForForkToComplete (
01981 IN
PEPROCESS CurrentProcess
01982 )
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005 {
02006 ULONG OldIrql;
02007 LOGICAL WsHeldSafe;
02008
02009
02010
02011
02012
02013
02014
02015
02016
UNLOCK_PFN (
APC_LEVEL);
02017
02018
02019
02020
02021
02022
02023
02024 OldIrql = CurrentProcess->WorkingSetLock.OldIrql;
02025
02026
UNLOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
02027
02028
02029
02030
02031
02032
02033
LOCK_ADDRESS_SPACE (CurrentProcess);
02034
02035
02036
02037
02038
02039
02040
LOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe);
02041
02042
02043
02044
02045
02046
02047
UNLOCK_ADDRESS_SPACE (CurrentProcess);
02048
02049
02050
02051
02052
02053 CurrentProcess->WorkingSetLock.OldIrql = OldIrql;
02054
02055
02056
02057
02058
02059
LOCK_PFN (OldIrql);
02060
return;
02061 }
02062
#if DBG
02063
VOID
02064 CloneTreeWalk (
02065
PMMCLONE_DESCRIPTOR Start
02066 )
02067
02068 {
02069
Start;
02070
NodeTreeWalk ( (
PMMADDRESS_NODE)(
PsGetCurrentProcess()->CloneRoot));
02071
return;
02072 }
02073
#endif //DBG
02074
02075
VOID
02076 MiUpPfnReferenceCount (
02077 IN PFN_NUMBER Page,
02078 IN USHORT Count
02079 )
02080
02081
02082
02083 {
02084 KIRQL OldIrql;
02085
PMMPFN Pfn1;
02086
02087 Pfn1 =
MI_PFN_ELEMENT (Page);
02088
LOCK_PFN (OldIrql);
02089 Pfn1->
u3.e2.ReferenceCount +=
Count;
02090
UNLOCK_PFN (OldIrql);
02091
return;
02092 }
02093
02094
VOID
02095 MiDownPfnReferenceCount (
02096 IN PFN_NUMBER Page,
02097 IN USHORT Count
02098 )
02099
02100
02101
02102 {
02103
USHORT i;
02104 KIRQL OldIrql;
02105
02106
LOCK_PFN (OldIrql);
02107
for (i = 0; i <
Count; i += 1) {
02108
MiDecrementReferenceCount (Page);
02109 }
02110
UNLOCK_PFN (OldIrql);
02111
return;
02112 }
02113
02114
VOID
02115 MiUpControlAreaRefs (
02116 IN
PCONTROL_AREA ControlArea
02117 )
02118
02119 {
02120 KIRQL OldIrql;
02121
02122
LOCK_PFN (OldIrql);
02123
02124 ControlArea->NumberOfMappedViews += 1;
02125 ControlArea->NumberOfUserReferences += 1;
02126
02127
UNLOCK_PFN (OldIrql);
02128
return;
02129 }
02130
02131
02132 ULONG
02133 MiDoneWithThisPageGetAnother (
02134 IN PPFN_NUMBER PageFrameIndex,
02135 IN
PMMPTE PointerPde,
02136 IN
PEPROCESS CurrentProcess
02137 )
02138
02139 {
02140 KIRQL OldIrql;
02141 ULONG ReleasedMutex;
02142
02143
LOCK_PFN (OldIrql);
02144
02145
if (*PageFrameIndex != (PFN_NUMBER)-1) {
02146
02147
02148
02149
02150
02151
02152
MiDecrementShareCountOnly (*PageFrameIndex);
02153 }
02154
02155 ReleasedMutex =
02156
MiEnsureAvailablePageOrWait (
02157 CurrentProcess,
02158
NULL);
02159
02160 *PageFrameIndex =
MiRemoveZeroPage (
02161
MI_PAGE_COLOR_PTE_PROCESS (PointerPde,
02162 &CurrentProcess->NextPageColor));
02163
02164
UNLOCK_PFN (OldIrql);
02165
return ReleasedMutex;
02166 }
02167
02168
VOID
02169 MiUpCloneProcessRefCount (
02170 IN
PMMCLONE_DESCRIPTOR Clone
02171 )
02172 {
02173 KIRQL OldIrql;
02174
02175
LOCK_PFN (OldIrql);
02176
02177 Clone->CloneHeader->NumberOfProcessReferences += 1;
02178
02179
UNLOCK_PFN (OldIrql);
02180
return;
02181 }
02182
02183
VOID
02184 MiUpCloneProtoRefCount (
02185 IN
PMMCLONE_BLOCK CloneProto,
02186 IN
PEPROCESS CurrentProcess
02187 )
02188
02189 {
02190 KIRQL OldIrql;
02191
02192
LOCK_PFN (OldIrql);
02193
02194
MiMakeSystemAddressValidPfnWs (CloneProto,
02195 CurrentProcess);
02196
02197 CloneProto->CloneRefCount += 1;
02198
02199
UNLOCK_PFN (OldIrql);
02200
return;
02201 }
02202
02203 ULONG
02204 MiHandleForkTransitionPte (
02205 IN
PMMPTE PointerPte,
02206 IN
PMMPTE PointerNewPte,
02207 IN
PMMCLONE_BLOCK ForkProtoPte
02208 )
02209
02210 {
02211 KIRQL OldIrql;
02212
PMMPFN Pfn2;
02213
MMPTE PteContents;
02214
PMMPTE ContainingPte;
02215 PFN_NUMBER PageTablePage;
02216
MMPTE TempPte;
02217
PMMPFN PfnForkPtePage;
02218
02219
02220
LOCK_PFN (OldIrql);
02221
02222
02223
02224
02225
02226
02227
02228 PteContents = *(
volatile PMMPTE)PointerPte;
02229
02230
if ((PteContents.
u.Soft.Transition == 0) ||
02231 (PteContents.
u.Soft.Prototype == 1)) {
02232
02233
02234
02235
02236
02237
02238
UNLOCK_PFN (OldIrql);
02239
return TRUE;
02240
02241 }
else {
02242
02243
02244
02245
02246
02247
02248 Pfn2 =
MI_PFN_ELEMENT (PteContents.
u.Trans.PageFrameNumber);
02249
02250
02251
02252
02253
02254
ASSERT (Pfn2->
u3.e1.PrototypePte != 1);
02255
02256
02257
02258
02259
02260
02261
02262 ForkProtoPte->ProtoPte = PteContents;
02263
02264
02265
02266
02267
02268
MI_MAKE_PROTECT_WRITE_COPY (ForkProtoPte->ProtoPte);
02269
02270 ForkProtoPte->CloneRefCount = 2;
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282 Pfn2->
PteAddress = &ForkProtoPte->ProtoPte;
02283 Pfn2->
u3.e1.PrototypePte = 1;
02284
02285
02286
02287
02288
02289
MI_MAKE_PROTECT_WRITE_COPY (Pfn2->
OriginalPte);
02290
02291 ContainingPte =
MiGetPteAddress(&ForkProtoPte->ProtoPte);
02292
02293
if (ContainingPte->
u.Hard.Valid == 0) {
02294
#if !defined (_WIN64)
02295
if (!
NT_SUCCESS(
MiCheckPdeForPagedPool (&ForkProtoPte->ProtoPte))) {
02296
#endif
02297
KeBugCheckEx (MEMORY_MANAGEMENT,
02298 0x61940,
02299 (ULONG_PTR)&ForkProtoPte->ProtoPte,
02300 (ULONG_PTR)ContainingPte->
u.Long,
02301 (ULONG_PTR)
MiGetVirtualAddressMappedByPte(&ForkProtoPte->ProtoPte));
02302
#if !defined (_WIN64)
02303
}
02304
#endif
02305
}
02306
02307 PageTablePage = Pfn2->
PteFrame;
02308
02309 Pfn2->
PteFrame =
MI_GET_PAGE_FRAME_FROM_PTE (ContainingPte);
02310
02311
02312
02313
02314
02315
02316
02317 PfnForkPtePage =
MI_PFN_ELEMENT (
02318 ContainingPte->
u.Hard.PageFrameNumber );
02319
02320 PfnForkPtePage->
u2.ShareCount += 1;
02321
02322 TempPte.
u.Long =
02323
MiProtoAddressForPte (Pfn2->
PteAddress);
02324 TempPte.
u.Proto.Prototype = 1;
02325
MI_WRITE_INVALID_PTE (PointerPte, TempPte);
02326
MI_WRITE_INVALID_PTE (PointerNewPte, TempPte);
02327
02328
02329
02330
02331
02332
02333
02334
MiDecrementShareCount (PageTablePage);
02335 }
02336
UNLOCK_PFN (OldIrql);
02337
return FALSE;
02338 }
02339
02340
VOID
02341 MiDownShareCountFlushEntireTb (
02342 IN PFN_NUMBER PageFrameIndex
02343 )
02344
02345 {
02346 KIRQL OldIrql;
02347
02348
LOCK_PFN (OldIrql);
02349
02350
if (PageFrameIndex != (PFN_NUMBER)-1) {
02351
02352
02353
02354
02355
02356
02357
MiDecrementShareCountOnly (PageFrameIndex);
02358 }
02359
02360
KeFlushEntireTb (
FALSE,
FALSE);
02361
UNLOCK_PFN (OldIrql);
02362
return;
02363 }
02364
02365
VOID
02366 MiUpForkPageShareCount(
02367 IN
PMMPFN PfnForkPtePage
02368 )
02369 {
02370 KIRQL OldIrql;
02371
02372
LOCK_PFN (OldIrql);
02373 PfnForkPtePage->u2.ShareCount += 1;
02374
02375
UNLOCK_PFN (OldIrql);
02376
return;
02377 }
02378
02379
VOID
02380 MiBuildForkPageTable(
02381 IN PFN_NUMBER PageFrameIndex,
02382 IN
PMMPTE PointerPde,
02383 IN
PMMPTE PointerNewPde,
02384 IN PFN_NUMBER PdePhysicalPage,
02385 IN
PMMPFN PfnPdPage
02386 )
02387 {
02388 KIRQL OldIrql;
02389
PMMPFN Pfn1;
02390
02391 Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
02392
02393
02394
02395
02396
02397
02398
02399
02400
LOCK_PFN (OldIrql);
02401
02402 Pfn1->
OriginalPte =
DemandZeroPde;
02403 Pfn1->
u2.ShareCount = 1;
02404 Pfn1->
u3.e2.ReferenceCount = 1;
02405 Pfn1->
PteAddress = PointerPde;
02406 Pfn1->
u3.e1.Modified = 1;
02407 Pfn1->
u3.e1.PageLocation =
ActiveAndValid;
02408 Pfn1->
PteFrame = PdePhysicalPage;
02409
02410
02411
02412
02413
02414
02415 PfnPdPage->u2.ShareCount += 1;
02416
02417
02418
02419
02420
02421
02422
02423
MI_WRITE_INVALID_PTE (PointerNewPde,
TransitionPde);
02424
02425
02426
02427
02428
02429
#ifndef _ALPHA_
02430
MI_SET_OWNER_IN_PTE (PointerNewPde,
UserMode);
02431
#endif //_ALPHA_
02432
PointerNewPde->u.Trans.PageFrameNumber = PageFrameIndex;
02433
02434
UNLOCK_PFN (OldIrql);
02435 }
02436
02437
#if defined (_X86PAE_)
02438
VOID
02439
MiRetrievePageDirectoryFrames(
02440 IN PFN_NUMBER RootPhysicalPage,
02441 OUT PPFN_NUMBER PageDirectoryFrames
02442 )
02443 {
02444 ULONG i;
02445 KIRQL OldIrql;
02446
PMMPTE PointerPte;
02447
02448 PointerPte = (
PMMPTE)
MiMapPageInHyperSpace (RootPhysicalPage, &OldIrql);
02449
02450
for (i = 0; i < PD_PER_SYSTEM; i += 1) {
02451 PageDirectoryFrames[i] =
MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
02452 PointerPte += 1;
02453 }
02454
02455
MiUnmapPageInHyperSpace (OldIrql);
02456
02457
return;
02458 }
02459
#endif