* Sync up to trunk r55544.
[reactos.git] / ntoskrnl / mm / ARM3 / i386 / init.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/i386/init.c
5 * PURPOSE: ARM Memory Manager Initialization for x86
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define MODULE_INVOLVED_IN_ARM3
16 #include "../../ARM3/miarm.h"
17
18 /* GLOBALS ********************************************************************/
19
20 /* Template PTE and PDE for a kernel page */
21 MMPTE ValidKernelPde = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}};
22 MMPTE ValidKernelPte = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}};
23
24 /* Template PDE for a demand-zero page */
25 MMPDE DemandZeroPde = {{MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}};
26 MMPTE DemandZeroPte = {{MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}};
27
28 /* Template PTE for prototype page */
29 MMPTE PrototypePte = {{(MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) |
30 PTE_PROTOTYPE | (MI_PTE_LOOKUP_NEEDED << PAGE_SHIFT)}};
31
32
33 /* PRIVATE FUNCTIONS **********************************************************/
34
35 VOID
36 NTAPI
37 INIT_FUNCTION
38 MiInitializeSessionSpaceLayout()
39 {
40 //
41 // Set the size of session view, pool, and image
42 //
43 MmSessionSize = MI_SESSION_SIZE;
44 MmSessionViewSize = MI_SESSION_VIEW_SIZE;
45 MmSessionPoolSize = MI_SESSION_POOL_SIZE;
46 MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
47
48 //
49 // Set the size of system view
50 //
51 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
52
53 //
54 // This is where it all ends
55 //
56 MiSessionImageEnd = (PVOID)PTE_BASE;
57
58 //
59 // This is where we will load Win32k.sys and the video driver
60 //
61 MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
62 MmSessionImageSize);
63
64 //
65 // So the view starts right below the session working set (itself below
66 // the image area)
67 //
68 MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
69 MmSessionImageSize -
70 MI_SESSION_WORKING_SET_SIZE -
71 MmSessionViewSize);
72
73 //
74 // Session pool follows
75 //
76 MiSessionPoolEnd = MiSessionViewStart;
77 MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
78 MmSessionPoolSize);
79
80 //
81 // And it all begins here
82 //
83 MmSessionBase = MiSessionPoolStart;
84
85 //
86 // Sanity check that our math is correct
87 //
88 ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
89
90 //
91 // Session space ends wherever image session space ends
92 //
93 MiSessionSpaceEnd = MiSessionImageEnd;
94
95 //
96 // System view space ends at session space, so now that we know where
97 // this is, we can compute the base address of system view space itself.
98 //
99 MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
100 MmSystemViewSize);
101
102 /* Compute the PTE addresses for all the addresses we carved out */
103 MiSessionImagePteStart = MiAddressToPte(MiSessionImageStart);
104 MiSessionImagePteEnd = MiAddressToPte(MiSessionImageEnd);
105 MiSessionBasePte = MiAddressToPte(MmSessionBase);
106 MiSessionLastPte = MiAddressToPte(MiSessionSpaceEnd);
107 }
108
109 VOID
110 NTAPI
111 INIT_FUNCTION
112 MiComputeNonPagedPoolVa(IN ULONG FreePages)
113 {
114 IN PFN_NUMBER PoolPages;
115
116 /* Check if this is a machine with less than 256MB of RAM, and no overide */
117 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
118 !(MmSizeOfNonPagedPoolInBytes))
119 {
120 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
121 MmSizeOfNonPagedPoolInBytes = 2 * _1MB;
122 }
123
124 /* Hyperspace ends here */
125 MmHyperSpaceEnd = (PVOID)((ULONG_PTR)MmSystemCacheWorkingSetList - 1);
126
127 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
128 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) > (FreePages * 7 / 8))
129 {
130 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
131 MmSizeOfNonPagedPoolInBytes = 0;
132 }
133
134 /* Check if no registry setting was set, or if the setting was too low */
135 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
136 {
137 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
138 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
139 MmSizeOfNonPagedPoolInBytes += (FreePages - 1024) / 256 * MmMinAdditionNonPagedPoolPerMb;
140 }
141
142 /* Check if the registy setting or our dynamic calculation was too high */
143 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
144 {
145 /* Set it to the maximum */
146 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
147 }
148
149 /* Check if a percentage cap was set through the registry */
150 if (MmMaximumNonPagedPoolPercent) UNIMPLEMENTED;
151
152 /* Page-align the nonpaged pool size */
153 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
154
155 /* Now, check if there was a registry size for the maximum size */
156 if (!MmMaximumNonPagedPoolInBytes)
157 {
158 /* Start with the default (1MB) */
159 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
160
161 /* Add space for PFN database */
162 MmMaximumNonPagedPoolInBytes += (ULONG)
163 PAGE_ALIGN((MmHighestPhysicalPage + 1) * sizeof(MMPFN));
164
165 /* Check if the machine has more than 512MB of free RAM */
166 if (FreePages >= 0x1F000)
167 {
168 /* Add 200KB for each MB above 4 */
169 MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 *
170 (MmMaxAdditionNonPagedPoolPerMb / 2);
171 if (MmMaximumNonPagedPoolInBytes < MI_MAX_NONPAGED_POOL_SIZE)
172 {
173 /* Make it at least 128MB since this machine has a lot of RAM */
174 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
175 }
176 }
177 else
178 {
179 /* Add 400KB for each MB above 4 */
180 MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 *
181 MmMaxAdditionNonPagedPoolPerMb;
182 }
183 }
184
185 /* Make sure there's at least 16 pages + the PFN available for expansion */
186 PoolPages = MmSizeOfNonPagedPoolInBytes + (PAGE_SIZE * 16) +
187 ((ULONG)PAGE_ALIGN(MmHighestPhysicalPage + 1) * sizeof(MMPFN));
188 if (MmMaximumNonPagedPoolInBytes < PoolPages)
189 {
190 /* The maximum should be at least high enough to cover all the above */
191 MmMaximumNonPagedPoolInBytes = PoolPages;
192 }
193
194 /* Systems with 2GB of kernel address space get double the size */
195 PoolPages = MI_MAX_NONPAGED_POOL_SIZE * 2;
196
197 /* On the other hand, make sure that PFN + nonpaged pool doesn't get too big */
198 if (MmMaximumNonPagedPoolInBytes > PoolPages)
199 {
200 /* Trim it down to the maximum architectural limit (256MB) */
201 MmMaximumNonPagedPoolInBytes = PoolPages;
202 }
203
204 /* Check if this is a system with > 128MB of non paged pool */
205 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
206 {
207 /* Check if the initial size is less than the extra 128MB boost */
208 if (MmSizeOfNonPagedPoolInBytes < (MmMaximumNonPagedPoolInBytes -
209 MI_MAX_NONPAGED_POOL_SIZE))
210 {
211 /* FIXME: Should check if the initial pool can be expanded */
212
213 /* Assume no expansion possible, check ift he maximum is too large */
214 if (MmMaximumNonPagedPoolInBytes > (MmSizeOfNonPagedPoolInBytes +
215 MI_MAX_NONPAGED_POOL_SIZE))
216 {
217 /* Set it to the initial value plus the boost */
218 MmMaximumNonPagedPoolInBytes = MmSizeOfNonPagedPoolInBytes +
219 MI_MAX_NONPAGED_POOL_SIZE;
220 }
221 }
222 }
223 }
224
225 NTSTATUS
226 NTAPI
227 INIT_FUNCTION
228 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
229 {
230 PFN_NUMBER PageFrameIndex;
231 PMMPTE StartPde, EndPde, PointerPte, LastPte;
232 MMPTE TempPde, TempPte;
233 PVOID NonPagedPoolExpansionVa;
234 KIRQL OldIrql;
235 PMMPFN Pfn1;
236 ULONG Flags;
237
238 /* Check for global bit */
239 #if 0
240 if (KeFeatureBits & KF_GLOBAL_PAGE)
241 {
242 /* Set it on the template PTE and PDE */
243 ValidKernelPte.u.Hard.Global = TRUE;
244 ValidKernelPde.u.Hard.Global = TRUE;
245 }
246 #endif
247 /* Now templates are ready */
248 TempPte = ValidKernelPte;
249 TempPde = ValidKernelPde;
250
251 //
252 // Set CR3 for the system process
253 //
254 PointerPte = MiAddressToPde(PDE_BASE);
255 PageFrameIndex = PFN_FROM_PTE(PointerPte) << PAGE_SHIFT;
256 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameIndex;
257
258 //
259 // Blow away user-mode
260 //
261 StartPde = MiAddressToPde(0);
262 EndPde = MiAddressToPde(KSEG0_BASE);
263 RtlZeroMemory(StartPde, (EndPde - StartPde) * sizeof(MMPTE));
264
265 /* Compute non paged pool limits and size */
266 MiComputeNonPagedPoolVa(MiNumberOfFreePages);
267
268 //
269 // Now calculate the nonpaged pool expansion VA region
270 //
271 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
272 MmMaximumNonPagedPoolInBytes +
273 MmSizeOfNonPagedPoolInBytes);
274 MmNonPagedPoolStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolStart);
275 NonPagedPoolExpansionVa = MmNonPagedPoolStart;
276 DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
277 MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
278
279 //
280 // Now calculate the nonpaged system VA region, which includes the
281 // nonpaged pool expansion (above) and the system PTEs. Note that it is
282 // then aligned to a PDE boundary (4MB).
283 //
284 MiNonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
285 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart -
286 MiNonPagedSystemSize);
287 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
288 ~(PDE_MAPPED_VA - 1));
289
290 //
291 // Don't let it go below the minimum
292 //
293 if (MmNonPagedSystemStart < (PVOID)0xEB000000)
294 {
295 //
296 // This is a hard-coded limit in the Windows NT address space
297 //
298 MmNonPagedSystemStart = (PVOID)0xEB000000;
299
300 //
301 // Reduce the amount of system PTEs to reach this point
302 //
303 MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart -
304 (ULONG_PTR)MmNonPagedSystemStart) >>
305 PAGE_SHIFT;
306 MmNumberOfSystemPtes--;
307 ASSERT(MmNumberOfSystemPtes > 1000);
308 }
309
310 //
311 // Check if we are in a situation where the size of the paged pool
312 // is so large that it overflows into nonpaged pool
313 //
314 if (MmSizeOfPagedPoolInBytes >
315 ((ULONG_PTR)MmNonPagedSystemStart - (ULONG_PTR)MmPagedPoolStart))
316 {
317 //
318 // We need some recalculations here
319 //
320 DPRINT1("Paged pool is too big!\n");
321 }
322
323 //
324 // Normally, the PFN database should start after the loader images.
325 // This is already the case in ReactOS, but for now we want to co-exist
326 // with the old memory manager, so we'll create a "Shadow PFN Database"
327 // instead, and arbitrarly start it at 0xB0000000.
328 //
329 MmPfnDatabase = (PVOID)0xB0000000;
330 ASSERT(((ULONG_PTR)MmPfnDatabase & (PDE_MAPPED_VA - 1)) == 0);
331
332 //
333 // Non paged pool comes after the PFN database
334 //
335 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase +
336 (MxPfnAllocation << PAGE_SHIFT));
337
338 //
339 // Now we actually need to get these many physical pages. Nonpaged pool
340 // is actually also physically contiguous (but not the expansion)
341 //
342 PageFrameIndex = MxGetNextPage(MxPfnAllocation +
343 (MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT));
344 ASSERT(PageFrameIndex != 0);
345 DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex);
346 DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex + MxPfnAllocation);
347
348 /* Convert nonpaged pool size from bytes to pages */
349 MmMaximumNonPagedPoolInPages = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT;
350
351 //
352 // Now we need some pages to create the page tables for the NP system VA
353 // which includes system PTEs and expansion NP
354 //
355 StartPde = MiAddressToPde(MmNonPagedSystemStart);
356 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
357 while (StartPde <= EndPde)
358 {
359 //
360 // Get a page
361 //
362 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
363 MI_WRITE_VALID_PTE(StartPde, TempPde);
364
365 //
366 // Zero out the page table
367 //
368 PointerPte = MiPteToAddress(StartPde);
369 RtlZeroMemory(PointerPte, PAGE_SIZE);
370
371 //
372 // Next
373 //
374 StartPde++;
375 }
376
377 //
378 // Now we need pages for the page tables which will map initial NP
379 //
380 StartPde = MiAddressToPde(MmPfnDatabase);
381 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
382 MmSizeOfNonPagedPoolInBytes - 1));
383 while (StartPde <= EndPde)
384 {
385 //
386 // Get a page
387 //
388 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
389 MI_WRITE_VALID_PTE(StartPde, TempPde);
390
391 //
392 // Zero out the page table
393 //
394 PointerPte = MiPteToAddress(StartPde);
395 RtlZeroMemory(PointerPte, PAGE_SIZE);
396
397 //
398 // Next
399 //
400 StartPde++;
401 }
402
403 //
404 // Now remember where the expansion starts
405 //
406 MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa;
407
408 //
409 // Last step is to actually map the nonpaged pool
410 //
411 PointerPte = MiAddressToPte(MmNonPagedPoolStart);
412 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
413 MmSizeOfNonPagedPoolInBytes - 1));
414 while (PointerPte <= LastPte)
415 {
416 //
417 // Use one of our contigous pages
418 //
419 TempPte.u.Hard.PageFrameNumber = PageFrameIndex++;
420 MI_WRITE_VALID_PTE(PointerPte++, TempPte);
421 }
422
423 //
424 // Sanity check: make sure we have properly defined the system PTE space
425 //
426 ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
427 MiAddressToPte(MmNonPagedPoolExpansionStart));
428
429 /* Now go ahead and initialize the nonpaged pool */
430 MiInitializeNonPagedPool();
431 MiInitializeNonPagedPoolThresholds();
432
433 /* Map the PFN database pages */
434 MiMapPfnDatabase(LoaderBlock);
435
436 /* Initialize the color tables */
437 MiInitializeColorTables();
438
439 /* Build the PFN Database */
440 MiInitializePfnDatabase(LoaderBlock);
441 MmInitializeBalancer(MmAvailablePages, 0);
442
443 //
444 // Reset the descriptor back so we can create the correct memory blocks
445 //
446 *MxFreeDescriptor = MxOldFreeDescriptor;
447
448 //
449 // Initialize the nonpaged pool
450 //
451 InitializePool(NonPagedPool, 0);
452
453 //
454 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
455 //
456 PointerPte = MiAddressToPte(MmNonPagedSystemStart);
457 MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
458 PointerPte;
459 MmNumberOfSystemPtes--;
460 DPRINT("Final System PTE count: %d (%d bytes)\n",
461 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
462
463 //
464 // Create the system PTE space
465 //
466 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
467
468 /* Get the PDE For hyperspace */
469 StartPde = MiAddressToPde(HYPER_SPACE);
470
471 /* Lock PFN database */
472 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
473
474 /* Allocate a page for hyperspace and create it */
475 MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
476 MI_SET_PROCESS2("Kernel");
477 PageFrameIndex = MiRemoveAnyPage(0);
478 TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
479 TempPde.u.Hard.Global = FALSE; // Hyperspace is local!
480 MI_WRITE_VALID_PTE(StartPde, TempPde);
481
482 /* Flush the TLB */
483 KeFlushCurrentTb();
484
485 /* Release the lock */
486 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
487
488 //
489 // Zero out the page table now
490 //
491 PointerPte = MiAddressToPte(HYPER_SPACE);
492 RtlZeroMemory(PointerPte, PAGE_SIZE);
493
494 //
495 // Setup the mapping PTEs
496 //
497 MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
498 MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
499 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
500
501 /* Set the working set address */
502 MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST;
503
504 //
505 // Reserve system PTEs for zeroing PTEs and clear them
506 //
507 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
508 SystemPteSpace);
509 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
510
511 //
512 // Set the counter to maximum to boot with
513 //
514 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
515
516 /* Lock PFN database */
517 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
518
519 /* Reset the ref/share count so that MmInitializeProcessAddressSpace works */
520 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(MiAddressToPde(PDE_BASE)));
521 Pfn1->u2.ShareCount = 0;
522 Pfn1->u3.e2.ReferenceCount = 0;
523
524 /* Get a page for the working set list */
525 MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
526 MI_SET_PROCESS2("Kernel WS List");
527 PageFrameIndex = MiRemoveAnyPage(0);
528 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
529
530 /* Map the working set list */
531 PointerPte = MiAddressToPte(MmWorkingSetList);
532 MI_WRITE_VALID_PTE(PointerPte, TempPte);
533
534 /* Zero it out, and save the frame index */
535 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
536 PsGetCurrentProcess()->WorkingSetPage = PageFrameIndex;
537
538 /* Check for Pentium LOCK errata */
539 if (KiI386PentiumLockErrataPresent)
540 {
541 /* Mark the 1st IDT page as Write-Through to prevent a lockup
542 on a F00F instruction.
543 See http://www.rcollins.org/Errata/Dec97/F00FBug.html */
544 PointerPte = MiAddressToPte(KeGetPcr()->IDT);
545 PointerPte->u.Hard.WriteThrough = 1;
546 }
547
548 /* Release the lock */
549 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
550
551 /* Initialize the bogus address space */
552 Flags = 0;
553 MmInitializeProcessAddressSpace(PsGetCurrentProcess(), NULL, NULL, &Flags, NULL);
554
555 /* Make sure the color lists are valid */
556 ASSERT(MmFreePagesByColor[0] < (PMMCOLOR_TABLES)PTE_BASE);
557 StartPde = MiAddressToPde(MmFreePagesByColor[0]);
558 ASSERT(StartPde->u.Hard.Valid == 1);
559 PointerPte = MiAddressToPte(MmFreePagesByColor[0]);
560 ASSERT(PointerPte->u.Hard.Valid == 1);
561 LastPte = MiAddressToPte((ULONG_PTR)&MmFreePagesByColor[1][MmSecondaryColors] - 1);
562 ASSERT(LastPte->u.Hard.Valid == 1);
563
564 /* Loop the color list PTEs */
565 while (PointerPte <= LastPte)
566 {
567 /* Get the PFN entry */
568 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
569 if (!Pfn1->u3.e2.ReferenceCount)
570 {
571 /* Fill it out */
572 Pfn1->u4.PteFrame = PFN_FROM_PTE(StartPde);
573 Pfn1->PteAddress = PointerPte;
574 Pfn1->u2.ShareCount++;
575 Pfn1->u3.e2.ReferenceCount = 1;
576 Pfn1->u3.e1.PageLocation = ActiveAndValid;
577 Pfn1->u3.e1.CacheAttribute = MiCached;
578 }
579
580 /* Keep going */
581 PointerPte++;
582 }
583
584 /* All done */
585 return STATUS_SUCCESS;
586 }
587
588 /* EOF */