964d488479b63b92492f97db2816b7394b7d5997
[reactos.git] / ntoskrnl / mm / amd64 / page.c
1 /*
2 * COPYRIGHT: GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/amd64/page.c
5 * PURPOSE: Low level memory managment manipulation
6 *
7 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
8 * ReactOS Portable Systems Group
9 */
10
11 /* INCLUDES ***************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 #include <mm/ARM3/miarm.h>
17
18 #undef InterlockedExchangePte
19 #define InterlockedExchangePte(pte1, pte2) \
20 InterlockedExchange64((LONG64*)&pte1->u.Long, pte2.u.Long)
21
22 #define PAGE_EXECUTE_ANY (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)
23 #define PAGE_WRITE_ANY (PAGE_EXECUTE_READWRITE|PAGE_READWRITE|PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY)
24 #define PAGE_WRITECOPY_ANY (PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY)
25
26 extern MMPTE HyperTemplatePte;
27
28 /* GLOBALS *****************************************************************/
29
30 const
31 ULONG64
32 MmProtectToPteMask[32] =
33 {
34 //
35 // These are the base MM_ protection flags
36 //
37 0,
38 PTE_READONLY | PTE_ENABLE_CACHE,
39 PTE_EXECUTE | PTE_ENABLE_CACHE,
40 PTE_EXECUTE_READ | PTE_ENABLE_CACHE,
41 PTE_READWRITE | PTE_ENABLE_CACHE,
42 PTE_WRITECOPY | PTE_ENABLE_CACHE,
43 PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE,
44 PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE,
45 //
46 // These OR in the MM_NOCACHE flag
47 //
48 0,
49 PTE_READONLY | PTE_DISABLE_CACHE,
50 PTE_EXECUTE | PTE_DISABLE_CACHE,
51 PTE_EXECUTE_READ | PTE_DISABLE_CACHE,
52 PTE_READWRITE | PTE_DISABLE_CACHE,
53 PTE_WRITECOPY | PTE_DISABLE_CACHE,
54 PTE_EXECUTE_READWRITE | PTE_DISABLE_CACHE,
55 PTE_EXECUTE_WRITECOPY | PTE_DISABLE_CACHE,
56 //
57 // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM
58 //
59 0,
60 PTE_READONLY | PTE_ENABLE_CACHE,
61 PTE_EXECUTE | PTE_ENABLE_CACHE,
62 PTE_EXECUTE_READ | PTE_ENABLE_CACHE,
63 PTE_READWRITE | PTE_ENABLE_CACHE,
64 PTE_WRITECOPY | PTE_ENABLE_CACHE,
65 PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE,
66 PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE,
67 //
68 // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining?
69 //
70 0,
71 PTE_READONLY | PTE_WRITECOMBINED_CACHE,
72 PTE_EXECUTE | PTE_WRITECOMBINED_CACHE,
73 PTE_EXECUTE_READ | PTE_WRITECOMBINED_CACHE,
74 PTE_READWRITE | PTE_WRITECOMBINED_CACHE,
75 PTE_WRITECOPY | PTE_WRITECOMBINED_CACHE,
76 PTE_EXECUTE_READWRITE | PTE_WRITECOMBINED_CACHE,
77 PTE_EXECUTE_WRITECOPY | PTE_WRITECOMBINED_CACHE,
78 };
79
80 const
81 ULONG MmProtectToValue[32] =
82 {
83 PAGE_NOACCESS,
84 PAGE_READONLY,
85 PAGE_EXECUTE,
86 PAGE_EXECUTE_READ,
87 PAGE_READWRITE,
88 PAGE_WRITECOPY,
89 PAGE_EXECUTE_READWRITE,
90 PAGE_EXECUTE_WRITECOPY,
91 PAGE_NOACCESS,
92 PAGE_NOCACHE | PAGE_READONLY,
93 PAGE_NOCACHE | PAGE_EXECUTE,
94 PAGE_NOCACHE | PAGE_EXECUTE_READ,
95 PAGE_NOCACHE | PAGE_READWRITE,
96 PAGE_NOCACHE | PAGE_WRITECOPY,
97 PAGE_NOCACHE | PAGE_EXECUTE_READWRITE,
98 PAGE_NOCACHE | PAGE_EXECUTE_WRITECOPY,
99 PAGE_NOACCESS,
100 PAGE_GUARD | PAGE_READONLY,
101 PAGE_GUARD | PAGE_EXECUTE,
102 PAGE_GUARD | PAGE_EXECUTE_READ,
103 PAGE_GUARD | PAGE_READWRITE,
104 PAGE_GUARD | PAGE_WRITECOPY,
105 PAGE_GUARD | PAGE_EXECUTE_READWRITE,
106 PAGE_GUARD | PAGE_EXECUTE_WRITECOPY,
107 PAGE_NOACCESS,
108 PAGE_WRITECOMBINE | PAGE_READONLY,
109 PAGE_WRITECOMBINE | PAGE_EXECUTE,
110 PAGE_WRITECOMBINE | PAGE_EXECUTE_READ,
111 PAGE_WRITECOMBINE | PAGE_READWRITE,
112 PAGE_WRITECOMBINE | PAGE_WRITECOPY,
113 PAGE_WRITECOMBINE | PAGE_EXECUTE_READWRITE,
114 PAGE_WRITECOMBINE | PAGE_EXECUTE_WRITECOPY
115 };
116
117 /* PRIVATE FUNCTIONS *******************************************************/
118
119 BOOLEAN
120 FORCEINLINE
121 MiIsHyperspaceAddress(PVOID Address)
122 {
123 return ((ULONG64)Address >= HYPER_SPACE &&
124 (ULONG64)Address <= HYPER_SPACE_END);
125 }
126
127 VOID
128 MiFlushTlb(PMMPTE Pte, PVOID Address)
129 {
130 if (MiIsHyperspaceAddress(Pte))
131 {
132 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte));
133 }
134 else
135 {
136 __invlpg(Address);
137 }
138 }
139
140 static
141 PMMPTE
142 MiGetPteForProcess(
143 PEPROCESS Process,
144 PVOID Address,
145 BOOLEAN Create)
146 {
147 MMPTE TmplPte, *Pte;
148
149 /* Check if we need hypersapce mapping */
150 if (Address < MmSystemRangeStart &&
151 Process && Process != PsGetCurrentProcess())
152 {
153 UNIMPLEMENTED;
154 __debugbreak();
155 return NULL;
156 }
157 else if (Create)
158 {
159 KIRQL OldIrql;
160 TmplPte.u.Long = 0;
161 TmplPte.u.Flush.Valid = 1;
162 TmplPte.u.Flush.Write = 1;
163
164 /* All page table levels of user pages are user owned */
165 TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
166
167 /* Lock the PFN database */
168 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
169
170 /* Get the PXE */
171 Pte = MiAddressToPxe(Address);
172 if (!Pte->u.Hard.Valid)
173 {
174 TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(0);
175 MI_WRITE_VALID_PTE(Pte, TmplPte);
176 }
177
178 /* Get the PPE */
179 Pte = MiAddressToPpe(Address);
180 if (!Pte->u.Hard.Valid)
181 {
182 TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(1);
183 MI_WRITE_VALID_PTE(Pte, TmplPte);
184 }
185
186 /* Get the PDE */
187 Pte = MiAddressToPde(Address);
188 if (!Pte->u.Hard.Valid)
189 {
190 TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(2);
191 MI_WRITE_VALID_PTE(Pte, TmplPte);
192 }
193
194 /* Unlock PFN database */
195 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
196 }
197 else
198 {
199 /* Get the PXE */
200 Pte = MiAddressToPxe(Address);
201 if (!Pte->u.Hard.Valid)
202 return NULL;
203
204 /* Get the PPE */
205 Pte = MiAddressToPpe(Address);
206 if (!Pte->u.Hard.Valid)
207 return NULL;
208
209 /* Get the PDE */
210 Pte = MiAddressToPde(Address);
211 if (!Pte->u.Hard.Valid)
212 return NULL;
213 }
214
215 return MiAddressToPte(Address);
216 }
217
218 static
219 ULONG64
220 MiGetPteValueForProcess(
221 PEPROCESS Process,
222 PVOID Address)
223 {
224 PMMPTE Pte;
225 ULONG64 PteValue;
226
227 Pte = MiGetPteForProcess(Process, Address, FALSE);
228 PteValue = Pte ? Pte->u.Long : 0;
229
230 if (MiIsHyperspaceAddress(Pte))
231 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte));
232
233 return PteValue;
234 }
235
236 ULONG
237 NTAPI
238 MiGetPteProtection(MMPTE Pte)
239 {
240 ULONG Protect;
241
242 if (!Pte.u.Flush.Valid)
243 {
244 Protect = PAGE_NOACCESS;
245 }
246 else if (Pte.u.Flush.NoExecute)
247 {
248 if (Pte.u.Flush.CopyOnWrite)
249 Protect = PAGE_WRITECOPY;
250 else if (Pte.u.Flush.Write)
251 Protect = PAGE_READWRITE;
252 else
253 Protect = PAGE_READONLY;
254 }
255 else
256 {
257 if (Pte.u.Flush.CopyOnWrite)
258 Protect = PAGE_EXECUTE_WRITECOPY;
259 else if (Pte.u.Flush.Write)
260 Protect = PAGE_EXECUTE_READWRITE;
261 else
262 Protect = PAGE_EXECUTE_READ;
263 }
264
265 if (Pte.u.Flush.CacheDisable)
266 Protect |= PAGE_NOCACHE;
267
268 if (Pte.u.Flush.WriteThrough)
269 Protect |= PAGE_WRITETHROUGH;
270
271 // PAGE_GUARD ?
272 return Protect;
273 }
274
275 VOID
276 NTAPI
277 MiSetPteProtection(PMMPTE Pte, ULONG Protection)
278 {
279 Pte->u.Flush.CopyOnWrite = (Protection & PAGE_WRITECOPY_ANY) ? 1 : 0;
280 Pte->u.Flush.Write = (Protection & PAGE_WRITE_ANY) ? 1 : 0;
281 Pte->u.Flush.CacheDisable = (Protection & PAGE_NOCACHE) ? 1 : 0;
282 Pte->u.Flush.WriteThrough = (Protection & PAGE_WRITETHROUGH) ? 1 : 0;
283
284 // FIXME: This doesn't work. Why?
285 // Pte->u.Flush.NoExecute = (Protection & PAGE_EXECUTE_ANY) ? 0 : 1;
286 }
287
288 /* FUNCTIONS ***************************************************************/
289
290 PFN_NUMBER
291 NTAPI
292 MmGetPfnForProcess(PEPROCESS Process,
293 PVOID Address)
294 {
295 MMPTE Pte;
296 Pte.u.Long = MiGetPteValueForProcess(Process, Address);
297 return Pte.u.Hard.Valid ? Pte.u.Hard.PageFrameNumber : 0;
298 }
299
300 BOOLEAN
301 NTAPI
302 MmIsPagePresent(PEPROCESS Process, PVOID Address)
303 {
304 MMPTE Pte;
305 Pte.u.Long = MiGetPteValueForProcess(Process, Address);
306 return (BOOLEAN)Pte.u.Hard.Valid;
307 }
308
309 BOOLEAN
310 NTAPI
311 MmIsDisabledPage(PEPROCESS Process, PVOID Address)
312 {
313 MMPTE Pte;
314 Pte.u.Long = MiGetPteValueForProcess(Process, Address);
315 __debugbreak(); // FIXME
316 return !Pte.u.Hard.Valid && !(Pte.u.Long & 0x800) && Pte.u.Hard.PageFrameNumber;
317 }
318
319 BOOLEAN
320 NTAPI
321 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
322 {
323 MMPTE Pte;
324 Pte.u.Long = MiGetPteValueForProcess(Process, Address);
325 return Pte.u.Hard.Valid && Pte.u.Soft.Transition;
326 }
327
328 static PMMPTE
329 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
330 {
331 __debugbreak();
332 return 0;
333 }
334
335 BOOLEAN MmUnmapPageTable(PMMPTE Pt)
336 {
337 ASSERT(FALSE);
338 return 0;
339 }
340
341 static ULONG64 MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
342 {
343 MMPTE Pte, *PointerPte;
344
345 PointerPte = MmGetPageTableForProcess(Process, Address, FALSE);
346 if (PointerPte)
347 {
348 Pte = *PointerPte;
349 MmUnmapPageTable(PointerPte);
350 return Pte.u.Long;
351 }
352 return 0;
353 }
354
355 VOID
356 NTAPI
357 MmGetPageFileMapping(
358 PEPROCESS Process,
359 PVOID Address,
360 SWAPENTRY* SwapEntry)
361 {
362 ULONG64 Entry = MmGetPageEntryForProcess(Process, Address);
363 *SwapEntry = Entry >> 1;
364 }
365
366 BOOLEAN
367 NTAPI
368 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
369 {
370 MMPTE Pte;
371 Pte.u.Long = MiGetPteValueForProcess(Process, Address);
372 return Pte.u.Hard.Valid && Pte.u.Hard.Dirty;
373 }
374
375 ULONG
376 NTAPI
377 MmGetPageProtect(PEPROCESS Process, PVOID Address)
378 {
379 MMPTE Pte;
380
381 Pte.u.Long = MiGetPteValueForProcess(Process, Address);
382
383 return MiGetPteProtection(Pte);
384 }
385
386 VOID
387 NTAPI
388 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
389 {
390 PMMPTE Pte;
391 MMPTE NewPte;
392
393 Pte = MiGetPteForProcess(Process, Address, FALSE);
394 ASSERT(Pte != NULL);
395
396 NewPte = *Pte;
397
398 MiSetPteProtection(&NewPte, flProtect);
399
400 InterlockedExchangePte(Pte, NewPte);
401
402 MiFlushTlb(Pte, Address);
403 }
404
405 VOID
406 NTAPI
407 MmSetCleanPage(PEPROCESS Process, PVOID Address)
408 {
409 PMMPTE Pte;
410
411 Pte = MiGetPteForProcess(Process, Address, FALSE);
412 if (!Pte)
413 {
414 KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0);
415 }
416
417 /* Ckear the dirty bit */
418 if (InterlockedBitTestAndReset64((PVOID)Pte, 6))
419 {
420 if (!MiIsHyperspaceAddress(Pte))
421 __invlpg(Address);
422 }
423
424 MiFlushTlb(Pte, Address);
425 }
426
427 VOID
428 NTAPI
429 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
430 {
431 PMMPTE Pte;
432
433 Pte = MiGetPteForProcess(Process, Address, FALSE);
434 if (!Pte)
435 {
436 KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0);
437 }
438
439 /* Ckear the dirty bit */
440 if (InterlockedBitTestAndSet64((PVOID)Pte, 6))
441 {
442 if (!MiIsHyperspaceAddress(Pte))
443 __invlpg(Address);
444 }
445
446 MiFlushTlb(Pte, Address);
447 }
448
449 VOID
450 NTAPI
451 MmDeleteVirtualMapping(
452 PEPROCESS Process,
453 PVOID Address,
454 BOOLEAN* WasDirty,
455 PPFN_NUMBER Page)
456 {
457 PFN_NUMBER Pfn;
458 PMMPTE Pte;
459 MMPTE OldPte;
460
461 Pte = MiGetPteForProcess(Process, Address, FALSE);
462
463 if (Pte)
464 {
465 /* Atomically set the entry to zero and get the old value. */
466 OldPte.u.Long = InterlockedExchange64((LONG64*)&Pte->u.Long, 0);
467
468 if (OldPte.u.Hard.Valid)
469 {
470 Pfn = OldPte.u.Hard.PageFrameNumber;
471 }
472 else
473 Pfn = 0;
474 }
475 else
476 {
477 OldPte.u.Long = 0;
478 Pfn = 0;
479 }
480
481 /* Return information to the caller */
482 if (WasDirty)
483 *WasDirty = (BOOLEAN)OldPte.u.Hard.Dirty;
484
485 if (Page)
486 *Page = Pfn;
487
488 MiFlushTlb(Pte, Address);
489 }
490
491 VOID
492 NTAPI
493 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
494 SWAPENTRY* SwapEntry)
495 {
496 UNIMPLEMENTED;
497 }
498
499 NTSTATUS
500 NTAPI
501 MmCreatePageFileMapping(PEPROCESS Process,
502 PVOID Address,
503 SWAPENTRY SwapEntry)
504 {
505 UNIMPLEMENTED;
506 return STATUS_UNSUCCESSFUL;
507 }
508
509
510 NTSTATUS
511 NTAPI
512 MmCreateVirtualMappingUnsafe(
513 PEPROCESS Process,
514 PVOID Address,
515 ULONG PageProtection,
516 PPFN_NUMBER Pages,
517 ULONG PageCount)
518 {
519 ULONG i;
520 MMPTE TmplPte, *Pte;
521
522 ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0);
523
524 /* Check if the range is valid */
525 if ((Process == NULL && Address < MmSystemRangeStart) ||
526 (Process != NULL && Address > MmHighestUserAddress))
527 {
528 DPRINT1("Address 0x%p is invalid for process %p\n", Address, Process);
529 ASSERT(FALSE);
530 }
531
532 TmplPte.u.Long = 0;
533 TmplPte.u.Hard.Valid = 1;
534 MiSetPteProtection(&TmplPte, PageProtection);
535
536 TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
537
538 //__debugbreak();
539
540 for (i = 0; i < PageCount; i++)
541 {
542 TmplPte.u.Hard.PageFrameNumber = Pages[i];
543
544 Pte = MiGetPteForProcess(Process, Address, TRUE);
545
546 DPRINT("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n",
547 Address, TmplPte.u.Long, Pte);
548
549 if (InterlockedExchangePte(Pte, TmplPte))
550 {
551 KeInvalidateTlbEntry(Address);
552 }
553
554 if (MiIsHyperspaceAddress(Pte))
555 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte));
556
557 Address = (PVOID)((ULONG64)Address + PAGE_SIZE);
558 }
559
560
561 return STATUS_SUCCESS;
562 }
563
564 NTSTATUS
565 NTAPI
566 MmCreateVirtualMapping(PEPROCESS Process,
567 PVOID Address,
568 ULONG Protect,
569 PPFN_NUMBER Pages,
570 ULONG PageCount)
571 {
572 ULONG i;
573
574 ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0);
575
576 for (i = 0; i < PageCount; i++)
577 {
578 if (!MmIsPageInUse(Pages[i]))
579 {
580 DPRINT1("Page %x not in use\n", Pages[i]);
581 KeBugCheck(MEMORY_MANAGEMENT);
582 }
583 }
584
585 return MmCreateVirtualMappingUnsafe(Process, Address, Protect, Pages, PageCount);
586 }
587
588 BOOLEAN
589 NTAPI
590 MmCreateProcessAddressSpace(IN ULONG MinWs,
591 IN PEPROCESS Process,
592 OUT PULONG_PTR DirectoryTableBase)
593 {
594 KIRQL OldIrql;
595 PFN_NUMBER TableBasePfn, HyperPfn, HyperPdPfn, HyperPtPfn, WorkingSetPfn;
596 PMMPTE SystemPte;
597 MMPTE TempPte, PdePte;
598 ULONG TableIndex;
599 PMMPTE PageTablePointer;
600
601 /* Make sure we don't already have a page directory setup */
602 ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
603 ASSERT(Process->Pcb.DirectoryTableBase[1] == 0);
604 ASSERT(Process->WorkingSetPage == 0);
605
606 /* Choose a process color */
607 Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
608
609 /* Setup the hyperspace lock */
610 KeInitializeSpinLock(&Process->HyperSpaceLock);
611
612 /* Lock PFN database */
613 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
614
615 /* Get a page for the table base and one for hyper space. The PFNs for
616 these pages will be initialized in MmInitializeProcessAddressSpace,
617 when we are already attached to the process. */
618 TableBasePfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
619 HyperPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
620 HyperPdPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
621 HyperPtPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
622 WorkingSetPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
623
624 /* Release PFN lock */
625 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
626
627 /* Zero pages */ /// FIXME:
628 MiZeroPhysicalPage(HyperPfn);
629 MiZeroPhysicalPage(WorkingSetPfn);
630
631 /* Set the base directory pointers */
632 Process->WorkingSetPage = WorkingSetPfn;
633 DirectoryTableBase[0] = TableBasePfn << PAGE_SHIFT;
634 DirectoryTableBase[1] = HyperPfn << PAGE_SHIFT;
635
636 /* Get a PTE to map the page directory */
637 SystemPte = MiReserveSystemPtes(1, SystemPteSpace);
638 ASSERT(SystemPte != NULL);
639
640 /* Get its address */
641 PageTablePointer = MiPteToAddress(SystemPte);
642
643 /* Build the PTE for the page directory and map it */
644 PdePte = ValidKernelPte;
645 PdePte.u.Hard.PageFrameNumber = TableBasePfn;
646 *SystemPte = PdePte;
647
648 /// architecture specific
649 //MiInitializePageDirectoryForProcess(
650
651 /* Copy the kernel mappings and zero out the rest */
652 TableIndex = PXE_PER_PAGE / 2;
653 RtlZeroMemory(PageTablePointer, TableIndex * sizeof(MMPTE));
654 RtlCopyMemory(PageTablePointer + TableIndex,
655 MiAddressToPxe(0) + TableIndex,
656 PAGE_SIZE - TableIndex * sizeof(MMPTE));
657
658 /* Sanity check */
659 ASSERT(MiAddressToPxi(MmHyperSpaceEnd) >= TableIndex);
660
661 /* Setup a PTE for the page directory mappings */
662 TempPte = ValidKernelPte;
663
664 /* Update the self mapping of the PML4 */
665 TableIndex = MiAddressToPxi((PVOID)PXE_SELFMAP);
666 TempPte.u.Hard.PageFrameNumber = TableBasePfn;
667 PageTablePointer[TableIndex] = TempPte;
668
669 /* Write the PML4 entry for hyperspace */
670 TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE);
671 TempPte.u.Hard.PageFrameNumber = HyperPfn;
672 PageTablePointer[TableIndex] = TempPte;
673
674 /* Map the hyperspace PDPT to the system PTE */
675 PdePte.u.Hard.PageFrameNumber = HyperPfn;
676 *SystemPte = PdePte;
677 __invlpg(PageTablePointer);
678
679 /* Write the hyperspace entry for the first PD */
680 TempPte.u.Hard.PageFrameNumber = HyperPdPfn;
681 PageTablePointer[0] = TempPte;
682
683 /* Map the hyperspace PD to the system PTE */
684 PdePte.u.Hard.PageFrameNumber = HyperPdPfn;
685 *SystemPte = PdePte;
686 __invlpg(PageTablePointer);
687
688 /* Write the hyperspace entry for the first PT */
689 TempPte.u.Hard.PageFrameNumber = HyperPtPfn;
690 PageTablePointer[0] = TempPte;
691
692 /* Map the hyperspace PT to the system PTE */
693 PdePte.u.Hard.PageFrameNumber = HyperPtPfn;
694 *SystemPte = PdePte;
695 __invlpg(PageTablePointer);
696
697 /* Write the hyperspace PTE for the working set list index */
698 TempPte.u.Hard.PageFrameNumber = WorkingSetPfn;
699 TableIndex = MiAddressToPti(MmWorkingSetList);
700 PageTablePointer[TableIndex] = TempPte;
701
702 /// end architecture specific
703
704 /* Release the system PTE */
705 MiReleaseSystemPtes(SystemPte, 1, SystemPteSpace);
706
707 /* Switch to phase 1 initialization */
708 ASSERT(Process->AddressSpaceInitialized == 0);
709 Process->AddressSpaceInitialized = 1;
710
711 return TRUE;
712 }
713
714 /* EOF */