ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

page.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       GPL, See COPYING in the top level directory
00003  * PROJECT:         ReactOS kernel
00004  * FILE:            ntoskrnl/mm/amd64/page.c
00005  * PURPOSE:         Low level memory managment manipulation
00006  *
00007  * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
00008  *                  ReactOS Portable Systems Group
00009  */
00010 
00011 /* INCLUDES ***************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #define NDEBUG
00015 #include <debug.h>
00016 #include "../ARM3/miarm.h"
00017 
00018 #undef InterlockedExchangePte
00019 #define InterlockedExchangePte(pte1, pte2) \
00020     InterlockedExchange64((LONG64*)&pte1->u.Long, pte2.u.Long)
00021 
00022 #define PAGE_EXECUTE_ANY (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)
00023 #define PAGE_WRITE_ANY (PAGE_EXECUTE_READWRITE|PAGE_READWRITE|PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY)
00024 #define PAGE_WRITECOPY_ANY (PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY)
00025 
00026 extern MMPTE HyperTemplatePte;
00027 
00028 /* GLOBALS *****************************************************************/
00029 
00030 const
00031 ULONG64
00032 MmProtectToPteMask[32] =
00033 {
00034     //
00035     // These are the base MM_ protection flags
00036     //
00037     0,
00038     PTE_READONLY            | PTE_ENABLE_CACHE,
00039     PTE_EXECUTE             | PTE_ENABLE_CACHE,
00040     PTE_EXECUTE_READ        | PTE_ENABLE_CACHE,
00041     PTE_READWRITE           | PTE_ENABLE_CACHE,
00042     PTE_WRITECOPY           | PTE_ENABLE_CACHE,
00043     PTE_EXECUTE_READWRITE   | PTE_ENABLE_CACHE,
00044     PTE_EXECUTE_WRITECOPY   | PTE_ENABLE_CACHE,
00045     //
00046     // These OR in the MM_NOCACHE flag
00047     //
00048     0,
00049     PTE_READONLY            | PTE_DISABLE_CACHE,
00050     PTE_EXECUTE             | PTE_DISABLE_CACHE,
00051     PTE_EXECUTE_READ        | PTE_DISABLE_CACHE,
00052     PTE_READWRITE           | PTE_DISABLE_CACHE,
00053     PTE_WRITECOPY           | PTE_DISABLE_CACHE,
00054     PTE_EXECUTE_READWRITE   | PTE_DISABLE_CACHE,
00055     PTE_EXECUTE_WRITECOPY   | PTE_DISABLE_CACHE,
00056     //
00057     // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM
00058     //
00059     0,
00060     PTE_READONLY            | PTE_ENABLE_CACHE,
00061     PTE_EXECUTE             | PTE_ENABLE_CACHE,
00062     PTE_EXECUTE_READ        | PTE_ENABLE_CACHE,
00063     PTE_READWRITE           | PTE_ENABLE_CACHE,
00064     PTE_WRITECOPY           | PTE_ENABLE_CACHE,
00065     PTE_EXECUTE_READWRITE   | PTE_ENABLE_CACHE,
00066     PTE_EXECUTE_WRITECOPY   | PTE_ENABLE_CACHE,
00067     //
00068     // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining?
00069     //
00070     0,
00071     PTE_READONLY            | PTE_WRITECOMBINED_CACHE,
00072     PTE_EXECUTE             | PTE_WRITECOMBINED_CACHE,
00073     PTE_EXECUTE_READ        | PTE_WRITECOMBINED_CACHE,
00074     PTE_READWRITE           | PTE_WRITECOMBINED_CACHE,
00075     PTE_WRITECOPY           | PTE_WRITECOMBINED_CACHE,
00076     PTE_EXECUTE_READWRITE   | PTE_WRITECOMBINED_CACHE,
00077     PTE_EXECUTE_WRITECOPY   | PTE_WRITECOMBINED_CACHE,
00078 };
00079 
00080 const
00081 ULONG MmProtectToValue[32] =
00082 {
00083     PAGE_NOACCESS,
00084     PAGE_READONLY,
00085     PAGE_EXECUTE,
00086     PAGE_EXECUTE_READ,
00087     PAGE_READWRITE,
00088     PAGE_WRITECOPY,
00089     PAGE_EXECUTE_READWRITE,
00090     PAGE_EXECUTE_WRITECOPY,
00091     PAGE_NOACCESS,
00092     PAGE_NOCACHE | PAGE_READONLY,
00093     PAGE_NOCACHE | PAGE_EXECUTE,
00094     PAGE_NOCACHE | PAGE_EXECUTE_READ,
00095     PAGE_NOCACHE | PAGE_READWRITE,
00096     PAGE_NOCACHE | PAGE_WRITECOPY,
00097     PAGE_NOCACHE | PAGE_EXECUTE_READWRITE,
00098     PAGE_NOCACHE | PAGE_EXECUTE_WRITECOPY,
00099     PAGE_NOACCESS,
00100     PAGE_GUARD | PAGE_READONLY,
00101     PAGE_GUARD | PAGE_EXECUTE,
00102     PAGE_GUARD | PAGE_EXECUTE_READ,
00103     PAGE_GUARD | PAGE_READWRITE,
00104     PAGE_GUARD | PAGE_WRITECOPY,
00105     PAGE_GUARD | PAGE_EXECUTE_READWRITE,
00106     PAGE_GUARD | PAGE_EXECUTE_WRITECOPY,
00107     PAGE_NOACCESS,
00108     PAGE_WRITECOMBINE | PAGE_READONLY,
00109     PAGE_WRITECOMBINE | PAGE_EXECUTE,
00110     PAGE_WRITECOMBINE | PAGE_EXECUTE_READ,
00111     PAGE_WRITECOMBINE | PAGE_READWRITE,
00112     PAGE_WRITECOMBINE | PAGE_WRITECOPY,
00113     PAGE_WRITECOMBINE | PAGE_EXECUTE_READWRITE,
00114     PAGE_WRITECOMBINE | PAGE_EXECUTE_WRITECOPY
00115 };
00116 
00117 /* PRIVATE FUNCTIONS *******************************************************/
00118 
00119 BOOLEAN
00120 FORCEINLINE
00121 MiIsHyperspaceAddress(PVOID Address)
00122 {
00123     return ((ULONG64)Address >= HYPER_SPACE &&
00124             (ULONG64)Address <= HYPER_SPACE_END);
00125 }
00126 
00127 VOID
00128 MiFlushTlb(PMMPTE Pte, PVOID Address)
00129 {
00130     if (MiIsHyperspaceAddress(Pte))
00131     {
00132         MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte));
00133     }
00134     else
00135     {
00136         __invlpg(Address);
00137     }
00138 }
00139 
00140 static
00141 VOID
00142 MmDeletePageTablePfn(PFN_NUMBER PageFrameNumber, ULONG Level)
00143 {
00144     PMMPTE PageTable;
00145     KIRQL OldIrql;
00146     PMMPFN PfnEntry;
00147     ULONG i, NumberEntries;
00148 
00149     /* Check if this is a page table */
00150     if (Level > 0)
00151     {
00152         NumberEntries = (Level == 4) ? MiAddressToPxi(MmHighestUserAddress)+1 : 512;
00153 
00154         /* Map the page table in hyperspace */
00155         PageTable = (PMMPTE)MmCreateHyperspaceMapping(PageFrameNumber);
00156 
00157         /* Loop all page table entries */
00158         for (i = 0; i < NumberEntries; i++)
00159         {
00160             /* Check if the entry is valid */
00161             if (PageTable[i].u.Hard.Valid)
00162             {
00163                 /* Recursively free the page that backs it */
00164                 MmDeletePageTablePfn(PageTable[i].u.Hard.PageFrameNumber, Level - 1);
00165             }
00166         }
00167 
00168         /* Delete the hyperspace mapping */
00169         MmDeleteHyperspaceMapping(PageTable);
00170     }
00171 
00172     /* Check if this is a legacy allocation */
00173     PfnEntry = MiGetPfnEntry(PageFrameNumber);
00174     if (MI_IS_ROS_PFN(PfnEntry))
00175     {
00176         /* Free it using the legacy API */
00177         MmReleasePageMemoryConsumer(MC_SYSTEM, PageFrameNumber);
00178     }
00179     else
00180     {
00181         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00182 
00183         /* Free it using the ARM3 API */
00184         MI_SET_PFN_DELETED(PfnEntry);
00185         MiDecrementShareCount(PfnEntry, PageFrameNumber);
00186 
00187         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00188     }
00189 }
00190 
00191 static
00192 PMMPTE
00193 MiGetPteForProcess(
00194     PEPROCESS Process,
00195     PVOID Address,
00196     BOOLEAN Create)
00197 {
00198     MMPTE TmplPte, *Pte;
00199 
00200     /* Check if we need hypersapce mapping */
00201     if (Address < MmSystemRangeStart &&
00202         Process && Process != PsGetCurrentProcess())
00203     {
00204         UNIMPLEMENTED;
00205         __debugbreak();
00206         return NULL;
00207     }
00208     else if (Create)
00209     {
00210         KIRQL OldIrql;
00211         TmplPte.u.Long = 0;
00212         TmplPte.u.Flush.Valid = 1;
00213         TmplPte.u.Flush.Write = 1;
00214 
00215         /* All page table levels of user pages are user owned */
00216         TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
00217 
00218         /* Lock the PFN database */
00219         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00220 
00221         /* Get the PXE */
00222         Pte = MiAddressToPxe(Address);
00223         if (!Pte->u.Hard.Valid)
00224         {
00225             TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(0);
00226             MI_WRITE_VALID_PTE(Pte, TmplPte);
00227         }
00228 
00229         /* Get the PPE */
00230         Pte = MiAddressToPpe(Address);
00231         if (!Pte->u.Hard.Valid)
00232         {
00233             TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(1);
00234             MI_WRITE_VALID_PTE(Pte, TmplPte);
00235         }
00236 
00237         /* Get the PDE */
00238         Pte = MiAddressToPde(Address);
00239         if (!Pte->u.Hard.Valid)
00240         {
00241             TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(2);
00242             MI_WRITE_VALID_PTE(Pte, TmplPte);
00243         }
00244 
00245         /* Unlock PFN database */
00246         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00247     }
00248     else
00249     {
00250         /* Get the PXE */
00251         Pte = MiAddressToPxe(Address);
00252         if (!Pte->u.Hard.Valid)
00253             return NULL;
00254 
00255         /* Get the PPE */
00256         Pte = MiAddressToPpe(Address);
00257         if (!Pte->u.Hard.Valid)
00258             return NULL;
00259 
00260         /* Get the PDE */
00261         Pte = MiAddressToPde(Address);
00262         if (!Pte->u.Hard.Valid)
00263             return NULL;
00264     }
00265 
00266     return MiAddressToPte(Address);
00267 }
00268 
00269 static
00270 ULONG64
00271 MiGetPteValueForProcess(
00272     PEPROCESS Process,
00273     PVOID Address)
00274 {
00275     PMMPTE Pte;
00276     ULONG64 PteValue;
00277 
00278     Pte = MiGetPteForProcess(Process, Address, FALSE);
00279     PteValue = Pte ? Pte->u.Long : 0;
00280 
00281     if (MiIsHyperspaceAddress(Pte))
00282         MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte));
00283 
00284     return PteValue;
00285 }
00286 
00287 ULONG
00288 NTAPI
00289 MiGetPteProtection(MMPTE Pte)
00290 {
00291     ULONG Protect;
00292 
00293     if (!Pte.u.Flush.Valid)
00294     {
00295         Protect = PAGE_NOACCESS;
00296     }
00297     else if (Pte.u.Flush.NoExecute)
00298     {
00299         if (Pte.u.Flush.CopyOnWrite)
00300             Protect = PAGE_WRITECOPY;
00301         else if (Pte.u.Flush.Write)
00302             Protect = PAGE_READWRITE;
00303         else
00304             Protect = PAGE_READONLY;
00305     }
00306     else
00307     {
00308         if (Pte.u.Flush.CopyOnWrite)
00309             Protect = PAGE_EXECUTE_WRITECOPY;
00310         else if (Pte.u.Flush.Write)
00311             Protect = PAGE_EXECUTE_READWRITE;
00312         else
00313             Protect = PAGE_EXECUTE_READ;
00314     }
00315 
00316     if (Pte.u.Flush.CacheDisable)
00317         Protect |= PAGE_NOCACHE;
00318 
00319     if (Pte.u.Flush.WriteThrough)
00320         Protect |= PAGE_WRITETHROUGH;
00321 
00322     // PAGE_GUARD ?
00323     return Protect;
00324 }
00325 
00326 VOID
00327 NTAPI
00328 MiSetPteProtection(PMMPTE Pte, ULONG Protection)
00329 {
00330     Pte->u.Flush.CopyOnWrite = (Protection & PAGE_WRITECOPY_ANY) ? 1 : 0;
00331     Pte->u.Flush.Write = (Protection & PAGE_WRITE_ANY) ? 1 : 0;
00332     Pte->u.Flush.CacheDisable = (Protection & PAGE_NOCACHE) ? 1 : 0;
00333     Pte->u.Flush.WriteThrough = (Protection & PAGE_WRITETHROUGH) ? 1 : 0;
00334 
00335     // FIXME: This doesn't work. Why?
00336 //    Pte->u.Flush.NoExecute = (Protection & PAGE_EXECUTE_ANY) ? 0 : 1;
00337 }
00338 
00339 /* FUNCTIONS ***************************************************************/
00340 
00341 PFN_NUMBER
00342 NTAPI
00343 MmGetPfnForProcess(PEPROCESS Process,
00344                    PVOID Address)
00345 {
00346     MMPTE Pte;
00347     Pte.u.Long = MiGetPteValueForProcess(Process, Address);
00348     return Pte.u.Hard.Valid ? Pte.u.Hard.PageFrameNumber : 0;
00349 }
00350 
00351 PHYSICAL_ADDRESS
00352 NTAPI
00353 MmGetPhysicalAddress(PVOID Address)
00354 {
00355     PHYSICAL_ADDRESS p;
00356     MMPTE Pte;
00357 
00358     Pte.u.Long = MiGetPteValueForProcess(NULL, Address);
00359     if (Pte.u.Hard.Valid)
00360     {
00361         p.QuadPart = Pte.u.Hard.PageFrameNumber * PAGE_SIZE;
00362         p.u.LowPart |= (ULONG_PTR)Address & (PAGE_SIZE - 1);
00363     }
00364     else
00365     {
00366         p.QuadPart = 0;
00367     }
00368 
00369     return p;
00370 }
00371 
00372 BOOLEAN
00373 NTAPI
00374 MmIsPagePresent(PEPROCESS Process, PVOID Address)
00375 {
00376     MMPTE Pte;
00377     Pte.u.Long = MiGetPteValueForProcess(Process, Address);
00378     return (BOOLEAN)Pte.u.Hard.Valid;
00379 }
00380 
00381 BOOLEAN
00382 NTAPI
00383 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
00384 {
00385     MMPTE Pte;
00386     Pte.u.Long = MiGetPteValueForProcess(Process, Address);
00387     return Pte.u.Hard.Valid && Pte.u.Soft.Transition;
00388 }
00389 
00390 static PMMPTE
00391 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
00392 {
00393     __debugbreak();
00394     return 0;
00395 }
00396 
00397 BOOLEAN MmUnmapPageTable(PMMPTE Pt)
00398 {
00399     ASSERT(FALSE);
00400     return 0;
00401 }
00402 
00403 static ULONG64 MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
00404 {
00405     MMPTE Pte, *PointerPte;
00406 
00407     PointerPte = MmGetPageTableForProcess(Process, Address, FALSE);
00408     if (PointerPte)
00409     {
00410         Pte = *PointerPte;
00411         MmUnmapPageTable(PointerPte);
00412         return Pte.u.Long;
00413     }
00414     return 0;
00415 }
00416 
00417 VOID
00418 NTAPI
00419 MmGetPageFileMapping(
00420     PEPROCESS Process,
00421     PVOID Address,
00422     SWAPENTRY* SwapEntry)
00423 {
00424     ULONG64 Entry = MmGetPageEntryForProcess(Process, Address);
00425     *SwapEntry = Entry >> 1;
00426 }
00427 
00428 BOOLEAN
00429 NTAPI
00430 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
00431 {
00432     MMPTE Pte;
00433     Pte.u.Long = MiGetPteValueForProcess(Process, Address);
00434     return Pte.u.Hard.Valid && Pte.u.Hard.Dirty;
00435 }
00436 
00437 ULONG
00438 NTAPI
00439 MmGetPageProtect(PEPROCESS Process, PVOID Address)
00440 {
00441     MMPTE Pte;
00442 
00443     Pte.u.Long = MiGetPteValueForProcess(Process, Address);
00444 
00445     return MiGetPteProtection(Pte);
00446 }
00447 
00448 VOID
00449 NTAPI
00450 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
00451 {
00452     PMMPTE Pte;
00453     MMPTE NewPte;
00454 
00455     Pte = MiGetPteForProcess(Process, Address, FALSE);
00456     ASSERT(Pte != NULL);
00457 
00458     NewPte = *Pte;
00459 
00460     MiSetPteProtection(&NewPte, flProtect);
00461 
00462     InterlockedExchangePte(Pte, NewPte);
00463 
00464     MiFlushTlb(Pte, Address);
00465 }
00466 
00467 VOID
00468 NTAPI
00469 MmSetCleanPage(PEPROCESS Process, PVOID Address)
00470 {
00471     PMMPTE Pte;
00472 
00473     Pte = MiGetPteForProcess(Process, Address, FALSE);
00474     if (!Pte)
00475     {
00476         KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0);
00477     }
00478 
00479     /* Ckear the dirty bit */
00480     if (InterlockedBitTestAndReset64((PVOID)Pte, 6))
00481     {
00482         if (!MiIsHyperspaceAddress(Pte))
00483             __invlpg(Address);
00484     }
00485 
00486     MiFlushTlb(Pte, Address);
00487 }
00488 
00489 VOID
00490 NTAPI
00491 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
00492 {
00493     PMMPTE Pte;
00494 
00495     Pte = MiGetPteForProcess(Process, Address, FALSE);
00496     if (!Pte)
00497     {
00498         KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0);
00499     }
00500 
00501     /* Ckear the dirty bit */
00502     if (InterlockedBitTestAndSet64((PVOID)Pte, 6))
00503     {
00504         if (!MiIsHyperspaceAddress(Pte))
00505             __invlpg(Address);
00506     }
00507 
00508     MiFlushTlb(Pte, Address);
00509 }
00510 
00511 
00512 NTSTATUS
00513 NTAPI
00514 Mmi386ReleaseMmInfo(PEPROCESS Process)
00515 {
00516     UNIMPLEMENTED;
00517     return STATUS_UNSUCCESSFUL;
00518 }
00519 
00520 VOID
00521 NTAPI
00522 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page)
00523 {
00524     UNIMPLEMENTED;
00525 }
00526 
00527 VOID
00528 NTAPI
00529 MmRawDeleteVirtualMapping(PVOID Address)
00530 {
00531     UNIMPLEMENTED;
00532 }
00533 
00534 VOID
00535 NTAPI
00536 MmDeleteVirtualMapping(
00537     PEPROCESS Process,
00538     PVOID Address,
00539     BOOLEAN FreePage,
00540     BOOLEAN* WasDirty,
00541     PPFN_NUMBER Page)
00542 {
00543     PFN_NUMBER Pfn;
00544     PMMPTE Pte;
00545     MMPTE OldPte;
00546 
00547     Pte = MiGetPteForProcess(Process, Address, FALSE);
00548 
00549     if (Pte)
00550     {
00551         /* Atomically set the entry to zero and get the old value. */
00552         OldPte.u.Long = InterlockedExchange64((LONG64*)&Pte->u.Long, 0);
00553 
00554         if (OldPte.u.Hard.Valid)
00555         {
00556             Pfn = OldPte.u.Hard.PageFrameNumber;
00557 
00558             //if (FreePage)
00559                 //MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00560         }
00561         else
00562             Pfn = 0;
00563     }
00564     else
00565     {
00566         OldPte.u.Long = 0;
00567         Pfn = 0;
00568     }
00569 
00570     /* Return information to the caller */
00571     if (WasDirty)
00572         *WasDirty = (BOOLEAN)OldPte.u.Hard.Dirty;;
00573 
00574     if (Page)
00575         *Page = Pfn;
00576 
00577     MiFlushTlb(Pte, Address);
00578 }
00579 
00580 VOID
00581 NTAPI
00582 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
00583                         SWAPENTRY* SwapEntry)
00584 {
00585     UNIMPLEMENTED;
00586 }
00587 
00588 
00589 VOID
00590 NTAPI
00591 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
00592 {
00593     UNIMPLEMENTED;
00594 }
00595 
00596 
00597 NTSTATUS
00598 NTAPI
00599 MmCreatePageFileMapping(PEPROCESS Process,
00600                         PVOID Address,
00601                         SWAPENTRY SwapEntry)
00602 {
00603     UNIMPLEMENTED;
00604     return STATUS_UNSUCCESSFUL;
00605 }
00606 
00607 
00608 NTSTATUS
00609 NTAPI
00610 MmCreateVirtualMappingUnsafe(
00611     PEPROCESS Process,
00612     PVOID Address,
00613     ULONG PageProtection,
00614     PPFN_NUMBER Pages,
00615     ULONG PageCount)
00616 {
00617     ULONG i;
00618     MMPTE TmplPte, *Pte;
00619 
00620     ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0);
00621 
00622     /* Check if the range is valid */
00623     if ((Process == NULL && Address < MmSystemRangeStart) ||
00624         (Process != NULL && Address > MmHighestUserAddress))
00625     {
00626         DPRINT1("Address 0x%p is invalid for process %p\n", Address, Process);
00627         ASSERT(FALSE);
00628     }
00629 
00630     TmplPte.u.Long = 0;
00631     TmplPte.u.Hard.Valid = 1;
00632     MiSetPteProtection(&TmplPte, PageProtection);
00633 
00634     TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
00635 
00636 //__debugbreak();
00637 
00638     for (i = 0; i < PageCount; i++)
00639     {
00640         TmplPte.u.Hard.PageFrameNumber = Pages[i];
00641 
00642         Pte = MiGetPteForProcess(Process, Address, TRUE);
00643 
00644 DPRINT("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n",
00645         Address, TmplPte.u.Long, Pte);
00646 
00647         if (InterlockedExchangePte(Pte, TmplPte))
00648         {
00649             KeInvalidateTlbEntry(Address);
00650         }
00651 
00652         if (MiIsHyperspaceAddress(Pte))
00653             MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte));
00654 
00655         Address = (PVOID)((ULONG64)Address + PAGE_SIZE);
00656     }
00657 
00658 
00659     return STATUS_SUCCESS;
00660 }
00661 
00662 NTSTATUS
00663 NTAPI
00664 MmCreateVirtualMapping(PEPROCESS Process,
00665                        PVOID Address,
00666                        ULONG Protect,
00667                        PPFN_NUMBER Pages,
00668                        ULONG PageCount)
00669 {
00670     ULONG i;
00671 
00672     ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0);
00673 
00674     for (i = 0; i < PageCount; i++)
00675     {
00676         if (!MmIsPageInUse(Pages[i]))
00677         {
00678             DPRINT1("Page %x not in use\n", Pages[i]);
00679             KeBugCheck(MEMORY_MANAGEMENT);
00680         }
00681     }
00682 
00683     return MmCreateVirtualMappingUnsafe(Process, Address, Protect, Pages, PageCount);
00684 }
00685 
00686 BOOLEAN
00687 NTAPI
00688 MmCreateProcessAddressSpace(IN ULONG MinWs,
00689                             IN PEPROCESS Process,
00690                             OUT PULONG_PTR DirectoryTableBase)
00691 {
00692     KIRQL OldIrql;
00693     PFN_NUMBER TableBasePfn, HyperPfn, HyperPdPfn, HyperPtPfn, WorkingSetPfn;
00694     PMMPTE SystemPte;
00695     MMPTE TempPte, PdePte;
00696     ULONG TableIndex;
00697     PMMPTE PageTablePointer;
00698 
00699     /* Make sure we don't already have a page directory setup */
00700     ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
00701     ASSERT(Process->Pcb.DirectoryTableBase[1] == 0);
00702     ASSERT(Process->WorkingSetPage == 0);
00703 
00704     /* Choose a process color */
00705     Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
00706 
00707     /* Setup the hyperspace lock */
00708     KeInitializeSpinLock(&Process->HyperSpaceLock);
00709 
00710     /* Lock PFN database */
00711     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00712 
00713     /* Get a page for the table base and one for hyper space. The PFNs for
00714        these pages will be initialized in MmInitializeProcessAddressSpace,
00715        when we are already attached to the process. */
00716     TableBasePfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
00717     HyperPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
00718     HyperPdPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
00719     HyperPtPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
00720     WorkingSetPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
00721 
00722     /* Release PFN lock */
00723     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00724 
00725     /* Zero pages */ 
00726     MiZeroPhysicalPage(HyperPfn);
00727     MiZeroPhysicalPage(WorkingSetPfn);
00728 
00729     /* Set the base directory pointers */
00730     Process->WorkingSetPage = WorkingSetPfn;
00731     DirectoryTableBase[0] = TableBasePfn << PAGE_SHIFT;
00732     DirectoryTableBase[1] = HyperPfn << PAGE_SHIFT;
00733 
00734     /* Get a PTE to map the page directory */
00735     SystemPte = MiReserveSystemPtes(1, SystemPteSpace);
00736     ASSERT(SystemPte != NULL);
00737 
00738     /* Get its address */
00739     PageTablePointer = MiPteToAddress(SystemPte);
00740 
00741     /* Build the PTE for the page directory and map it */
00742     PdePte = ValidKernelPte;
00743     PdePte.u.Hard.PageFrameNumber = TableBasePfn;
00744     *SystemPte = PdePte;
00745 
00747     //MiInitializePageDirectoryForProcess(
00748 
00749     /* Copy the kernel mappings and zero out the rest */
00750     TableIndex = PXE_PER_PAGE / 2;
00751     RtlZeroMemory(PageTablePointer, TableIndex * sizeof(MMPTE));
00752     RtlCopyMemory(PageTablePointer + TableIndex,
00753                   MiAddressToPxe(0) + TableIndex,
00754                   PAGE_SIZE - TableIndex * sizeof(MMPTE));
00755 
00756     /* Sanity check */
00757     ASSERT(MiAddressToPxi(MmHyperSpaceEnd) >= TableIndex);
00758 
00759     /* Setup a PTE for the page directory mappings */
00760     TempPte = ValidKernelPte;
00761 
00762     /* Update the self mapping of the PML4 */
00763     TableIndex = MiAddressToPxi((PVOID)PXE_SELFMAP);
00764     TempPte.u.Hard.PageFrameNumber = TableBasePfn;
00765     PageTablePointer[TableIndex] = TempPte;
00766 
00767     /* Write the PML4 entry for hyperspace */
00768     TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE);
00769     TempPte.u.Hard.PageFrameNumber = HyperPfn;
00770     PageTablePointer[TableIndex] = TempPte;
00771 
00772     /* Map the hyperspace PDPT to the system PTE */
00773     PdePte.u.Hard.PageFrameNumber = HyperPfn;
00774     *SystemPte = PdePte;
00775     __invlpg(PageTablePointer);
00776 
00777     /* Write the hyperspace entry for the first PD */
00778     TempPte.u.Hard.PageFrameNumber = HyperPdPfn;
00779     PageTablePointer[0] = TempPte;
00780 
00781     /* Map the hyperspace PD to the system PTE */
00782     PdePte.u.Hard.PageFrameNumber = HyperPdPfn;
00783     *SystemPte = PdePte;
00784     __invlpg(PageTablePointer);
00785 
00786     /* Write the hyperspace entry for the first PT */
00787     TempPte.u.Hard.PageFrameNumber = HyperPtPfn;
00788     PageTablePointer[0] = TempPte;
00789 
00790     /* Map the hyperspace PT to the system PTE */
00791     PdePte.u.Hard.PageFrameNumber = HyperPtPfn;
00792     *SystemPte = PdePte;
00793     __invlpg(PageTablePointer);
00794 
00795     /* Write the hyperspace PTE for the working set list index */
00796     TempPte.u.Hard.PageFrameNumber = WorkingSetPfn;
00797     TableIndex = MiAddressToPti(MmWorkingSetList);
00798     PageTablePointer[TableIndex] = TempPte;
00799 
00801 
00802     /* Release the system PTE */
00803     MiReleaseSystemPtes(SystemPte, 1, SystemPteSpace);
00804 
00805     /* Switch to phase 1 initialization */
00806     ASSERT(Process->AddressSpaceInitialized == 0);
00807     Process->AddressSpaceInitialized = 1;
00808 
00809     return TRUE;
00810 }
00811 
00812 /* EOF */

Generated on Sat May 26 2012 04:25:34 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.