Leaked source code of windows server 2003
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.

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