Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1288 lines
30 KiB

  1. /*++
  2. Copyright (c) 1991-1999 Microsoft Corporation
  3. Module Name:
  4. ntsetup.c
  5. Abstract:
  6. This module is the tail-end of the osloader program. It performs all
  7. x86-specific allocations and setups for ntoskrnl. osloader.c calls
  8. this module immediately before branching into the loaded kernel image.
  9. Author:
  10. John Vert (jvert) 20-Jun-1991
  11. Environment:
  12. Revision History:
  13. --*/
  14. #include "bootx86.h"
  15. #ifdef ARCI386
  16. #include "stdio.h"
  17. #include "string.h"
  18. #include "stdlib.h"
  19. CHAR OutputBuffer[256];
  20. char BreakInKey;
  21. ULONG Count;
  22. #endif
  23. extern PHARDWARE_PTE HalPT;
  24. extern PHARDWARE_PTE PDE;
  25. extern ULONG_PTR BlHeapFree;
  26. extern ULONG PcrBasePage;
  27. extern ULONG TssBasePage;
  28. #define PDI_SHIFT_X86PAE 21
  29. //
  30. // PaeEnabled is set to TRUE when we actually transition to PAE mode.
  31. //
  32. BOOLEAN PaeEnabled = FALSE;
  33. //
  34. // PDPT is a pointer to the Page Directory Pointer Table, used to support
  35. // PAE mode.
  36. //
  37. PHARDWARE_PTE_X86PAE PDPT = NULL;
  38. //
  39. // We need a block of memory to split the free heap that we can allocate before
  40. // we begin cleanup
  41. //
  42. PMEMORY_ALLOCATION_DESCRIPTOR SplitDescriptor;
  43. //
  44. // So we know where to unmap to
  45. //
  46. extern ULONG HighestPde;
  47. //
  48. // Private function prototypes
  49. //
  50. VOID
  51. NSFixProcessorContext(
  52. IN ULONG PCR,
  53. IN ULONG TSS
  54. );
  55. VOID
  56. NSDumpMemoryDescriptors(
  57. IN PLIST_ENTRY ListHead
  58. );
  59. VOID
  60. NSUnmapFreeDescriptors(
  61. IN PLIST_ENTRY ListHead
  62. );
  63. VOID
  64. NSDumpMemory(
  65. PVOID Start,
  66. ULONG Length
  67. );
  68. VOID
  69. NSFixMappings(
  70. IN PLIST_ENTRY ListHead
  71. );
  72. ARC_STATUS
  73. BlpAllocatePAETables(
  74. VOID
  75. );
  76. PHARDWARE_PTE_X86PAE
  77. BlpFindPAEPageDirectoryEntry(
  78. IN ULONG Va
  79. );
  80. PHARDWARE_PTE_X86PAE
  81. BlpFindPAEPageTableEntry(
  82. IN ULONG Va
  83. );
  84. VOID
  85. BlpInitializePAETables(
  86. VOID
  87. );
  88. VOID
  89. BlpEnablePAE(
  90. IN ULONG PaePhysicalAddress
  91. );
  92. VOID
  93. BlpTruncateDescriptors (
  94. IN ULONG HighestPage
  95. );
  96. ARC_STATUS
  97. BlSetupForNt(
  98. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  99. )
  100. /*++
  101. Routine Description:
  102. Called by osloader to handle any processor-dependent allocations or
  103. setups.
  104. Arguments:
  105. BlLoaderBlock - Pointer to the parameters which will be passed to
  106. ntoskrnl
  107. EntryPoint - Supplies the entry point for ntoskrnl.exe
  108. Return Value:
  109. ESUCCESS - All setup succesfully completed.
  110. --*/
  111. {
  112. ARC_STATUS Status = ESUCCESS;
  113. static ULONG PCR;
  114. static ULONG TSS;
  115. ULONG i;
  116. HARDWARE_PTE_X86 nullpte;
  117. //
  118. // First clean up the display, meaning that any messages displayed after
  119. // this point cannot be DBCS. Unfortunately there are a couple of messages
  120. // that can be displayed in certain error paths from this point out but
  121. // fortunately they are extremely rare.
  122. //
  123. // Note that TextGrTerminate goes into real mode to do some of its work
  124. // so we really really have to call it here (see comment at bottom of
  125. // this routine about real mode).
  126. //
  127. TextGrTerminate();
  128. BlLoaderBlock->u.I386.CommonDataArea = NULL;
  129. BlLoaderBlock->u.I386.MachineType = MachineType;
  130. PCR = PcrBasePage;
  131. if (PCR == 0 || PCR >= _16MB) {
  132. BlPrint("Couldn't allocate PCR descriptor in NtProcessStartup,BlSetupForNt is failing\n");
  133. return(ENOMEM);
  134. }
  135. //
  136. // Mapped hardcoded virtual pointer to the boot processors PCR
  137. // The virtual pointer comes from the HAL reserved area
  138. //
  139. // First zero out any PTEs that may have already been mapped for
  140. // a SCSI card.
  141. //
  142. RtlZeroMemory(HalPT, PAGE_SIZE);
  143. _asm {
  144. mov eax, cr3
  145. mov cr3, eax
  146. }
  147. HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> PAGE_SHIFT].PageFrameNumber = PCR + 1;
  148. HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> PAGE_SHIFT].Valid = 1;
  149. HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> PAGE_SHIFT].Write = 1;
  150. RtlZeroMemory((PVOID)KI_USER_SHARED_DATA, PAGE_SIZE);
  151. HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> PAGE_SHIFT].PageFrameNumber = PCR;
  152. HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> PAGE_SHIFT].Valid = 1;
  153. HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> PAGE_SHIFT].Write = 1;
  154. PCR = KIP0PCRADDRESS;
  155. if (BlUsePae != FALSE) {
  156. //
  157. // Allocate the new PAE mapping structures
  158. //
  159. Status = BlpAllocatePAETables();
  160. if (Status != ESUCCESS) {
  161. goto SetupFailed;
  162. }
  163. } else {
  164. //
  165. // If we are not booting in PAE mode then truncate any memory
  166. // above 4G. The parameter to BlpTruncateDescriptors() is expressed
  167. // in pages, and is the highest page that will be included after
  168. // the truncation.
  169. //
  170. BlpTruncateDescriptors( 1024 * 1024 - 1 );
  171. }
  172. //
  173. // use our pre-allocated space for Tss.
  174. //
  175. TSS = TssBasePage;
  176. if (TSS == 0 || TSS >= _16MB) {
  177. BlPrint("Couldn't allocate valid TSS descriptor in NtProcessStartup, BlSetupForNt is failing\n");
  178. return(ENOMEM);
  179. }
  180. TSS = (KSEG0_BASE | (TSS << PAGE_SHIFT)) + BlVirtualBias;
  181. #ifdef LOADER_DEBUG
  182. NSDumpMemoryDescriptors(&(BlLoaderBlock->MemoryDescriptorListHead));
  183. #endif
  184. //
  185. // Clean up the page directory and table entries.
  186. //
  187. RtlZeroMemory (&nullpte,sizeof (HARDWARE_PTE_X86));
  188. if (BlVirtualBias) {
  189. if (!BlOldKernel) {
  190. //
  191. // Blow away the 48MB from the old to the new alternate
  192. //
  193. i= OLD_ALTERNATE >> PDI_SHIFT;
  194. while (i < (ALTERNATE_BASE >> PDI_SHIFT)) {
  195. PDE[i++]= nullpte;
  196. }
  197. }
  198. } else {
  199. //
  200. // Remove both sets of 3GB mappings
  201. //
  202. i=(OLD_ALTERNATE) >> PDI_SHIFT;
  203. for (i; i < (ALTERNATE_BASE+BASE_LOADER_IMAGE) >> PDI_SHIFT; i++) {
  204. PDE[i]= nullpte;
  205. }
  206. }
  207. //
  208. // Allocate this before we unmap free descriptors, so we can grow the heap
  209. //
  210. SplitDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
  211. sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
  212. //
  213. // Do this before PAE mode.
  214. //
  215. NSUnmapFreeDescriptors(&(BlLoaderBlock->MemoryDescriptorListHead));
  216. _asm {
  217. mov eax, cr3
  218. mov cr3, eax
  219. }
  220. if (BlUsePae != FALSE) {
  221. // Copy the four byte page table mapping to the new eight byte
  222. // mapping and transition to PAE mode.
  223. //
  224. BlpInitializePAETables();
  225. BlpEnablePAE( (ULONG)PDPT );
  226. //
  227. // We are now in PAE mode. The debugger looks at PaeEnabled in order
  228. // to correctly interpret page table entries, update that now.
  229. //
  230. PaeEnabled = TRUE;
  231. }
  232. //
  233. // N. B. DO NOT GO BACK INTO REAL MODE AFTER REMAPPING THE GDT AND
  234. // IDT TO HIGH MEMORY!! If you do, they will get re-mapped
  235. // back into low-memory, then UN-mapped by MmInit, and you
  236. // will be completely tubed!
  237. //
  238. NSFixProcessorContext(PCR, TSS);
  239. NSFixMappings(&(BlLoaderBlock->MemoryDescriptorListHead));
  240. BlLoaderBlock->Extension->LoaderPagesSpanned=BlHighestPage+1;
  241. if (BlVirtualBias) {
  242. // BlLoaderBlock->Extension->LoaderPagesSpanned=(BASE_LOADER_IMAGE >> PAGE_SHIFT) - BlLowestPage;
  243. //
  244. // gubgub once we can relocate the GDT/IDT use the computation
  245. //
  246. BlLoaderBlock->Extension->LoaderPagesSpanned=(BASE_LOADER_IMAGE >> PAGE_SHIFT);
  247. if (!BlOldKernel) {
  248. BlVirtualBias += ((BlLowestPage) << PAGE_SHIFT);
  249. }
  250. }
  251. BlLoaderBlock->u.I386.VirtualBias = BlVirtualBias;
  252. //
  253. // If the system has not been biased into upper memory to allow 3gb of
  254. // user address space, then clear the ALTERNATE_BASE PDEs.
  255. //
  256. SetupFailed:
  257. return Status;
  258. }
  259. VOID
  260. NSFixProcessorContext(
  261. IN ULONG PCR,
  262. IN ULONG TSS
  263. )
  264. /*++
  265. Routine Description:
  266. This relocates the GDT, IDT, PCR, and TSS to high virtual memory space.
  267. Arguments:
  268. PCR - Pointer to the PCR's location (in high virtual memory)
  269. TSS - Pointer to kernel's TSS (in high virtual memory)
  270. Return Value:
  271. None.
  272. --*/
  273. {
  274. #pragma pack(2)
  275. static struct {
  276. USHORT Limit;
  277. ULONG Base;
  278. } GdtDef,IdtDef;
  279. #pragma pack(4)
  280. PKGDTENTRY pGdt;
  281. ULONG Bias = 0;
  282. if (BlVirtualBias != 0 ) {
  283. Bias = BlVirtualBias;
  284. }
  285. //
  286. // Kernel expects the PCR to be zero-filled on startup
  287. //
  288. RtlZeroMemory((PVOID)PCR, PAGE_SIZE);
  289. _asm {
  290. sgdt GdtDef;
  291. sidt IdtDef;
  292. }
  293. GdtDef.Base = (KSEG0_BASE | GdtDef.Base) + Bias;
  294. IdtDef.Base = (KSEG0_BASE | IdtDef.Base) + Bias;
  295. pGdt = (PKGDTENTRY)GdtDef.Base;
  296. //
  297. // Initialize selector that points to PCR
  298. //
  299. pGdt[6].BaseLow = (USHORT)(PCR & 0xffff);
  300. pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((PCR >> 16) & 0xff);
  301. pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((PCR >> 24) & 0xff);
  302. //
  303. // Initialize selector that points to TSS
  304. //
  305. pGdt[5].BaseLow = (USHORT)(TSS & 0xffff);
  306. pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((TSS >> 16) & 0xff);
  307. pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((TSS >> 24) & 0xff);
  308. _asm {
  309. lgdt GdtDef;
  310. lidt IdtDef;
  311. }
  312. }
  313. VOID
  314. NSUnmapFreeDescriptors(
  315. IN PLIST_ENTRY ListHead
  316. )
  317. /*++
  318. Routine Description:
  319. Unmaps memory which is marked as free, so it memory management will know
  320. to reclaim it.
  321. Arguments:
  322. ListHead - pointer to the start of the MemoryDescriptorList
  323. Return Value:
  324. None.
  325. --*/
  326. {
  327. PMEMORY_ALLOCATION_DESCRIPTOR CurrentDescriptor;
  328. PLIST_ENTRY CurrentLink;
  329. ULONG EndPage;
  330. ULONG FrameNumber;
  331. PHARDWARE_PTE PageTable;
  332. ULONG StartPage;
  333. ULONG PageVa;
  334. ULONG i,stoppde,Limit;
  335. HARDWARE_PTE_X86 nullpte;
  336. Limit = 0x1000000 >> PAGE_SHIFT;
  337. if (BlOldKernel) {
  338. BlpRemapReserve();
  339. } else {
  340. if (Limit < BlHighestPage) {
  341. Limit = BlHighestPage;
  342. }
  343. }
  344. CurrentLink = ListHead->Flink;
  345. while (CurrentLink != ListHead) {
  346. CurrentDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)CurrentLink;
  347. #if 0
  348. #define UNINIT_FILL 0x12345678
  349. //
  350. // Fill unused memory with a bogus pattern to catch problems where kernel code
  351. // expects uninitalized memory to be zero.
  352. //
  353. if ((CurrentDescriptor->MemoryType == LoaderFree) ||
  354. (CurrentDescriptor->MemoryType == LoaderReserve)) {
  355. if (CurrentDescriptor->BasePage + CurrentDescriptor->PageCount < Limit) {
  356. //
  357. // This descriptor should already be mapped, just fill it
  358. //
  359. RtlFillMemoryUlong((PVOID)((CurrentDescriptor->BasePage << PAGE_SHIFT) | KSEG0_BASE),
  360. CurrentDescriptor->PageCount << PAGE_SHIFT,
  361. UNINIT_FILL);
  362. } else {
  363. //
  364. // This descriptor is not mapped. Use the first HAL page table to map and fill each page
  365. //
  366. for (StartPage = CurrentDescriptor->BasePage;
  367. StartPage < CurrentDescriptor->BasePage + CurrentDescriptor->PageCount;
  368. StartPage++) {
  369. HalPT[0].PageFrameNumber = StartPage;
  370. HalPT[0].Valid = 1;
  371. HalPT[0].Write = 1;
  372. _asm {
  373. mov eax, cr3
  374. mov cr3, eax
  375. }
  376. RtlFillMemory((PVOID)0xFFC00000,PAGE_SIZE,UNINIT_FILL);
  377. }
  378. HalPT[0].PageFrameNumber = 0;
  379. HalPT[0].Valid = 0;
  380. HalPT[0].Write = 0;
  381. _asm {
  382. mov eax, cr3
  383. mov cr3, eax
  384. }
  385. }
  386. }
  387. #endif
  388. if ( (CurrentDescriptor->MemoryType == LoaderFree) ||
  389. (((CurrentDescriptor->MemoryType == LoaderFirmwareTemporary) ||
  390. (CurrentDescriptor->MemoryType == LoaderReserve)) &&
  391. (CurrentDescriptor->BasePage < Limit)) ||
  392. (CurrentDescriptor->MemoryType == LoaderLoadedProgram) ||
  393. (CurrentDescriptor->MemoryType == LoaderOsloaderStack)) {
  394. StartPage = CurrentDescriptor->BasePage | (KSEG0_BASE >> PAGE_SHIFT);
  395. EndPage = CurrentDescriptor->BasePage + CurrentDescriptor->PageCount;
  396. if (EndPage > Limit) {
  397. EndPage = Limit;
  398. }
  399. EndPage |= (KSEG0_BASE >> PAGE_SHIFT);
  400. while(StartPage < EndPage) {
  401. if (PDE[StartPage >> 10].Valid != 0) {
  402. FrameNumber = PDE[StartPage >> 10].PageFrameNumber;
  403. PageTable= (PHARDWARE_PTE)(KSEG0_BASE | (FrameNumber << PAGE_SHIFT));
  404. ((PULONG)(PageTable))[StartPage & 0x3ff] = 0;
  405. }
  406. StartPage++;
  407. }
  408. }
  409. CurrentLink = CurrentLink->Flink;
  410. }
  411. if (BlOldKernel) {
  412. return;
  413. }
  414. //
  415. // Unmap the PDEs too if running on a new mm
  416. //
  417. RtlZeroMemory (&nullpte,sizeof (HARDWARE_PTE_X86));
  418. for (i=(BlHighestPage >> 10)+1;i <= HighestPde;i++){
  419. PDE[i]=nullpte;
  420. PDE[i+(KSEG0_BASE >> PDI_SHIFT)]=nullpte;
  421. if (BlVirtualBias) {
  422. PDE[i + ((KSEG0_BASE+BlVirtualBias) >> PDI_SHIFT)] = nullpte;
  423. }
  424. }
  425. if (BlVirtualBias) {
  426. //
  427. //BlHighest page here is the address of the LOWEST page used, so put the
  428. //subtraction in the loader block and use the value for the base of the bias
  429. //
  430. i = ((BlVirtualBias|KSEG0_BASE)>> PDI_SHIFT)+1;
  431. stoppde = (((BlVirtualBias|KSEG0_BASE) -
  432. (BASE_LOADER_IMAGE-(BlLowestPage << PAGE_SHIFT)) ) >> PDI_SHIFT)-1;
  433. while (i < stoppde){
  434. PDE[i++]=nullpte;
  435. }
  436. }
  437. }
  438. /*++
  439. Routine Description:
  440. Fixup the mappings to be consistent.
  441. We need to have one at address 0 (For the valid PDE entries)
  442. One at KSEG0 for standard loads
  443. One at either ALTERNATE_BASE or OLD_ALTERNATE for /3gb systems on a
  444. post 5.0 or 5.0 and prior respectively
  445. Arguments:
  446. None
  447. Return Value:
  448. None.
  449. --*/
  450. VOID
  451. NSFixMappings(
  452. IN PLIST_ENTRY ListHead
  453. )
  454. {
  455. ULONG Index,Index2;
  456. ULONG Limit;
  457. ULONG Count;
  458. PHARDWARE_PTE_X86PAE PdePae,PdePae2;
  459. PMEMORY_ALLOCATION_DESCRIPTOR CurrentDescriptor;
  460. PLIST_ENTRY CurrentLink;
  461. ULONG StartPage,Bias=0,FreePage,FreeCount,OldFree;
  462. //
  463. // Finally, go through and mark all large OsloaderHeap blocks
  464. // as firmware temporary, so that MM reclaims them in phase 0
  465. // (for /3gb) EXCEPT the LoaderBlock.
  466. //
  467. CurrentLink = ListHead->Flink;
  468. if (BlVirtualBias) {
  469. Bias = BlVirtualBias >> PAGE_SHIFT;
  470. }
  471. FreePage = (BlHeapFree & ~KSEG0_BASE) >> PAGE_SHIFT;
  472. while (CurrentLink != ListHead) {
  473. CurrentDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)CurrentLink;
  474. StartPage = CurrentDescriptor->BasePage | (KSEG0_BASE >> PAGE_SHIFT) ;
  475. StartPage += Bias;
  476. //
  477. // BlHeapFree is not Biased, it relies on the 2GB mapping.
  478. //
  479. if ( CurrentDescriptor->MemoryType == LoaderOsloaderHeap) {
  480. if ((CurrentDescriptor->BasePage <= FreePage) &&
  481. ((CurrentDescriptor->BasePage + CurrentDescriptor->PageCount) > FreePage + 1)) {
  482. FreeCount = CurrentDescriptor->PageCount;
  483. CurrentDescriptor->PageCount = FreePage-CurrentDescriptor->BasePage+1;
  484. SplitDescriptor->MemoryType= LoaderFirmwareTemporary;
  485. SplitDescriptor->BasePage = FreePage+1;
  486. SplitDescriptor->PageCount = FreeCount-CurrentDescriptor->PageCount;
  487. BlInsertDescriptor(SplitDescriptor);
  488. }
  489. if (PaeEnabled) {
  490. PdePae = BlpFindPAEPageDirectoryEntry( StartPage << PAGE_SHIFT);
  491. if (PdePae->Valid == 0) {
  492. CurrentDescriptor->MemoryType = LoaderFirmwareTemporary;
  493. }
  494. }else {
  495. if (PDE[StartPage >> 10].Valid == 0 ) {
  496. CurrentDescriptor->MemoryType = LoaderFirmwareTemporary;
  497. }
  498. }
  499. }
  500. if ( (CurrentDescriptor->MemoryType == LoaderReserve)) {
  501. CurrentDescriptor->MemoryType = LoaderFree;
  502. }
  503. CurrentLink = CurrentLink->Flink;
  504. }
  505. _asm {
  506. mov eax, cr3
  507. mov cr3, eax
  508. }
  509. }
  510. //
  511. // Temp. for debugging
  512. //
  513. VOID
  514. NSDumpMemory(
  515. PVOID Start,
  516. ULONG Length
  517. )
  518. {
  519. ULONG cnt;
  520. BlPrint(" %lx:\n",(ULONG)Start);
  521. for (cnt=0; cnt<Length; cnt++) {
  522. BlPrint("%x ",*((PUSHORT)(Start)+cnt));
  523. if (((cnt+1)%16)==0) {
  524. BlPrint("\n");
  525. }
  526. }
  527. }
  528. VOID
  529. NSDumpMemoryDescriptors(
  530. IN PLIST_ENTRY ListHead
  531. )
  532. /*++
  533. Routine Description:
  534. Dumps a memory descriptor list to the screen. Used for debugging only.
  535. Arguments:
  536. ListHead - Pointer to the head of the memory descriptor list
  537. Return Value:
  538. None.
  539. --*/
  540. {
  541. PLIST_ENTRY CurrentLink;
  542. PMEMORY_ALLOCATION_DESCRIPTOR CurrentDescriptor;
  543. CurrentLink = ListHead->Flink;
  544. while (CurrentLink != ListHead) {
  545. CurrentDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)CurrentLink;
  546. BlPrint("Fl = %lx Bl = %lx ",
  547. (ULONG)CurrentDescriptor->ListEntry.Flink,
  548. (ULONG)CurrentDescriptor->ListEntry.Blink
  549. );
  550. BlPrint("Type %x Base %lx Pages %lx\n",
  551. (USHORT)(CurrentDescriptor->MemoryType),
  552. CurrentDescriptor->BasePage,
  553. CurrentDescriptor->PageCount
  554. );
  555. CurrentLink = CurrentLink->Flink;
  556. }
  557. while (!GET_KEY()) { // DEBUG ONLY!
  558. }
  559. }
  560. ULONG
  561. BlpCountPAEPagesToMapX86Page(
  562. PHARDWARE_PTE_X86 PageTable
  563. )
  564. /*++
  565. Routine Description:
  566. Called to prepare the conversion of 4-byte PTEs to 8-byte PAE PTEs, this
  567. routine returns the number of 8-byte page tables that will be required
  568. to map the contents of this 4-byte page table.
  569. Because an 8-byte page table has half the number of entries as a 4-byte
  570. page table, the answer will be 0, 1 or 2.
  571. Arguments:
  572. PageTable - Pointer to a 4-byte page table.
  573. Return Value:
  574. The number of 8-byte page tables required to map the contents of this
  575. 4-byte page table.
  576. --*/
  577. {
  578. PHARDWARE_PTE_X86 pageTableEntry;
  579. ULONG chunkIndex;
  580. ULONG pageTableIndex;
  581. ULONG newPageTableCount;
  582. //
  583. // PAE page tables contain fewer PTEs than regular page tables do.
  584. //
  585. // Examine the page table in chunks, where each chunk contains the PTEs
  586. // that represent an entire PAE page table.
  587. //
  588. newPageTableCount = 0;
  589. for (chunkIndex = 0;
  590. chunkIndex < PTE_PER_PAGE_X86;
  591. chunkIndex += PTE_PER_PAGE_X86PAE) {
  592. for (pageTableIndex = 0;
  593. pageTableIndex < PTE_PER_PAGE_X86PAE;
  594. pageTableIndex++) {
  595. pageTableEntry = &PageTable[ chunkIndex + pageTableIndex ];
  596. if (pageTableEntry->Valid) {
  597. //
  598. // One or more PTEs are valid in this chunk, record
  599. // the fact that a new page table will be needed to map
  600. // them and skip to the next chunk.
  601. //
  602. newPageTableCount++;
  603. break;
  604. }
  605. }
  606. }
  607. return newPageTableCount;
  608. }
  609. VOID
  610. BlpCopyX86PteToPAEPte(
  611. IN PHARDWARE_PTE_X86 OldPte,
  612. OUT PHARDWARE_PTE_X86PAE NewPte
  613. )
  614. /*++
  615. Routine Description:
  616. Copies the contents of a 4-byte PTE to an 8-byte PTE, with the exception
  617. of the PageFrameNumber field.
  618. Arguments:
  619. OldPte - Pointer to the source 4-byte PTE.
  620. NewPte - Pointer to the destination 8-byte PTE.
  621. Return Value:
  622. None.
  623. --*/
  624. {
  625. NewPte->Valid = OldPte->Valid;
  626. NewPte->Write = OldPte->Write;
  627. NewPte->Owner = OldPte->Owner;
  628. NewPte->WriteThrough = OldPte->WriteThrough;
  629. NewPte->CacheDisable = OldPte->CacheDisable;
  630. NewPte->Accessed = OldPte->Accessed;
  631. NewPte->Dirty = OldPte->Dirty;
  632. NewPte->LargePage = OldPte->LargePage;
  633. NewPte->Global = OldPte->Global;
  634. }
  635. PHARDWARE_PTE_X86PAE
  636. BlpFindPAEPageDirectoryEntry(
  637. IN ULONG Va
  638. )
  639. /*++
  640. Routine Description:
  641. Given a virtual address, locates and returns a pointer to the appropriate
  642. 8-byte Page Directory Entry.
  643. Arguments:
  644. Va - Virtual Address for which a PDE pointer is desired.
  645. Return Value:
  646. Pointer to the page directory entry for the supplied Va.
  647. --*/
  648. {
  649. PHARDWARE_PTE_X86PAE directoryPointerTableEntry;
  650. PHARDWARE_PTE_X86PAE pageDirectoryEntry;
  651. PHARDWARE_PTE_X86PAE pageDirectory;
  652. ULONG pageDirectoryIndex;
  653. ULONG directoryPointerTableIndex;
  654. //
  655. // Get a pointer to the directory pointer table entry
  656. //
  657. directoryPointerTableIndex = PP_INDEX_PAE( Va );
  658. directoryPointerTableEntry = &PDPT[ directoryPointerTableIndex ];
  659. //
  660. // Get a pointer to the page directory entry
  661. //
  662. pageDirectory = PAGE_FRAME_FROM_PTE( directoryPointerTableEntry );
  663. pageDirectoryIndex = PD_INDEX_PAE( Va );
  664. pageDirectoryEntry = &pageDirectory[ pageDirectoryIndex ];
  665. return pageDirectoryEntry;
  666. }
  667. PHARDWARE_PTE_X86PAE
  668. BlpFindPAEPageTableEntry(
  669. IN ULONG Va
  670. )
  671. /*++
  672. Routine Description:
  673. Given a virtual address, locates and returns a pointer to the appropriate
  674. 8-byte Page Table Entry.
  675. Arguments:
  676. Va - Virtual Address for which a PTE pointer is desired.
  677. Return Value:
  678. Pointer to the page directory entry for the supplied Va.
  679. --*/
  680. {
  681. PHARDWARE_PTE_X86PAE pageDirectoryEntry;
  682. PHARDWARE_PTE_X86PAE pageTableEntry;
  683. PHARDWARE_PTE_X86PAE pageTable;
  684. ULONG pageTableIndex;
  685. //
  686. // Get a pointer to the page directory entry
  687. //
  688. pageDirectoryEntry = BlpFindPAEPageDirectoryEntry( Va );
  689. ASSERT( pageDirectoryEntry->Valid != 0 );
  690. //
  691. // Get a pointer to the page table entry
  692. //
  693. pageTable = PAGE_FRAME_FROM_PTE( pageDirectoryEntry );
  694. pageTableIndex = PT_INDEX_PAE( Va );
  695. pageTableEntry = &pageTable[ pageTableIndex ];
  696. return pageTableEntry;
  697. }
  698. VOID
  699. BlpMapAddress(
  700. IN ULONG Va,
  701. IN PHARDWARE_PTE_X86 OldPageDirectoryEntry,
  702. IN PHARDWARE_PTE_X86 OldPageTableEntry,
  703. IN OUT PULONG NextFreePage
  704. )
  705. /*++
  706. Routine Description:
  707. Worker function used during the conversion of a two-level, 4-byte mapping
  708. structure to the three-level, 8-byte mapping structure required for PAE
  709. mode.
  710. Maps VA to the physical address referenced by OldPageTableEntry, allocating
  711. a new page table if necessary.
  712. Arguments:
  713. Va - Virtual Address for this mapping.
  714. OldPageDirectoryEntry - Pointer to the existing, 4-byte PDE.
  715. OldPageTableEntry - Pointer to the existing, 4-byte PTE.
  716. NextFreePage - Pointer to the physical page number of the next free
  717. page in our private page pool.
  718. Return Value:
  719. None.
  720. --*/
  721. {
  722. PHARDWARE_PTE_X86PAE pageDirectoryEntry;
  723. PHARDWARE_PTE_X86PAE directoryPointerTableEntry;
  724. PHARDWARE_PTE_X86PAE pageTable;
  725. PHARDWARE_PTE_X86PAE pageTableEntry;
  726. ULONG pageFrameNumber;
  727. ULONG directoryPointerTableIndex;
  728. ULONG pageTableVa;
  729. //
  730. // Ignore recursive mappings that exist in the old page table
  731. // structure, we set those up as we go.
  732. //
  733. if ((Va >= PTE_BASE) && (Va < (PDE_BASE_X86 + PAGE_SIZE))) {
  734. return;
  735. }
  736. //
  737. // Get a pointer to the page directory entry
  738. //
  739. pageDirectoryEntry = BlpFindPAEPageDirectoryEntry( Va );
  740. //
  741. // If the page table for this PTE isn't present yet, allocate one and
  742. // copy over the old page directory attributes.
  743. //
  744. if (pageDirectoryEntry->Valid == 0) {
  745. pageFrameNumber = *NextFreePage;
  746. *NextFreePage += 1;
  747. BlpCopyX86PteToPAEPte( OldPageDirectoryEntry, pageDirectoryEntry );
  748. pageDirectoryEntry->PageFrameNumber = pageFrameNumber;
  749. //
  750. // Check the recursive mapping for this page table
  751. //
  752. pageTableVa = PTE_BASE +
  753. (Va / PAGE_SIZE) * sizeof(HARDWARE_PTE_X86PAE);
  754. pageTableEntry = BlpFindPAEPageTableEntry( pageTableVa );
  755. if (pageTableEntry->Valid == 0) {
  756. DbgBreakPoint();
  757. }
  758. if (pageTableEntry->PageFrameNumber != pageFrameNumber) {
  759. DbgBreakPoint();
  760. }
  761. }
  762. //
  763. // Get a pointer to the page table entry
  764. //
  765. pageTableEntry = BlpFindPAEPageTableEntry( Va );
  766. if (pageTableEntry->Valid != 0) {
  767. DbgBreakPoint();
  768. }
  769. //
  770. // Propogate the PTE page and attributes.
  771. //
  772. BlpCopyX86PteToPAEPte( OldPageTableEntry, pageTableEntry );
  773. pageTableEntry->PageFrameNumber = OldPageTableEntry->PageFrameNumber;
  774. }
  775. VOID
  776. BlpInitializePAETables(
  777. VOID
  778. )
  779. /*++
  780. Routine Description:
  781. Allocates a new, three-level, 8-byte PTE mapping structure and duplicates
  782. in it the mapping described by the existing 4-byte PTE mapping structure.
  783. Arguments:
  784. None.
  785. Return Value:
  786. None.
  787. --*/
  788. {
  789. PHARDWARE_PTE_X86 pageDirectory;
  790. ULONG pageDirectoryIndex;
  791. ULONG va;
  792. ULONG physAddress;
  793. PHARDWARE_PTE_X86 pageDirectoryEntry;
  794. PHARDWARE_PTE_X86 pageTableEntry;
  795. PHARDWARE_PTE_X86 pageTable;
  796. PHARDWARE_PTE_X86PAE paeDirectoryEntry;
  797. PHARDWARE_PTE_X86PAE paeTableEntry;
  798. ULONG directoryPointerIndex;
  799. ULONG nextFreePage;
  800. ULONG i;
  801. ULONG pageTableIndex;
  802. ULONG pageDirectoryVa;
  803. ULONG pageTableVa;
  804. ULONGLONG pageFrameNumber;
  805. nextFreePage = ((ULONG)PDPT) >> PAGE_SHIFT;
  806. //
  807. // Initialize the page directory pointer table to reference the four
  808. // page directories.
  809. //
  810. nextFreePage++;
  811. for (i = 0; i < 4; i++) {
  812. PDPT[i].PageFrameNumber = nextFreePage;
  813. PDPT[i].Valid = 1;
  814. nextFreePage++;
  815. }
  816. //
  817. // Set up the recursive mapping: first the PDE.
  818. //
  819. directoryPointerIndex = PDE_BASE_X86PAE >> PPI_SHIFT_X86PAE;
  820. pageFrameNumber = PDPT[ directoryPointerIndex ].PageFrameNumber;
  821. paeDirectoryEntry = (PHARDWARE_PTE_X86PAE)(pageFrameNumber << PAGE_SHIFT);
  822. for (i = 0; i < 4; i++) {
  823. paeDirectoryEntry->PageFrameNumber = PDPT[i].PageFrameNumber;
  824. paeDirectoryEntry->Valid = 1;
  825. paeDirectoryEntry->Write = 1;
  826. paeDirectoryEntry++;
  827. }
  828. for (pageDirectoryIndex = 0;
  829. pageDirectoryIndex < PTE_PER_PAGE_X86;
  830. pageDirectoryIndex++) {
  831. pageDirectoryEntry = &PDE[pageDirectoryIndex];
  832. if (pageDirectoryEntry->Valid == 0) {
  833. continue;
  834. }
  835. pageTable = PAGE_FRAME_FROM_PTE( pageDirectoryEntry );
  836. for (pageTableIndex = 0;
  837. pageTableIndex < PTE_PER_PAGE_X86;
  838. pageTableIndex++) {
  839. pageTableEntry = &pageTable[pageTableIndex];
  840. if (pageTableEntry->Valid == 0) {
  841. continue;
  842. }
  843. va = (pageDirectoryIndex << PDI_SHIFT_X86) +
  844. (pageTableIndex << PTI_SHIFT);
  845. //
  846. // We have a physical address and a va, update the new mapping.
  847. //
  848. BlpMapAddress( va,
  849. pageDirectoryEntry,
  850. pageTableEntry,
  851. &nextFreePage );
  852. }
  853. }
  854. //
  855. // Finally, set up the PDE for the second of two HAL common buffer page
  856. // tables.
  857. //
  858. paeDirectoryEntry =
  859. BlpFindPAEPageDirectoryEntry( 0xFFC00000 + (1 << PDI_SHIFT_X86PAE) );
  860. paeDirectoryEntry->Valid = 1;
  861. paeDirectoryEntry->Write = 1;
  862. paeDirectoryEntry->PageFrameNumber = nextFreePage;
  863. nextFreePage += 1;
  864. }
  865. ARC_STATUS
  866. BlpAllocatePAETables(
  867. VOID
  868. )
  869. /*++
  870. Routine Description:
  871. Calculates the number of pages required to contain an 8-byte mapping
  872. structure to duplicate the existing 4-byte mapping structure.
  873. Arguments:
  874. None.
  875. Return Value:
  876. None.
  877. --*/
  878. {
  879. ULONG cr3;
  880. ULONG pageTableBlockSize;
  881. ULONG pageDirectoryIndex;
  882. ULONG pageTableIndex;
  883. ULONG oldPageTableCount;
  884. PHARDWARE_PTE_X86 pageDirectoryEntry;
  885. PHARDWARE_PTE_X86 pageTable;
  886. PHARDWARE_PTE_X86 pageTableEntry;
  887. PHARDWARE_PTE_X86PAE pageDirectoryPointerTable;
  888. ULONG chunkIndex;
  889. ULONG status;
  890. ULONG pageBase;
  891. ULONG newPageTableCount;
  892. ULONG allocationSize;
  893. PVOID blockPtr;
  894. //
  895. // Find out how many page tables we are going to need by examining the
  896. // existing page table entries.
  897. //
  898. newPageTableCount = 0;
  899. for (pageDirectoryIndex = 0;
  900. pageDirectoryIndex < PTE_PER_PAGE_X86;
  901. pageDirectoryIndex++) {
  902. pageDirectoryEntry = &PDE[pageDirectoryIndex];
  903. if (pageDirectoryEntry->Valid != 0) {
  904. pageTable = PAGE_FRAME_FROM_PTE( pageDirectoryEntry );
  905. //
  906. // For each valid page table, scan the PTEs in chunks, where
  907. // a chunk represents the PTEs that will reside in a PAE page
  908. // table.
  909. //
  910. newPageTableCount += BlpCountPAEPagesToMapX86Page( pageTable );
  911. }
  912. }
  913. //
  914. // Include a page for the second HAL page table. This won't get
  915. // included automatically in the conversion count because it doesn't
  916. // currently contain any valid page table entries.
  917. //
  918. newPageTableCount += 1;
  919. //
  920. // Include a page for each of four page directories and the page
  921. // directory pointer table, then allocate the pages.
  922. //
  923. newPageTableCount += 5;
  924. status = BlAllocateDescriptor( LoaderMemoryData,
  925. 0,
  926. newPageTableCount,
  927. &pageBase );
  928. if (status != ESUCCESS) {
  929. DbgPrint("BlAllocateDescriptor failed!\n");
  930. return status;
  931. }
  932. allocationSize = newPageTableCount << PAGE_SHIFT;
  933. pageDirectoryPointerTable =
  934. (PHARDWARE_PTE_X86PAE)PAGE_TO_VIRTUAL( pageBase );
  935. RtlZeroMemory( pageDirectoryPointerTable, allocationSize );
  936. //
  937. // Set the global PDPT, we're done.
  938. //
  939. PDPT = pageDirectoryPointerTable;
  940. return status;
  941. }