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.

4169 lines
99 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. amd64x86.c
  5. Abstract:
  6. This module contains routines necessary to support loading and
  7. transitioning into an AMD64 kernel. The code in this module has
  8. access to x86-specific defines found in i386.h but not to amd64-
  9. specific declarations found in amd64.h.
  10. Author:
  11. Forrest Foltz (forrestf) 20-Apr-2000
  12. Environment:
  13. Revision History:
  14. --*/
  15. #include "amd64prv.h"
  16. #include <pcmp.inc>
  17. #include <ntapic.inc>
  18. #if defined(ROUND_UP)
  19. #undef ROUND_UP
  20. #endif
  21. #include "cmp.h"
  22. #include "arc.h"
  23. #define WANT_BLDRTHNK_FUNCTIONS
  24. #define COPYBUF_MALLOC BlAllocateHeap
  25. #include <amd64thk.h>
  26. #define IMAGE_DEFINITIONS 0
  27. #include <ximagdef.h>
  28. //
  29. // Warning 4152 is "nonstandard extension, function/data pointer conversion
  30. //
  31. #pragma warning(disable:4152)
  32. //
  33. // Private, tempory memory descriptor type
  34. //
  35. #define LoaderAmd64MemoryData (LoaderMaximum + 10)
  36. //
  37. // Array of 64-bit memory descriptors
  38. //
  39. PMEMORY_ALLOCATION_DESCRIPTOR_64 BlAmd64DescriptorArray;
  40. LONG BlAmd64DescriptorArraySize;
  41. //
  42. // Forward declarations for functions local to this module
  43. //
  44. ARC_STATUS
  45. BlAmd64AllocateMemoryAllocationDescriptors(
  46. VOID
  47. );
  48. ARC_STATUS
  49. BlAmd64BuildLdrDataTableEntry64(
  50. IN PLDR_DATA_TABLE_ENTRY DataTableEntry32,
  51. OUT PLDR_DATA_TABLE_ENTRY_64 *DataTableEntry64
  52. );
  53. ARC_STATUS
  54. BlAmd64BuildLoaderBlock64(
  55. VOID
  56. );
  57. ARC_STATUS
  58. BlAmd64BuildLoaderBlockExtension64(
  59. VOID
  60. );
  61. ARC_STATUS
  62. BlAmd64BuildMappingPhase1(
  63. VOID
  64. );
  65. ARC_STATUS
  66. BlAmd64BuildMappingPhase2(
  67. VOID
  68. );
  69. ARC_STATUS
  70. BlAmd64BuildMappingWorker(
  71. VOID
  72. );
  73. BOOLEAN
  74. BlAmd64ContainsResourceList(
  75. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  76. OUT PULONG ResourceListSize64
  77. );
  78. ARC_STATUS
  79. BlAmd64FixSharedUserPage(
  80. VOID
  81. );
  82. BOOLEAN
  83. BlAmd64IsPageMapped(
  84. IN ULONG Va,
  85. OUT PFN_NUMBER *Pfn,
  86. OUT PBOOLEAN PageTableMapped
  87. );
  88. ARC_STATUS
  89. BlAmd64PrepareSystemStructures(
  90. VOID
  91. );
  92. VOID
  93. BlAmd64ReplaceMemoryDescriptorType(
  94. IN TYPE_OF_MEMORY Target,
  95. IN TYPE_OF_MEMORY Replacement,
  96. IN BOOLEAN Coallesce
  97. );
  98. VOID
  99. BlAmd64ResetPageTableHeap(
  100. VOID
  101. );
  102. VOID
  103. BlAmd64SwitchToLongMode(
  104. VOID
  105. );
  106. ARC_STATUS
  107. BlAmd64TransferArcDiskInformation(
  108. VOID
  109. );
  110. ARC_STATUS
  111. BlAmd64TransferBootDriverNodes(
  112. VOID
  113. );
  114. ARC_STATUS
  115. BlAmd64TransferConfigurationComponentData(
  116. VOID
  117. );
  118. PCONFIGURATION_COMPONENT_DATA_64
  119. BlAmd64TransferConfigWorker(
  120. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  121. IN PCONFIGURATION_COMPONENT_DATA_64 ComponentDataParent64
  122. );
  123. ARC_STATUS
  124. BlAmd64TransferHardwareIdList(
  125. IN PPNP_HARDWARE_ID HardwareId,
  126. OUT POINTER64 *HardwareIdDatabaseList64
  127. );
  128. ARC_STATUS
  129. BlAmd64TransferLoadedModuleState(
  130. VOID
  131. );
  132. ARC_STATUS
  133. BlAmd64TransferMemoryAllocationDescriptors(
  134. VOID
  135. );
  136. ARC_STATUS
  137. BlAmd64TransferNlsData(
  138. VOID
  139. );
  140. VOID
  141. BlAmd64TransferResourceList(
  142. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  143. OUT PCONFIGURATION_COMPONENT_DATA_64 ComponentData64
  144. );
  145. ARC_STATUS
  146. BlAmd64TransferSetupLoaderBlock(
  147. VOID
  148. );
  149. #if DBG
  150. PCHAR BlAmd64MemoryDescriptorText[] = {
  151. "LoaderExceptionBlock",
  152. "LoaderSystemBlock",
  153. "LoaderFree",
  154. "LoaderBad",
  155. "LoaderLoadedProgram",
  156. "LoaderFirmwareTemporary",
  157. "LoaderFirmwarePermanent",
  158. "LoaderOsloaderHeap",
  159. "LoaderOsloaderStack",
  160. "LoaderSystemCode",
  161. "LoaderHalCode",
  162. "LoaderBootDriver",
  163. "LoaderConsoleInDriver",
  164. "LoaderConsoleOutDriver",
  165. "LoaderStartupDpcStack",
  166. "LoaderStartupKernelStack",
  167. "LoaderStartupPanicStack",
  168. "LoaderStartupPcrPage",
  169. "LoaderStartupPdrPage",
  170. "LoaderRegistryData",
  171. "LoaderMemoryData",
  172. "LoaderNlsData",
  173. "LoaderSpecialMemory",
  174. "LoaderBBTMemory",
  175. "LoaderReserve"
  176. };
  177. #endif
  178. VOID
  179. NSUnmapFreeDescriptors(
  180. IN PLIST_ENTRY ListHead
  181. );
  182. //
  183. // Data declarations
  184. //
  185. PLOADER_PARAMETER_BLOCK BlAmd64LoaderBlock32;
  186. PLOADER_PARAMETER_BLOCK_64 BlAmd64LoaderBlock64;
  187. //
  188. // Pointer to the top of the 64-bit stack frame to use upon transition
  189. // to long mode.
  190. //
  191. POINTER64 BlAmd64IdleStack64;
  192. //
  193. // GDT and IDT pseudo-descriptor for use with LGDT/LIDT
  194. //
  195. DESCRIPTOR_TABLE_DESCRIPTOR BlAmd64GdtDescriptor;
  196. DESCRIPTOR_TABLE_DESCRIPTOR BlAmd64IdtDescriptor;
  197. DESCRIPTOR_TABLE_DESCRIPTOR BlAmd32GdtDescriptor;
  198. //
  199. // 64-bit pointers to the loader parameter block and kernel
  200. // entry routine
  201. //
  202. POINTER64 BlAmd64LoaderParameterBlock;
  203. POINTER64 BlAmd64KernelEntry;
  204. //
  205. // A private list of page tables used to build the long mode paging
  206. // structures is kept. This is in order to avoid memory allocations while
  207. // the structures are being assembled.
  208. //
  209. // The PT_NODE type as well as the BlAmd64FreePfnList and BlAmd64BusyPfnList
  210. // globals are used to that end.
  211. //
  212. typedef struct _PT_NODE *PPT_NODE;
  213. typedef struct _PT_NODE {
  214. PPT_NODE Next;
  215. PAMD64_PAGE_TABLE PageTable;
  216. } PT_NODE;
  217. PPT_NODE BlAmd64FreePfnList = NULL;
  218. PPT_NODE BlAmd64BusyPfnList = NULL;
  219. //
  220. // Indicate if the system is waking up from hibernate
  221. //
  222. ULONG HiberInProgress = 0;
  223. //
  224. // External data
  225. //
  226. extern ULONG64 BlAmd64_LOCALAPIC;
  227. ARC_STATUS
  228. BlAmd64MapMemoryRegion(
  229. IN ULONG RegionVa,
  230. IN ULONG RegionSize
  231. )
  232. /*++
  233. Routine Description:
  234. This function creates long mode mappings for all valid x86 mappings
  235. within the region described by RegionVa and RegionSize.
  236. Arguments:
  237. RegionVa - Supplies the starting address of the VA region.
  238. RegionSize - Supplies the size of the VA region.
  239. Return Value:
  240. ARC_STATUS - Status of operation.
  241. --*/
  242. {
  243. ULONG va32;
  244. ULONG va32End;
  245. POINTER64 va64;
  246. ARC_STATUS status;
  247. PFN_NUMBER pfn;
  248. BOOLEAN pageMapped;
  249. BOOLEAN pageTableMapped;
  250. ULONG increment;
  251. va32 = RegionVa;
  252. va32End = va32 + RegionSize;
  253. while (va32 < va32End) {
  254. pageMapped = BlAmd64IsPageMapped( va32, &pfn, &pageTableMapped );
  255. if (pageTableMapped != FALSE) {
  256. //
  257. // The page table corresponding to this address is present.
  258. //
  259. if (pageMapped != FALSE) {
  260. //
  261. // The page corresponding to this address is present.
  262. //
  263. if ((va32 & KSEG0_BASE_X86) != 0) {
  264. //
  265. // The address lies within the X86 KSEG0 region. Map
  266. // it to the corresponding address within the AMD64
  267. // KSEG0 region.
  268. //
  269. va64 = PTR_64( (PVOID)va32 );
  270. } else {
  271. //
  272. // Map the VA directly.
  273. //
  274. va64 = (POINTER64)va32;
  275. }
  276. //
  277. // Now create the mapping in the AMD64 page table structure.
  278. //
  279. status = BlAmd64CreateMapping( va64, pfn );
  280. if (status != ESUCCESS) {
  281. return status;
  282. }
  283. }
  284. //
  285. // Check the next page.
  286. //
  287. increment = PAGE_SIZE;
  288. } else {
  289. //
  290. // Not only is the page not mapped but neither is the page table.
  291. // Skip to the next page table address boundary.
  292. //
  293. increment = 1 << PDI_SHIFT;
  294. }
  295. //
  296. // Advance to the next VA to check, checking for overflow.
  297. //
  298. va32 = (va32 + increment) & ~(increment - 1);
  299. if (va32 == 0) {
  300. break;
  301. }
  302. }
  303. return ESUCCESS;
  304. }
  305. BOOLEAN
  306. BlAmd64IsPageMapped(
  307. IN ULONG Va,
  308. OUT PFN_NUMBER *Pfn,
  309. OUT PBOOLEAN PageTableMapped
  310. )
  311. /*++
  312. Routine Description:
  313. This function accepts a 32-bit virtual address, determines whether it
  314. is a valid address, and if so returns the Pfn associated with it.
  315. Addresses that are within the recursive mapping are treated as NOT
  316. mapped.
  317. Arguments:
  318. None.
  319. Return Value:
  320. ARC_STATUS - Status of operation.
  321. --*/
  322. {
  323. ULONG pdeIndex;
  324. ULONG pteIndex;
  325. PHARDWARE_PTE pde;
  326. PHARDWARE_PTE pte;
  327. BOOLEAN dummy;
  328. PBOOLEAN pageTableMapped;
  329. //
  330. // Point the output parameter pointer as appropriate.
  331. //
  332. if (ARGUMENT_PRESENT(PageTableMapped)) {
  333. pageTableMapped = PageTableMapped;
  334. } else {
  335. pageTableMapped = &dummy;
  336. }
  337. //
  338. // Pages that are a part of the X86 32-bit mapping structure ARE
  339. // IGNORED.
  340. //
  341. if (Va >= PTE_BASE && Va <= PTE_TOP) {
  342. *pageTableMapped = TRUE;
  343. return FALSE;
  344. }
  345. //
  346. // Determine whether the mapping PDE is present
  347. //
  348. pdeIndex = Va >> PDI_SHIFT;
  349. pde = &((PHARDWARE_PTE)PDE_BASE)[ pdeIndex ];
  350. if (pde->Valid == 0) {
  351. *pageTableMapped = FALSE;
  352. return FALSE;
  353. }
  354. //
  355. // Indicate that the page table for this address is mapped.
  356. //
  357. *pageTableMapped = TRUE;
  358. //
  359. // It is, now get the page present status
  360. //
  361. pteIndex = Va >> PTI_SHIFT;
  362. pte = &((PHARDWARE_PTE)PTE_BASE)[ pteIndex ];
  363. if (pte->Valid == 0) {
  364. return FALSE;
  365. }
  366. *Pfn = pte->PageFrameNumber;
  367. return TRUE;
  368. }
  369. PAMD64_PAGE_TABLE
  370. BlAmd64AllocatePageTable(
  371. VOID
  372. )
  373. /*++
  374. Routine Description:
  375. This function allocates and initializes a PAGE_TABLE structure.
  376. Arguments:
  377. None.
  378. Return Value:
  379. Returns a pointer to the allocated page table structure, or NULL
  380. if the allocation failed.
  381. --*/
  382. {
  383. ARC_STATUS status;
  384. ULONG descriptor;
  385. PPT_NODE ptNode;
  386. PAMD64_PAGE_TABLE pageTable;
  387. //
  388. // Pull a page table off of the free list, if one exists
  389. //
  390. ptNode = BlAmd64FreePfnList;
  391. if (ptNode != NULL) {
  392. BlAmd64FreePfnList = ptNode->Next;
  393. } else {
  394. //
  395. // The free page table list is empty, allocate a new
  396. // page table and node to track it with.
  397. //
  398. status = BlAllocateDescriptor( LoaderAmd64MemoryData,
  399. 0,
  400. 1,
  401. &descriptor );
  402. if (status != ESUCCESS) {
  403. return NULL;
  404. }
  405. ptNode = BlAllocateHeap( sizeof(PT_NODE) );
  406. if (ptNode == NULL) {
  407. return NULL;
  408. }
  409. ptNode->PageTable = (PAMD64_PAGE_TABLE)(descriptor << PAGE_SHIFT);
  410. }
  411. ptNode->Next = BlAmd64BusyPfnList;
  412. BlAmd64BusyPfnList = ptNode;
  413. pageTable = ptNode->PageTable;
  414. RtlZeroMemory( pageTable, PAGE_SIZE );
  415. return pageTable;
  416. }
  417. ARC_STATUS
  418. BlAmd64TransferToKernel(
  419. IN PTRANSFER_ROUTINE SystemEntry,
  420. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  421. )
  422. /*++
  423. Routine Description:
  424. This routine prepares the AMD64 data structures required for kernel
  425. execution, including page table structures and 64-bit loader block,
  426. and transfers control to the kernel.
  427. This routine returns only upon an error.
  428. Arguments:
  429. SystemEntry - Pointer to the kernel entry point.
  430. BlLoaderBlock - Pointer to the 32-bit loader block structure.
  431. Return Value:
  432. No return on success. On failure, returns the status of the operation.
  433. --*/
  434. {
  435. UNREFERENCED_PARAMETER( BlLoaderBlock );
  436. BlAmd64LoaderParameterBlock = PTR_64(BlAmd64LoaderBlock64);
  437. BlAmd64KernelEntry = PTR_64(SystemEntry);
  438. BlAmd64SwitchToLongMode();
  439. return EINVAL;
  440. }
  441. ARC_STATUS
  442. BlAmd64PrepForTransferToKernelPhase1(
  443. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  444. )
  445. /*++
  446. Routine Description:
  447. This routine prepares the AMD64 data structures required for kernel
  448. execution, including page table structures and 64-bit loader block.
  449. This is the first of two phases of preperation. This phase is executed
  450. while heap and descriptor allocations are still permitted.
  451. Arguments:
  452. BlLoaderBlock - Pointer to the 32-bit loader block structure.
  453. Return Value:
  454. No return on success. On failure, returns the status of the operation.
  455. --*/
  456. {
  457. ARC_STATUS status;
  458. //
  459. // This is the main routine called to do preperatory work before
  460. // transitioning into the AMD64 kernel.
  461. //
  462. BlAmd64LoaderBlock32 = BlLoaderBlock;
  463. //
  464. // Build a 64-bit copy of the loader parameter block.
  465. //
  466. status = BlAmd64BuildLoaderBlock64();
  467. if (status != ESUCCESS) {
  468. return status;
  469. }
  470. //
  471. // Process the loaded modules.
  472. //
  473. status = BlAmd64TransferLoadedModuleState();
  474. if (status != ESUCCESS) {
  475. return status;
  476. }
  477. //
  478. // Next the boot driver nodes
  479. //
  480. status = BlAmd64TransferBootDriverNodes();
  481. if (status != ESUCCESS) {
  482. return status;
  483. }
  484. //
  485. // NLS data
  486. //
  487. status = BlAmd64TransferNlsData();
  488. if (status != ESUCCESS) {
  489. return status;
  490. }
  491. //
  492. // Configuration component data tree
  493. //
  494. status = BlAmd64TransferConfigurationComponentData();
  495. if (status != ESUCCESS) {
  496. return status;
  497. }
  498. //
  499. // ARC disk information
  500. //
  501. status = BlAmd64TransferArcDiskInformation();
  502. if (status != ESUCCESS) {
  503. return status;
  504. }
  505. //
  506. // Setup loader block
  507. //
  508. status = BlAmd64TransferSetupLoaderBlock();
  509. if (status != ESUCCESS) {
  510. return status;
  511. }
  512. //
  513. // Allocate structures needed by the kernel: TSS, stacks etc.
  514. //
  515. status = BlAmd64PrepareSystemStructures();
  516. if (status != ESUCCESS) {
  517. return status;
  518. }
  519. //
  520. // Mark the descriptor for the shared user page so that it will
  521. // not be freed by the kernel.
  522. //
  523. status = BlAmd64FixSharedUserPage();
  524. if (status != ESUCCESS) {
  525. return status;
  526. }
  527. //
  528. // Pre-allocate any pages needed for the long mode paging structures.
  529. //
  530. status = BlAmd64BuildMappingPhase1();
  531. if (status != ESUCCESS) {
  532. return status;
  533. }
  534. //
  535. // Pre-allocate the 64-bit memory allocation descriptors that will be
  536. // used by BlAmd64TransferMemoryAllocationDescriptors().
  537. //
  538. status = BlAmd64AllocateMemoryAllocationDescriptors();
  539. if (status != ESUCCESS) {
  540. return status;
  541. }
  542. return status;
  543. }
  544. VOID
  545. BlAmd64PrepForTransferToKernelPhase2(
  546. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  547. )
  548. /*++
  549. Routine Description:
  550. This routine prepares the AMD64 data structures required for kernel
  551. execution, including page table structures and 64-bit loader block.
  552. This is the second of two phases of preperation. This phase is executed
  553. after the 32-bit page tables have been purged of any unused mappings.
  554. Note that descriptor and heap allocations are not permitted at this
  555. point. Any necessary storage must have been preallocated during phase 1.
  556. Arguments:
  557. BlLoaderBlock - Pointer to the 32-bit loader block structure.
  558. Return Value:
  559. No return on success. On failure, returns the status of the operation.
  560. --*/
  561. {
  562. PLOADER_PARAMETER_EXTENSION_64 extension;
  563. ARC_STATUS status;
  564. UNREFERENCED_PARAMETER( BlLoaderBlock );
  565. //
  566. // At this point everything has been preallocated, nothing can fail.
  567. //
  568. status = BlAmd64BuildMappingPhase2();
  569. ASSERT(status == ESUCCESS);
  570. //
  571. // Transfer the memory descriptor state.
  572. //
  573. status = BlAmd64TransferMemoryAllocationDescriptors();
  574. ASSERT(status == ESUCCESS);
  575. //
  576. // Set LoaderPagesSpanned in the 64-bit loader block.
  577. //
  578. extension = PTR_32(BlAmd64LoaderBlock64->Extension);
  579. extension->LoaderPagesSpanned = BlHighestPage+1;
  580. }
  581. ARC_STATUS
  582. BlAmd64BuildMappingPhase1(
  583. VOID
  584. )
  585. /*++
  586. Routine Description:
  587. This routine performs the first of the two-phase long mode mapping
  588. structure creation process now, while memory allocations are still
  589. possible. It simply calls BlAmd64BuilMappingWorker() which in fact
  590. creates the mapping structures, and (more importantly) allocates all
  591. of the page tables required to do so.
  592. Arguments:
  593. None.
  594. Return Value:
  595. None.
  596. --*/
  597. {
  598. ARC_STATUS status;
  599. //
  600. // While it is possible to perform memory allocations, reserve enough
  601. // page tables to build the AMD64 paging structures.
  602. //
  603. // The easiest way to calculate the maximum number of pages needed is
  604. // to actually build the structures. We do that now with the first of
  605. // two calls to BlAmd64BuildMappingWorker().
  606. //
  607. status = BlAmd64BuildMappingWorker();
  608. if (status != ESUCCESS) {
  609. return status;
  610. }
  611. return ESUCCESS;
  612. }
  613. ARC_STATUS
  614. BlAmd64BuildMappingPhase2(
  615. VOID
  616. )
  617. /*++
  618. Routine Description:
  619. This routine performs the second of the two-phase long mode mapping
  620. structure creation process. All page tables will have been preallocated
  621. as a result of the work performed by BlAmd64BuildMappingPhase1().
  622. Arguments:
  623. None.
  624. Return Value:
  625. None.
  626. --*/
  627. {
  628. ARC_STATUS status;
  629. //
  630. // Reset the Amd64 paging structures
  631. //
  632. BlAmd64ResetPageTableHeap();
  633. //
  634. // All necessary page tables can now be found on BlAmd64FreePfnList.
  635. // On this, the second call to BlAmd64BuildMappingWorker(), those are the
  636. // pages that will be used to perform the mapping.
  637. //
  638. status = BlAmd64BuildMappingWorker();
  639. if (status != ESUCCESS) {
  640. return status;
  641. }
  642. return ESUCCESS;
  643. }
  644. ARC_STATUS
  645. BlAmd64BuildMappingWorker(
  646. VOID
  647. )
  648. /*++
  649. Routine Description:
  650. This routine creates any necessary memory mappings in the long-mode
  651. page table structure. It is called twice, once from
  652. BlAmd64BuildMappingPhase1() and again from BlAmd64BuildMappingPhase2().
  653. Any additional memory mapping that must be carried out should go in
  654. this routine.
  655. Arguments:
  656. None.
  657. Return Value:
  658. None.
  659. --*/
  660. {
  661. ARC_STATUS status;
  662. PFN_NUMBER pfn;
  663. //
  664. // Any long mode mapping code goes here. This routine is called twice:
  665. // once from BlAmd64BuildMappingPhase1(), and again from
  666. // BlAmd64BuildMappingPhase2().
  667. //
  668. //
  669. // Transfer any mappings in the first 32MB of identity mapping.
  670. //
  671. status = BlAmd64MapMemoryRegion( 0,
  672. 32 * 1024 * 1024 );
  673. if (status != ESUCCESS) {
  674. return status;
  675. }
  676. //
  677. // Transfer any mappings in the 1GB region starting at KSEG0_BASE_X86.
  678. //
  679. status = BlAmd64MapMemoryRegion( KSEG0_BASE_X86,
  680. 0x40000000 );
  681. if (status != ESUCCESS) {
  682. return status;
  683. }
  684. //
  685. // "Map" the HAL va
  686. //
  687. status = BlAmd64MapHalVaSpace();
  688. if (status != ESUCCESS) {
  689. return status;
  690. }
  691. //
  692. // Map the shared user data page
  693. //
  694. BlAmd64IsPageMapped( KI_USER_SHARED_DATA, &pfn, NULL );
  695. status = BlAmd64CreateMapping( KI_USER_SHARED_DATA_64, pfn );
  696. if (status != ESUCCESS) {
  697. return status;
  698. }
  699. return ESUCCESS;
  700. }
  701. VOID
  702. BlAmd64ResetPageTableHeap(
  703. VOID
  704. )
  705. /*++
  706. Routine Description:
  707. This function is called as part of the two-phase page table creation
  708. process. Its purpose is to move all of the PFNs required to build
  709. the long mode page tables back to the free list, and to otherwise
  710. initialize the long mode paging structure.
  711. Arguments:
  712. None.
  713. Return Value:
  714. None.
  715. --*/
  716. {
  717. PPT_NODE ptNodeLast;
  718. //
  719. // Move the page table nodes from the busy list to the free list.
  720. //
  721. if (BlAmd64BusyPfnList != NULL) {
  722. //
  723. // A tail pointer is not kept, so find the tail node here.
  724. //
  725. ptNodeLast = BlAmd64BusyPfnList;
  726. while (ptNodeLast->Next != NULL) {
  727. ptNodeLast = ptNodeLast->Next;
  728. }
  729. ptNodeLast->Next = BlAmd64FreePfnList;
  730. BlAmd64FreePfnList = BlAmd64BusyPfnList;
  731. BlAmd64BusyPfnList = NULL;
  732. }
  733. //
  734. // Zero the top-level pte declared in amd64.c
  735. //
  736. BlAmd64ClearTopLevelPte();
  737. }
  738. ARC_STATUS
  739. BlAmd64TransferHardwareIdList(
  740. IN PPNP_HARDWARE_ID HardwareId,
  741. OUT POINTER64 *HardwareIdDatabaseList64
  742. )
  743. /*++
  744. Routine Description:
  745. This routine walks the singly-linked list of PNP_HARDWARE_ID structures
  746. and for each one found, creates a 64-bit PNP_HARDWARE_ID_64 structure and
  747. inserts it on a list of same.
  748. The resultant 64-bit list is in the same order as the supplied 32-bit
  749. list.
  750. Arguments:
  751. HardwareId - Supplies a pointer to the head of the singly-linked list of
  752. PNP_HARDWARE_ID structures.
  753. HardwareIdDatabaseList64 -
  754. Supplies a pointer to a POINTER64 which upon successful
  755. completion of this routine will contain a 64-bit KSEG0
  756. pointer to the created 64-bit PNP_HARDWARE_ID_64 list.
  757. Return Value:
  758. ARC_STATUS - Status of operation.
  759. --*/
  760. {
  761. PPNP_HARDWARE_ID_64 hardwareId64;
  762. ARC_STATUS status;
  763. //
  764. // Walk the id list backwards. To do this we call ourselves
  765. // recursively until we find the end of the list, then process the nodes
  766. // on the way back up.
  767. //
  768. if (HardwareId == NULL) {
  769. return ESUCCESS;
  770. }
  771. status = BlAmd64TransferHardwareIdList( HardwareId->Next,
  772. HardwareIdDatabaseList64 );
  773. if (status != ESUCCESS) {
  774. return status;
  775. }
  776. hardwareId64 = BlAllocateHeap(sizeof(PNP_HARDWARE_ID_64));
  777. if (hardwareId64 == NULL) {
  778. return ENOMEM;
  779. }
  780. status = Copy_PNP_HARDWARE_ID( HardwareId, hardwareId64 );
  781. if (status != ESUCCESS) {
  782. return status;
  783. }
  784. //
  785. // Link it into the front of the 64-bit list.
  786. //
  787. hardwareId64->Next = *HardwareIdDatabaseList64;
  788. *HardwareIdDatabaseList64 = PTR_64(hardwareId64);
  789. return ESUCCESS;
  790. }
  791. ARC_STATUS
  792. BlAmd64TransferDeviceRegistryList(
  793. IN PDETECTED_DEVICE_REGISTRY DetectedDeviceRegistry32,
  794. OUT POINTER64 *DetectedDeviceRegistry64
  795. )
  796. /*++
  797. Routine Description:
  798. This routine walks the singly-linked list of DETECTED_DEVICE_REGISTRY
  799. structures and for each one found, creates a 64-bit
  800. DETECTED_DEVICE_REGISTRY_64 structure and inserts it on a list of same.
  801. The resultant 64-bit list is in the same order as the supplied 32-bit
  802. list.
  803. Arguments:
  804. DetectedDeviceRegistry32 - Supplies a pointer to the head of the singly-linked list of
  805. DETECTED_DEVICE_REGISTRY structures.
  806. DetectedDeviceRegistry64 -
  807. Supplies a pointer to a POINTER64 which upon successful
  808. completion of this routine will contain a 64-bit KSEG0
  809. pointer to the created 64-bit DETECTED_DEVICE_REGISTRY_64
  810. list.
  811. Return Value:
  812. ARC_STATUS - Status of operation.
  813. --*/
  814. {
  815. PDETECTED_DEVICE_REGISTRY_64 registry64;
  816. ARC_STATUS status;
  817. //
  818. // Walk the registry list backwards. To do this we call ourselves
  819. // recursively until we find the end of the list, then process the nodes
  820. // on the way back up.
  821. //
  822. if (DetectedDeviceRegistry32 == NULL) {
  823. return ESUCCESS;
  824. }
  825. status = BlAmd64TransferDeviceRegistryList( DetectedDeviceRegistry32->Next,
  826. DetectedDeviceRegistry64 );
  827. if (status != ESUCCESS) {
  828. return status;
  829. }
  830. //
  831. // Allocate a 64-bit registry structure and copy the contents
  832. // of the 32-bit one in.
  833. //
  834. registry64 = BlAllocateHeap(sizeof(DETECTED_DEVICE_REGISTRY_64));
  835. if (registry64 == NULL) {
  836. return ENOMEM;
  837. }
  838. status = Copy_DETECTED_DEVICE_REGISTRY( DetectedDeviceRegistry32, registry64 );
  839. if (status != ESUCCESS) {
  840. return status;
  841. }
  842. //
  843. // Link it into the front of the 64-bit list.
  844. //
  845. registry64->Next = *DetectedDeviceRegistry64;
  846. *DetectedDeviceRegistry64 = PTR_64(registry64);
  847. return ESUCCESS;
  848. }
  849. ARC_STATUS
  850. BlAmd64TransferDeviceFileList(
  851. IN PDETECTED_DEVICE_FILE DetectedDeviceFile32,
  852. OUT POINTER64 *DetectedDeviceFile64
  853. )
  854. /*++
  855. Routine Description:
  856. This routine walks the singly-linked list of DETECTED_DEVICE_FILE
  857. structures and for each one found, creates a 64-bit
  858. DETECTED_DEVICE_FILE_64 structure and inserts it on a list of same.
  859. The resultant 64-bit list is in the same order as the supplied 32-bit
  860. list.
  861. Arguments:
  862. DetectedDeviceFile32 - Supplies a pointer to the head of the singly-linked
  863. list of DETECTED_DEVICE_FILE structures.
  864. DetectedDeviceFile64 -
  865. Supplies a pointer to a POINTER64 which upon successful
  866. completion of this routine will contain a 64-bit KSEG0
  867. pointer to the created 64-bit DETECTED_DEVICE_FILE_64
  868. list.
  869. Return Value:
  870. ARC_STATUS - Status of operation.
  871. --*/
  872. {
  873. PDETECTED_DEVICE_FILE_64 file64;
  874. ARC_STATUS status;
  875. //
  876. // Walk the file list backwards. To do this we call ourselves
  877. // recursively until we find the end of the list, then process the nodes
  878. // on the way back up.
  879. //
  880. if (DetectedDeviceFile32 == NULL) {
  881. return ESUCCESS;
  882. }
  883. status = BlAmd64TransferDeviceFileList( DetectedDeviceFile32->Next,
  884. DetectedDeviceFile64 );
  885. if (status != ESUCCESS) {
  886. return status;
  887. }
  888. //
  889. // Allocate a 64-bit file structure and copy the contents
  890. // of the 32-bit one in.
  891. //
  892. file64 = BlAllocateHeap(sizeof(DETECTED_DEVICE_FILE_64));
  893. if (file64 == NULL) {
  894. return ENOMEM;
  895. }
  896. status = Copy_DETECTED_DEVICE_FILE( DetectedDeviceFile32, file64 );
  897. if (status != ESUCCESS) {
  898. return status;
  899. }
  900. //
  901. // Transfer the singly-linked list of DETECTED_DEVICE_REGISTRY structures
  902. // linked to this DETECTED_DEVICE_FILE structure.
  903. //
  904. status = BlAmd64TransferDeviceRegistryList(
  905. DetectedDeviceFile32->RegistryValueList,
  906. &file64->RegistryValueList );
  907. if (status != ESUCCESS) {
  908. return status;
  909. }
  910. //
  911. // Link it into the front of the 64-bit list.
  912. //
  913. file64->Next = *DetectedDeviceFile64;
  914. *DetectedDeviceFile64 = PTR_64(file64);
  915. return ESUCCESS;
  916. }
  917. ARC_STATUS
  918. BlAmd64TransferDeviceList(
  919. IN PDETECTED_DEVICE DetectedDevice32,
  920. OUT POINTER64 *DetectedDeviceList64
  921. )
  922. /*++
  923. Routine Description:
  924. This routine walks the singly-linked list of DETECTED_DEVICE
  925. structures and for each one found, creates a 64-bit
  926. DETECTED_DEVICE_64 structure and inserts it on a list of same.
  927. The resultant 64-bit list is in the same order as the supplied 32-bit
  928. list.
  929. Arguments:
  930. DetectedDevice32 - Supplies a pointer to the head of the singly-linked
  931. list of DETECTED_DEVICE structures.
  932. DetectedDeviceList64 -
  933. Supplies a pointer to a POINTER64 which upon successful
  934. completion of this routine will contain a 64-bit KSEG0
  935. pointer to the created 64-bit DETECTED_DEVICE_64
  936. list.
  937. Return Value:
  938. ARC_STATUS - Status of operation.
  939. --*/
  940. {
  941. PDETECTED_DEVICE_64 device64;
  942. ARC_STATUS status;
  943. //
  944. // Walk the device list backwards. To do this we call ourselves
  945. // recursively until we find the end of the list, then process the nodes
  946. // on the way back up.
  947. //
  948. if (DetectedDevice32 == NULL) {
  949. return ESUCCESS;
  950. }
  951. status = BlAmd64TransferDeviceList( DetectedDevice32->Next,
  952. DetectedDeviceList64 );
  953. if (status != ESUCCESS) {
  954. return status;
  955. }
  956. //
  957. // Allocate a 64-bit device structure and copy the contents
  958. // of the 32-bit one in.
  959. //
  960. device64 = BlAllocateHeap(sizeof(DETECTED_DEVICE_64));
  961. if (device64 == NULL) {
  962. return ENOMEM;
  963. }
  964. status = Copy_DETECTED_DEVICE( DetectedDevice32, device64 );
  965. if (status != ESUCCESS) {
  966. return status;
  967. }
  968. //
  969. // Transfer any PROTECTED_DEVICE_FILE structures
  970. //
  971. status = BlAmd64TransferDeviceFileList( DetectedDevice32->Files,
  972. &device64->Files );
  973. if (status != ESUCCESS) {
  974. return status;
  975. }
  976. //
  977. // Link it into the front of the 64-bit list.
  978. //
  979. device64->Next = *DetectedDeviceList64;
  980. *DetectedDeviceList64 = PTR_64(device64);
  981. return ESUCCESS;
  982. }
  983. ARC_STATUS
  984. BlAmd64TransferSetupLoaderBlock(
  985. VOID
  986. )
  987. /*++
  988. Routine Description:
  989. This routine creates a SETUP_LOADER_BLOCK_64 structure that is the
  990. equivalent of the 32-bit SETUP_LOADER_BLOCK structure referenced within
  991. the 32-bit setup loader block.
  992. Arguments:
  993. None.
  994. Return Value:
  995. ARC_STATUS - Status of operation.
  996. --*/
  997. {
  998. PSETUP_LOADER_BLOCK setupBlock32;
  999. PSETUP_LOADER_BLOCK_64 setupBlock64;
  1000. ARC_STATUS status;
  1001. setupBlock32 = BlAmd64LoaderBlock32->SetupLoaderBlock;
  1002. if (setupBlock32 == NULL) {
  1003. return ESUCCESS;
  1004. }
  1005. setupBlock64 = BlAllocateHeap(sizeof(SETUP_LOADER_BLOCK_64));
  1006. if (setupBlock64 == NULL) {
  1007. return ENOMEM;
  1008. }
  1009. status = Copy_SETUP_LOADER_BLOCK( setupBlock32, setupBlock64 );
  1010. if (status != ESUCCESS) {
  1011. return status;
  1012. }
  1013. {
  1014. #define TRANSFER_DEVICE_LIST(x) \
  1015. setupBlock64->x = PTR_64(NULL); \
  1016. status = BlAmd64TransferDeviceList( setupBlock32->x, \
  1017. &setupBlock64->x ); \
  1018. if (status != ESUCCESS) return status;
  1019. TRANSFER_DEVICE_LIST(KeyboardDevices);
  1020. TRANSFER_DEVICE_LIST(ScsiDevices);
  1021. TRANSFER_DEVICE_LIST(BootBusExtenders);
  1022. TRANSFER_DEVICE_LIST(BusExtenders);
  1023. TRANSFER_DEVICE_LIST(InputDevicesSupport);
  1024. #undef TRANSFER_DEVICE_LIST
  1025. }
  1026. setupBlock64->HardwareIdDatabase = PTR_64(NULL);
  1027. status = BlAmd64TransferHardwareIdList( setupBlock32->HardwareIdDatabase,
  1028. &setupBlock64->HardwareIdDatabase );
  1029. if (status != ESUCCESS) {
  1030. return status;
  1031. }
  1032. BlAmd64LoaderBlock64->SetupLoaderBlock = PTR_64(setupBlock64);
  1033. return status;
  1034. }
  1035. ARC_STATUS
  1036. BlAmd64TransferArcDiskInformation(
  1037. VOID
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. This routine creates an ARC_DISK_INFORMATION_64 structure that is the
  1042. equivalent of the 32-bit ARC_DISK_INFORMATION structure referenced within
  1043. the 32-bit loader block.
  1044. Arguments:
  1045. None.
  1046. Return Value:
  1047. ARC_STATUS - Status of operation.
  1048. --*/
  1049. {
  1050. ARC_STATUS status;
  1051. PLIST_ENTRY listHead;
  1052. PLIST_ENTRY listEntry;
  1053. PARC_DISK_INFORMATION diskInfo32;
  1054. PARC_DISK_INFORMATION_64 diskInfo64;
  1055. PARC_DISK_SIGNATURE diskSignature32;
  1056. PARC_DISK_SIGNATURE_64 diskSignature64;
  1057. //
  1058. // Create a 64-bit ARC_DISK_INFORMATION structure
  1059. //
  1060. diskInfo32 = BlAmd64LoaderBlock32->ArcDiskInformation;
  1061. if (diskInfo32 == NULL) {
  1062. return ESUCCESS;
  1063. }
  1064. diskInfo64 = BlAllocateHeap(sizeof(ARC_DISK_INFORMATION_64));
  1065. if (diskInfo64 == NULL) {
  1066. return ENOMEM;
  1067. }
  1068. status = Copy_ARC_DISK_INFORMATION( diskInfo32, diskInfo64 );
  1069. if (status != ESUCCESS) {
  1070. return status;
  1071. }
  1072. InitializeListHead64( &diskInfo64->DiskSignatures );
  1073. //
  1074. // Walk the 32-bit list of ARC_DISK_SIGNATURE nodes and create
  1075. // a 64-bit version of each
  1076. //
  1077. listHead = &diskInfo32->DiskSignatures;
  1078. listEntry = listHead->Flink;
  1079. while (listEntry != listHead) {
  1080. diskSignature32 = CONTAINING_RECORD( listEntry,
  1081. ARC_DISK_SIGNATURE,
  1082. ListEntry );
  1083. diskSignature64 = BlAllocateHeap(sizeof(ARC_DISK_SIGNATURE_64));
  1084. if (diskSignature64 == NULL) {
  1085. return ENOMEM;
  1086. }
  1087. status = Copy_ARC_DISK_SIGNATURE( diskSignature32, diskSignature64 );
  1088. if (status != ESUCCESS) {
  1089. return status;
  1090. }
  1091. InsertTailList64( &diskInfo64->DiskSignatures,
  1092. &diskSignature64->ListEntry );
  1093. listEntry = listEntry->Flink;
  1094. }
  1095. BlAmd64LoaderBlock64->ArcDiskInformation = PTR_64(diskInfo64);
  1096. return ESUCCESS;
  1097. }
  1098. ARC_STATUS
  1099. BlAmd64TransferConfigurationComponentData(
  1100. VOID
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. This routine creates a CONFIGURATION_COMPONENT_DATA_64 structure tree
  1105. that is the equivalent of the 32-bit CONFIGURATION_COMPONENT_DATA
  1106. structure tree referenced within the 32-bit loader block.
  1107. Arguments:
  1108. None.
  1109. Return Value:
  1110. ARC_STATUS - Status of operation.
  1111. --*/
  1112. {
  1113. PCONFIGURATION_COMPONENT_DATA_64 rootComponent64;
  1114. if (BlAmd64LoaderBlock32->ConfigurationRoot == NULL) {
  1115. return ESUCCESS;
  1116. }
  1117. rootComponent64 =
  1118. BlAmd64TransferConfigWorker( BlAmd64LoaderBlock32->ConfigurationRoot,
  1119. NULL );
  1120. if (rootComponent64 == NULL) {
  1121. return ENOMEM;
  1122. }
  1123. BlAmd64LoaderBlock64->ConfigurationRoot = PTR_64(rootComponent64);
  1124. return ESUCCESS;
  1125. }
  1126. PCONFIGURATION_COMPONENT_DATA_64
  1127. BlAmd64TransferConfigWorker(
  1128. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  1129. IN PCONFIGURATION_COMPONENT_DATA_64 ComponentDataParent64
  1130. )
  1131. /*++
  1132. Routine Description:
  1133. Given a 32-bit CONFIGURATION_COMPONENT_DATA structure, this routine
  1134. creates an equivalent 64-bit CONFIGURATION_COMPONENT_DATA structure
  1135. for the supplied structure, as well as for all of its children and
  1136. siblings.
  1137. This routine calls itself recursively for each sibling and child.
  1138. Arguments:
  1139. ComponentData32 - Supplies a pointer to the 32-bit structure to transfer.
  1140. ComponentDataParent64 - Supplies a pointer to the current 64-bit parent
  1141. structure.
  1142. Return Value:
  1143. Returns a pointer to the created 64-bit structure, or NULL if a failure
  1144. was encountered.
  1145. --*/
  1146. {
  1147. ARC_STATUS status;
  1148. ULONG componentDataSize64;
  1149. ULONG partialResourceListSize64;
  1150. BOOLEAN thunkResourceList;
  1151. PCONFIGURATION_COMPONENT_DATA_64 componentData64;
  1152. PCONFIGURATION_COMPONENT_DATA_64 newCompData64;
  1153. //
  1154. // Create and copy configuration component data node
  1155. //
  1156. componentDataSize64 = sizeof(CONFIGURATION_COMPONENT_DATA_64);
  1157. thunkResourceList = BlAmd64ContainsResourceList(ComponentData32,
  1158. &partialResourceListSize64);
  1159. if (thunkResourceList != FALSE) {
  1160. //
  1161. // This node contains a CM_PARTIAL_RESOURCE_LIST structure.
  1162. // partialResourceListSize64 contains the number of bytes beyond the
  1163. // CONFIGURATION_COMPONENT_DATA header that must be allocated in order to
  1164. // thunk the CM_PARTIAL_RESOURCE_LIST into a 64-bit version.
  1165. //
  1166. componentDataSize64 += partialResourceListSize64;
  1167. }
  1168. componentData64 = BlAllocateHeap(componentDataSize64);
  1169. if (componentData64 == NULL) {
  1170. return NULL;
  1171. }
  1172. status = Copy_CONFIGURATION_COMPONENT_DATA( ComponentData32,
  1173. componentData64 );
  1174. if (status != ESUCCESS) {
  1175. return NULL;
  1176. }
  1177. if (thunkResourceList != FALSE) {
  1178. //
  1179. // Update the configuration component data size
  1180. //
  1181. componentData64->ComponentEntry.ConfigurationDataLength =
  1182. partialResourceListSize64;
  1183. }
  1184. componentData64->Parent = PTR_64(ComponentDataParent64);
  1185. if (thunkResourceList != FALSE) {
  1186. //
  1187. // Now transfer the resource list.
  1188. //
  1189. BlAmd64TransferResourceList(ComponentData32,componentData64);
  1190. }
  1191. //
  1192. // Process the child (and recursively, all children)
  1193. //
  1194. if (ComponentData32->Child != NULL) {
  1195. newCompData64 = BlAmd64TransferConfigWorker( ComponentData32->Child,
  1196. componentData64 );
  1197. if (newCompData64 == NULL) {
  1198. return newCompData64;
  1199. }
  1200. componentData64->Child = PTR_64(newCompData64);
  1201. }
  1202. //
  1203. // Process the sibling (and recursively, all siblings)
  1204. //
  1205. if (ComponentData32->Sibling != NULL) {
  1206. newCompData64 = BlAmd64TransferConfigWorker( ComponentData32->Sibling,
  1207. ComponentDataParent64 );
  1208. if (newCompData64 == NULL) {
  1209. return newCompData64;
  1210. }
  1211. componentData64->Sibling = PTR_64(newCompData64);
  1212. }
  1213. return componentData64;
  1214. }
  1215. VOID
  1216. BlAmd64TransferResourceList(
  1217. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  1218. OUT PCONFIGURATION_COMPONENT_DATA_64 ComponentData64
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This routine transfers the 32-bit CM_PARTIAL_RESOURCE_LIST structure that
  1223. immediately follows ComponentData32 to the memory immediately after
  1224. ComponentData64.
  1225. Arguments:
  1226. ComponentData32 - Supplies a pointer to the 32-bit structure to transfer from.
  1227. ComponentData64 - Supplies a pointer to the 64-bit structure to transfer to.
  1228. Return Value:
  1229. None.
  1230. --*/
  1231. {
  1232. PCM_PARTIAL_RESOURCE_LIST resourceList32;
  1233. PCM_PARTIAL_RESOURCE_LIST_64 resourceList64;
  1234. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDesc32;
  1235. PCM_PARTIAL_RESOURCE_DESCRIPTOR_64 resourceDesc64;
  1236. PVOID descBody32;
  1237. PVOID descBody64;
  1238. PUCHAR tail32;
  1239. PUCHAR tail64;
  1240. ULONG tailSize;
  1241. ULONG descriptorCount;
  1242. //
  1243. // Calculate pointers to the source and target descriptor lists.
  1244. //
  1245. resourceList32 = (PCM_PARTIAL_RESOURCE_LIST)ComponentData32->ConfigurationData;
  1246. resourceList64 = (PCM_PARTIAL_RESOURCE_LIST_64)(ComponentData64 + 1);
  1247. //
  1248. // Update ComponentData64 to refer to it's new data area, which will be immediately
  1249. // following the component data structure.
  1250. //
  1251. ComponentData64->ConfigurationData = PTR_64(resourceList64);
  1252. //
  1253. // Copy the resource list header information
  1254. //
  1255. Copy_CM_PARTIAL_RESOURCE_LIST(resourceList32,resourceList64);
  1256. //
  1257. // Now thunk each of the resource descriptors
  1258. //
  1259. descriptorCount = resourceList32->Count;
  1260. resourceDesc32 = resourceList32->PartialDescriptors;
  1261. resourceDesc64 = &resourceList64->PartialDescriptors;
  1262. while (descriptorCount > 0) {
  1263. //
  1264. // Transfer the common header information
  1265. //
  1266. Copy_CM_PARTIAL_RESOURCE_DESCRIPTOR(resourceDesc32,resourceDesc64);
  1267. descBody32 = &resourceDesc32->u;
  1268. descBody64 = &resourceDesc64->u;
  1269. RtlZeroMemory(descBody64,
  1270. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR_64) -
  1271. FIELD_OFFSET(CM_PARTIAL_RESOURCE_DESCRIPTOR_64,u));
  1272. //
  1273. // Transfer the body according to the type
  1274. //
  1275. switch(resourceDesc32->Type) {
  1276. case CmResourceTypeNull:
  1277. break;
  1278. case CmResourceTypePort:
  1279. Copy_CM_PRD_PORT(descBody32,descBody64);
  1280. break;
  1281. case CmResourceTypeInterrupt:
  1282. Copy_CM_PRD_INTERRUPT(descBody32,descBody64);
  1283. break;
  1284. case CmResourceTypeMemory:
  1285. Copy_CM_PRD_MEMORY(descBody32,descBody64);
  1286. break;
  1287. case CmResourceTypeDma:
  1288. Copy_CM_PRD_DMA(descBody32,descBody64);
  1289. break;
  1290. case CmResourceTypeDeviceSpecific:
  1291. Copy_CM_PRD_DEVICESPECIFICDATA(descBody32,descBody64);
  1292. break;
  1293. case CmResourceTypeBusNumber:
  1294. Copy_CM_PRD_BUSNUMBER(descBody32,descBody64);
  1295. break;
  1296. default:
  1297. Copy_CM_PRD_GENERIC(descBody32,descBody64);
  1298. break;
  1299. }
  1300. resourceDesc32 += 1;
  1301. resourceDesc64 += 1;
  1302. descriptorCount -= 1;
  1303. }
  1304. //
  1305. // Calculate how much data, if any, is appended to the resource list.
  1306. //
  1307. tailSize = ComponentData32->ComponentEntry.ConfigurationDataLength +
  1308. (PUCHAR)resourceList32 -
  1309. (PUCHAR)resourceDesc32;
  1310. if (tailSize > 0) {
  1311. //
  1312. // Some data is there, append it as-is to the 64-bit structure.
  1313. //
  1314. tail32 = (PUCHAR)resourceDesc32;
  1315. tail64 = (PUCHAR)resourceDesc64;
  1316. RtlCopyMemory(tail64,tail32,tailSize);
  1317. }
  1318. }
  1319. BOOLEAN
  1320. BlAmd64ContainsResourceList(
  1321. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  1322. OUT PULONG ResourceListSize64
  1323. )
  1324. /*++
  1325. Routine Description:
  1326. Given a 32-bit CONFIGURATION_COMPONENT_DATA structure, this routine
  1327. determines whether the data associated with the structure contains a
  1328. CM_PARTIAL_RESOURCE_LIST structure.
  1329. If it does, the size of the 64-bit representation of this structure is calculated,
  1330. added to any data that might be appended to the resource list structure, and
  1331. returned in ResourceListSize64.
  1332. Arguments:
  1333. ComponentData32 - Supplies a pointer to the 32-bit structure to transfer.
  1334. ResourceListSize64 - Supplies a pointer to a ULONG in which the necessary
  1335. additional data size is returned.
  1336. Return Value:
  1337. Returns TRUE if the CONFIGURATION_COMPONENT_DATA stucture refers to a
  1338. CM_PARTIAL_RESOURCE_LIST structure, FALSE otherwise.
  1339. --*/
  1340. {
  1341. ULONG configDataLen;
  1342. PCM_PARTIAL_RESOURCE_LIST resourceList;
  1343. ULONG resourceCount;
  1344. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
  1345. PCM_PARTIAL_RESOURCE_DESCRIPTOR lastResourceDescriptor;
  1346. configDataLen = ComponentData32->ComponentEntry.ConfigurationDataLength;
  1347. if (configDataLen < sizeof(CM_PARTIAL_RESOURCE_LIST)) {
  1348. //
  1349. // Data not large enough to contain the smallest possible resource list
  1350. //
  1351. return FALSE;
  1352. }
  1353. resourceList = (PCM_PARTIAL_RESOURCE_LIST)ComponentData32->ConfigurationData;
  1354. if (resourceList->Version != 0 || resourceList->Revision != 0) {
  1355. //
  1356. // Unrecognized version.
  1357. //
  1358. return FALSE;
  1359. }
  1360. configDataLen -= FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,PartialDescriptors);
  1361. resourceCount = resourceList->Count;
  1362. if (configDataLen < sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * resourceCount) {
  1363. //
  1364. // Config data len is not large enough to contain a CM_PARTIAL_RESOURCE_LIST
  1365. // as large as this one claims to be.
  1366. //
  1367. return FALSE;
  1368. }
  1369. //
  1370. // Validate each of the CM_PARTIAL_RESOURCE_DESCRIPTOR structures in the list
  1371. //
  1372. resourceDescriptor = resourceList->PartialDescriptors;
  1373. lastResourceDescriptor = resourceDescriptor + resourceCount;
  1374. while (resourceDescriptor < lastResourceDescriptor) {
  1375. if (resourceDescriptor->Type > CmResourceTypeMaximum) {
  1376. return FALSE;
  1377. }
  1378. resourceDescriptor += 1;
  1379. }
  1380. //
  1381. // Looks like this is an actual resource list. Calculate the size of any remaining
  1382. // data after the CM_PARTIAL_RESOURCE_LIST structure.
  1383. //
  1384. configDataLen -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * resourceCount;
  1385. *ResourceListSize64 = sizeof(CM_PARTIAL_RESOURCE_LIST_64) +
  1386. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR_64) * (resourceCount - 1) +
  1387. configDataLen;
  1388. return TRUE;
  1389. }
  1390. ARC_STATUS
  1391. BlAmd64TransferNlsData(
  1392. VOID
  1393. )
  1394. /*++
  1395. Routine Description:
  1396. This routine creates an NLS_DATA_BLOCK64 structure that is the
  1397. equivalent of the 32-bit NLS_DATA_BLOCK structure referenced within
  1398. the 32-bit loader block.
  1399. Arguments:
  1400. None.
  1401. Return Value:
  1402. ARC_STATUS - Status of operation.
  1403. --*/
  1404. {
  1405. ARC_STATUS status;
  1406. PNLS_DATA_BLOCK nlsDataBlock32;
  1407. PNLS_DATA_BLOCK_64 nlsDataBlock64;
  1408. nlsDataBlock32 = BlAmd64LoaderBlock32->NlsData;
  1409. if (nlsDataBlock32 == NULL) {
  1410. return ESUCCESS;
  1411. }
  1412. nlsDataBlock64 = BlAllocateHeap(sizeof(NLS_DATA_BLOCK_64));
  1413. if (nlsDataBlock64 == NULL) {
  1414. return ENOMEM;
  1415. }
  1416. status = Copy_NLS_DATA_BLOCK( nlsDataBlock32, nlsDataBlock64 );
  1417. if (status != ESUCCESS) {
  1418. return status;
  1419. }
  1420. BlAmd64LoaderBlock64->NlsData = PTR_64( nlsDataBlock64 );
  1421. return ESUCCESS;
  1422. }
  1423. ARC_STATUS
  1424. BlAmd64BuildLoaderBlock64(
  1425. VOID
  1426. )
  1427. /*++
  1428. Routine Description:
  1429. This routine allocates a 64-bit loader parameter block and copies the
  1430. contents of the 32-bit loader parameter block into it.
  1431. Arguments:
  1432. None.
  1433. Return Value:
  1434. The status of the operation.
  1435. --*/
  1436. {
  1437. ARC_STATUS status;
  1438. //
  1439. // Allocate the loader block and extension
  1440. //
  1441. BlAmd64LoaderBlock64 = BlAllocateHeap(sizeof(LOADER_PARAMETER_BLOCK_64));
  1442. if (BlAmd64LoaderBlock64 == NULL) {
  1443. return ENOMEM;
  1444. }
  1445. //
  1446. // Copy the contents of the 32-bit loader parameter block to the
  1447. // 64-bit version
  1448. //
  1449. status = Copy_LOADER_PARAMETER_BLOCK( BlAmd64LoaderBlock32, BlAmd64LoaderBlock64 );
  1450. if (status != ESUCCESS) {
  1451. return status;
  1452. }
  1453. //
  1454. // Build the loader block extension
  1455. //
  1456. status = BlAmd64BuildLoaderBlockExtension64();
  1457. if (status != ESUCCESS) {
  1458. return status;
  1459. }
  1460. return ESUCCESS;
  1461. }
  1462. ARC_STATUS
  1463. BlAmd64TransferMemoryAllocationDescriptors(
  1464. VOID
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. This routine transfers all of the 32-bit memory allocation descriptors
  1469. to a 64-bit list.
  1470. The storage for the 64-bit memory allocation descriptors has been
  1471. preallocated by a previous call to
  1472. BlAmd64AllocateMemoryAllocationDescriptors(). This memory is described
  1473. by BlAmd64DescriptorArray and BlAmd64DescriptorArraySize.
  1474. Arguments:
  1475. None.
  1476. Return Value:
  1477. The status of the operation.
  1478. --*/
  1479. {
  1480. ARC_STATUS status;
  1481. PMEMORY_ALLOCATION_DESCRIPTOR memDesc32;
  1482. PMEMORY_ALLOCATION_DESCRIPTOR_64 memDesc64;
  1483. PLIST_ENTRY listHead;
  1484. PLIST_ENTRY listEntry;
  1485. LONG descriptorCount;
  1486. //
  1487. // Modify some descriptor types. All of the descriptors of type
  1488. // LoaderMemoryData really contain things that won't be used in 64-bit
  1489. // mode, such as 32-bit page tables and the like.
  1490. //
  1491. // The descriptors that we really want to stick around are allocated with
  1492. // LoaderAmd64MemoryData.
  1493. //
  1494. // Perform two memory descriptor list search-and-replacements:
  1495. //
  1496. // LoaderMemoryData -> LoaderOSLoaderHeap
  1497. //
  1498. // These desriptors will be freed during kernel init phase 1
  1499. //
  1500. // LoaderAmd64MemoryData -> LoaderMemoryData
  1501. //
  1502. // This stuff will be kept around
  1503. //
  1504. //
  1505. // All existing LoaderMemoryData refers to structures that are not useful
  1506. // once running in long mode. However, we're using some of the structures
  1507. // now (32-bit page tables for example), so convert them to
  1508. // type LoaderOsloaderHeap, which will be eventually freed by the kernel.
  1509. //
  1510. BlAmd64ReplaceMemoryDescriptorType(LoaderMemoryData,
  1511. LoaderOsloaderHeap,
  1512. TRUE);
  1513. //
  1514. // Same for LoaderStartupPcrPage
  1515. //
  1516. BlAmd64ReplaceMemoryDescriptorType(LoaderStartupPcrPage,
  1517. LoaderOsloaderHeap,
  1518. TRUE);
  1519. //
  1520. // All of the permanent structures that need to be around for longmode
  1521. // were temporarily allocated with LoaderAmd64MemoryData. Convert all
  1522. // of those to LoaderMemoryData now.
  1523. //
  1524. BlAmd64ReplaceMemoryDescriptorType(LoaderAmd64MemoryData,
  1525. LoaderMemoryData,
  1526. TRUE);
  1527. //
  1528. // Now walk the 32-bit memory descriptors, filling in and inserting a
  1529. // 64-bit version into BlAmd64LoaderBlock64.
  1530. //
  1531. InitializeListHead64( &BlAmd64LoaderBlock64->MemoryDescriptorListHead );
  1532. memDesc64 = BlAmd64DescriptorArray;
  1533. descriptorCount = BlAmd64DescriptorArraySize;
  1534. listHead = &BlAmd64LoaderBlock32->MemoryDescriptorListHead;
  1535. listEntry = listHead->Flink;
  1536. while (listEntry != listHead && descriptorCount > 0) {
  1537. memDesc32 = CONTAINING_RECORD( listEntry,
  1538. MEMORY_ALLOCATION_DESCRIPTOR,
  1539. ListEntry );
  1540. status = Copy_MEMORY_ALLOCATION_DESCRIPTOR( memDesc32, memDesc64 );
  1541. if (status != ESUCCESS) {
  1542. return status;
  1543. }
  1544. #if DBG
  1545. DbgPrint("Base 0x%08x size 0x%02x %s\n",
  1546. memDesc32->BasePage,
  1547. memDesc32->PageCount,
  1548. BlAmd64MemoryDescriptorText[memDesc32->MemoryType]);
  1549. #endif
  1550. InsertTailList64( &BlAmd64LoaderBlock64->MemoryDescriptorListHead,
  1551. &memDesc64->ListEntry );
  1552. listEntry = listEntry->Flink;
  1553. memDesc64 = memDesc64 + 1;
  1554. descriptorCount -= 1;
  1555. }
  1556. ASSERT( descriptorCount >= 0 && listEntry == listHead );
  1557. return ESUCCESS;
  1558. }
  1559. ARC_STATUS
  1560. BlAmd64AllocateMemoryAllocationDescriptors(
  1561. VOID
  1562. )
  1563. /*++
  1564. Routine Description:
  1565. This routine preallocates a quantity of memory sufficient to contain
  1566. a 64-bit version of each memory allocation descriptor.
  1567. The resultant memory is described in two globals: BlAmd64DescriptorArray
  1568. and BlAmd64DescriptorArrayCount.
  1569. Arguments:
  1570. None.
  1571. Return Value:
  1572. The status of the operation.
  1573. --*/
  1574. {
  1575. PLIST_ENTRY listHead;
  1576. PLIST_ENTRY listEntry;
  1577. ULONG descriptorCount;
  1578. ULONG arraySize;
  1579. PMEMORY_ALLOCATION_DESCRIPTOR_64 descriptorArray;
  1580. //
  1581. // Count the number of descriptors needed.
  1582. //
  1583. descriptorCount = 0;
  1584. listHead = &BlAmd64LoaderBlock32->MemoryDescriptorListHead;
  1585. listEntry = listHead->Flink;
  1586. while (listEntry != listHead) {
  1587. descriptorCount += 1;
  1588. listEntry = listEntry->Flink;
  1589. }
  1590. //
  1591. // Allocate memory sufficient to contain them all in 64-bit form.
  1592. //
  1593. arraySize = descriptorCount *
  1594. sizeof(MEMORY_ALLOCATION_DESCRIPTOR_64);
  1595. descriptorArray = BlAllocateHeap(arraySize);
  1596. if (descriptorArray == NULL) {
  1597. return ENOMEM;
  1598. }
  1599. BlAmd64DescriptorArray = descriptorArray;
  1600. BlAmd64DescriptorArraySize = descriptorCount;
  1601. return ESUCCESS;
  1602. }
  1603. ARC_STATUS
  1604. BlAmd64TransferLoadedModuleState(
  1605. VOID
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. This routine transfers the 32-bit list of LDR_DATA_TABLE_ENTRY structures
  1610. to an equivalent 64-bit list.
  1611. Arguments:
  1612. None.
  1613. Return Value:
  1614. The status of the operation.
  1615. --*/
  1616. {
  1617. PLDR_DATA_TABLE_ENTRY dataTableEntry32;
  1618. PLDR_DATA_TABLE_ENTRY_64 dataTableEntry64;
  1619. PLIST_ENTRY listEntry;
  1620. PLIST_ENTRY listHead;
  1621. ARC_STATUS status;
  1622. InitializeListHead64( &BlAmd64LoaderBlock64->LoadOrderListHead );
  1623. //
  1624. // For each of the LDR_DATA_TABLE_ENTRY structures in the 32-bit
  1625. // loader parameter block, create a 64-bit LDR_DATA_TABLE_ENTRY
  1626. // and queue it on the 64-bit loader parameter block.
  1627. //
  1628. listHead = &BlAmd64LoaderBlock32->LoadOrderListHead;
  1629. listEntry = listHead->Flink;
  1630. while (listEntry != listHead) {
  1631. dataTableEntry32 = CONTAINING_RECORD( listEntry,
  1632. LDR_DATA_TABLE_ENTRY,
  1633. InLoadOrderLinks );
  1634. status = BlAmd64BuildLdrDataTableEntry64( dataTableEntry32,
  1635. &dataTableEntry64 );
  1636. if (status != ESUCCESS) {
  1637. return status;
  1638. }
  1639. //
  1640. // Insert it into the 64-bit loader block's data table queue.
  1641. //
  1642. InsertTailList64( &BlAmd64LoaderBlock64->LoadOrderListHead,
  1643. &dataTableEntry64->InLoadOrderLinks );
  1644. listEntry = listEntry->Flink;
  1645. }
  1646. return ESUCCESS;
  1647. }
  1648. ARC_STATUS
  1649. BlAmd64BuildLdrDataTableEntry64(
  1650. IN PLDR_DATA_TABLE_ENTRY DataTableEntry32,
  1651. OUT PLDR_DATA_TABLE_ENTRY_64 *DataTableEntry64
  1652. )
  1653. /*++
  1654. Routine Description:
  1655. This routine transfers the contents of a single 32-bit
  1656. LDR_DATA_TABLE_ENTRY structure to the 64-bit equivalent.
  1657. Arguments:
  1658. DataTableEntry32 - Supplies a pointer to the source structure.
  1659. DataTableEntry64 - Supplies a pointer to the destination pointer to
  1660. the created structure.
  1661. Return Value:
  1662. The status of the operation.
  1663. --*/
  1664. {
  1665. ARC_STATUS status;
  1666. PLDR_DATA_TABLE_ENTRY_64 dataTableEntry64;
  1667. //
  1668. // Allocate a 64-bit data table entry and transfer the 32-bit
  1669. // contents
  1670. //
  1671. dataTableEntry64 = BlAllocateHeap( sizeof(LDR_DATA_TABLE_ENTRY_64) );
  1672. if (dataTableEntry64 == NULL) {
  1673. return ENOMEM;
  1674. }
  1675. status = Copy_LDR_DATA_TABLE_ENTRY( DataTableEntry32, dataTableEntry64 );
  1676. if (status != ESUCCESS) {
  1677. return status;
  1678. }
  1679. *DataTableEntry64 = dataTableEntry64;
  1680. //
  1681. // Later on, we'll need to determine the 64-bit copy of this data
  1682. // table entry. Store the 64-bit pointer to the copy here.
  1683. //
  1684. *((POINTER64 *)&DataTableEntry32->DllBase) = PTR_64(dataTableEntry64);
  1685. return ESUCCESS;
  1686. }
  1687. ARC_STATUS
  1688. BlAmd64BuildLoaderBlockExtension64(
  1689. VOID
  1690. )
  1691. /*++
  1692. Routine Description:
  1693. This routine transfers the contents of the 32-bit loader block
  1694. extension to a 64-bit equivalent.
  1695. Arguments:
  1696. None.
  1697. Return Value:
  1698. The status of the operation.
  1699. --*/
  1700. {
  1701. PLOADER_PARAMETER_EXTENSION_64 loaderExtension;
  1702. ARC_STATUS status;
  1703. //
  1704. // Allocate the 64-bit extension and transfer the contents of the
  1705. // 32-bit block.
  1706. //
  1707. loaderExtension = BlAllocateHeap( sizeof(LOADER_PARAMETER_EXTENSION_64) );
  1708. if (loaderExtension == NULL) {
  1709. return ENOMEM;
  1710. }
  1711. //
  1712. // Perform automatic copy of most fields
  1713. //
  1714. status = Copy_LOADER_PARAMETER_EXTENSION( BlLoaderBlock->Extension,
  1715. loaderExtension );
  1716. if (status != ESUCCESS) {
  1717. return status;
  1718. }
  1719. //
  1720. // Initialize Symbol list head properly
  1721. //
  1722. InitializeListHead64( &loaderExtension->FirmwareDescriptorListHead );
  1723. //
  1724. // Manually fix up remaining fields
  1725. //
  1726. loaderExtension->Size = sizeof(LOADER_PARAMETER_EXTENSION_64);
  1727. BlAmd64LoaderBlock64->Extension = PTR_64(loaderExtension);
  1728. return ESUCCESS;
  1729. }
  1730. ARC_STATUS
  1731. BlAmd64TransferBootDriverNodes(
  1732. VOID
  1733. )
  1734. /*++
  1735. Routine Description:
  1736. This routine transfers the 32-bit list of BOOT_DRIVER_NODE structures
  1737. to an equivalent 64-bit list.
  1738. Arguments:
  1739. None.
  1740. Return Value:
  1741. The status of the operation.
  1742. --*/
  1743. {
  1744. PBOOT_DRIVER_LIST_ENTRY driverListEntry32;
  1745. PBOOT_DRIVER_NODE driverNode32;
  1746. PBOOT_DRIVER_NODE_64 driverNode64;
  1747. POINTER64 dataTableEntry64;
  1748. PKLDR_DATA_TABLE_ENTRY dataTableEntry;
  1749. PLIST_ENTRY listEntry;
  1750. PLIST_ENTRY listHead;
  1751. ARC_STATUS status;
  1752. InitializeListHead64( &BlAmd64LoaderBlock64->BootDriverListHead );
  1753. //
  1754. // For each of the BOOT_DRIVER_NODE structures in the 32-bit
  1755. // loader parameter block, create a 64-bit BOOT_DRIVER_NODE
  1756. // and (possibly) associated LDR_DATA_TABLE_ENTRY structure.
  1757. //
  1758. listHead = &BlAmd64LoaderBlock32->BootDriverListHead;
  1759. listEntry = listHead->Flink;
  1760. while (listEntry != listHead) {
  1761. driverListEntry32 = CONTAINING_RECORD( listEntry,
  1762. BOOT_DRIVER_LIST_ENTRY,
  1763. Link );
  1764. driverNode32 = CONTAINING_RECORD( driverListEntry32,
  1765. BOOT_DRIVER_NODE,
  1766. ListEntry );
  1767. driverNode64 = BlAllocateHeap( sizeof(BOOT_DRIVER_NODE_64) );
  1768. if (driverNode64 == NULL) {
  1769. return ENOMEM;
  1770. }
  1771. status = Copy_BOOT_DRIVER_NODE( driverNode32, driverNode64 );
  1772. if (status != ESUCCESS) {
  1773. return status;
  1774. }
  1775. dataTableEntry = driverNode32->ListEntry.LdrEntry;
  1776. if (dataTableEntry != NULL) {
  1777. //
  1778. // There is already a 64-bit copy of this table entry, and we
  1779. // stored a pointer to it at DllBase.
  1780. //
  1781. dataTableEntry64 = *((POINTER64 *)&dataTableEntry->DllBase);
  1782. driverNode64->ListEntry.LdrEntry = dataTableEntry64;
  1783. }
  1784. //
  1785. // Now insert the driver list entry into the 64-bit loader block.
  1786. //
  1787. InsertTailList64( &BlAmd64LoaderBlock64->BootDriverListHead,
  1788. &driverNode64->ListEntry.Link );
  1789. listEntry = listEntry->Flink;
  1790. }
  1791. return ESUCCESS;
  1792. }
  1793. ARC_STATUS
  1794. BlAmd64CheckForLongMode(
  1795. IN ULONG LoadDeviceId,
  1796. IN OUT PCHAR KernelPath,
  1797. IN PCHAR KernelFileName
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. This routine examines a kernel image and determines whether it was
  1802. compiled for AMD64. The global BlAmd64UseLongMode is set to non-zero
  1803. if a long-mode kernel is discovered.
  1804. Arguments:
  1805. LoadDeviceId - Supplies the load device identifier.
  1806. KernelPath - Supplies a pointer to the path to the kernel directory.
  1807. Upon successful return, KernelFileName will be appended
  1808. to this path.
  1809. KernelFileName - Supplies a pointer to the name of the kernel file.
  1810. Note: If KernelPath already contains the full path and filename of
  1811. the kernel image to check, pass a pointer to "\0" for
  1812. KernelFileName.
  1813. Return Value:
  1814. The status of the operation. Upon successful completion ESUCCESS
  1815. is returned, whether long mode capability was detected or not.
  1816. --*/
  1817. {
  1818. CHAR localBufferSpace[ SECTOR_SIZE * 2 + SECTOR_SIZE - 1 ];
  1819. PCHAR localBuffer;
  1820. ULONG fileId;
  1821. PIMAGE_NT_HEADERS32 ntHeaders;
  1822. ARC_STATUS status;
  1823. ULONG bytesRead;
  1824. PCHAR kernelNameTarget;
  1825. //
  1826. // File I/O here must be sector-aligned.
  1827. //
  1828. localBuffer = (PCHAR)
  1829. (((ULONG)localBufferSpace + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1));
  1830. //
  1831. // Build the path to the kernel and open it.
  1832. //
  1833. kernelNameTarget = KernelPath + strlen(KernelPath);
  1834. strcpy(kernelNameTarget, KernelFileName);
  1835. status = BlOpen( LoadDeviceId, KernelPath, ArcOpenReadOnly, &fileId );
  1836. *kernelNameTarget = '\0'; // Restore the kernel path, assuming
  1837. // failure.
  1838. if (status != ESUCCESS) {
  1839. return status;
  1840. }
  1841. //
  1842. // Read the PE image header
  1843. //
  1844. status = BlRead( fileId, localBuffer, SECTOR_SIZE * 2, &bytesRead );
  1845. BlClose( fileId );
  1846. //
  1847. // Determine whether the image header is valid, and if so whether
  1848. // the image is AMD64, I386 or something else.
  1849. //
  1850. ntHeaders = RtlImageNtHeader( localBuffer );
  1851. if (ntHeaders == NULL) {
  1852. return EBADF;
  1853. }
  1854. if (IMAGE_64BIT(ntHeaders)) {
  1855. //
  1856. // Return with the kernel name appended to the path
  1857. //
  1858. if (BlIsAmd64Supported() != FALSE) {
  1859. strcpy(kernelNameTarget, KernelFileName);
  1860. BlAmd64UseLongMode = TRUE;
  1861. status = ESUCCESS;
  1862. } else {
  1863. //
  1864. // We have an AMD64 image, but the processor does not support
  1865. // AMD64. There is nothing we can do.
  1866. //
  1867. status = EBADF;
  1868. }
  1869. } else if (IMAGE_32BIT(ntHeaders)) {
  1870. ASSERT( BlAmd64UseLongMode == FALSE );
  1871. status = ESUCCESS;
  1872. } else {
  1873. status = EBADF;
  1874. }
  1875. return status;
  1876. }
  1877. ARC_STATUS
  1878. BlAmd64PrepareSystemStructures(
  1879. VOID
  1880. )
  1881. /*++
  1882. Routine Description:
  1883. This routine allocates and initializes several structures necessary
  1884. for transfer to an AMD64 kernel. These structures include:
  1885. GDT
  1886. IDT
  1887. KTSS64
  1888. Idle thread stack
  1889. DPC stack
  1890. Double fault stack
  1891. MCA exception stack
  1892. Arguments:
  1893. None.
  1894. Return Value:
  1895. The status of the operation.
  1896. --*/
  1897. {
  1898. PCHAR processorData;
  1899. ULONG dataSize;
  1900. ULONG descriptor;
  1901. ULONG stackOffset;
  1902. PKTSS64_64 sysTss64;
  1903. PCHAR idleStack;
  1904. PCHAR dpcStack;
  1905. PCHAR doubleFaultStack;
  1906. PCHAR mcaStack;
  1907. PVOID gdt64;
  1908. PVOID idt64;
  1909. ARC_STATUS status;
  1910. //
  1911. // Calculate the cumulative, rounded size of the various structures that
  1912. // we need, and allocate a sufficient number of pages.
  1913. //
  1914. dataSize = ROUNDUP16(GDT_64_SIZE) +
  1915. ROUNDUP16(IDT_64_SIZE) +
  1916. ROUNDUP16(sizeof(KTSS64_64));
  1917. dataSize = ROUNDUP_PAGE(dataSize);
  1918. stackOffset = dataSize;
  1919. dataSize += KERNEL_STACK_SIZE_64 + // Idle thread stack
  1920. KERNEL_STACK_SIZE_64 + // DPC stack
  1921. DOUBLE_FAULT_STACK_SIZE_64 + // Double fault stack
  1922. MCA_EXCEPTION_STACK_SIZE_64; // MCA exception stack
  1923. //
  1924. // dataSize is still page aligned.
  1925. //
  1926. status = BlAllocateDescriptor( LoaderAmd64MemoryData,
  1927. 0,
  1928. dataSize / PAGE_SIZE,
  1929. &descriptor );
  1930. if (status != ESUCCESS) {
  1931. return status;
  1932. }
  1933. processorData = (PCHAR)(descriptor * PAGE_SIZE | KSEG0_BASE_X86);
  1934. //
  1935. // Zero the block that was just allocated, then get local pointers to the
  1936. // various structures within.
  1937. //
  1938. RtlZeroMemory( processorData, dataSize );
  1939. //
  1940. // Assign the stack pointers. Stack pointers start at the TOP of their
  1941. // respective stack areas.
  1942. //
  1943. idleStack = processorData + stackOffset + KERNEL_STACK_SIZE_64;
  1944. dpcStack = idleStack + KERNEL_STACK_SIZE_64;
  1945. doubleFaultStack = dpcStack + DOUBLE_FAULT_STACK_SIZE_64;
  1946. mcaStack = doubleFaultStack + MCA_EXCEPTION_STACK_SIZE_64;
  1947. //
  1948. // Record the idle stack base so that we can switch to it in amd64s.asm
  1949. //
  1950. BlAmd64IdleStack64 = PTR_64(idleStack);
  1951. //
  1952. // Assign pointers to GDT, IDT and KTSS64.
  1953. //
  1954. gdt64 = (PVOID)processorData;
  1955. processorData += ROUNDUP16(GDT_64_SIZE);
  1956. idt64 = (PVOID)processorData;
  1957. processorData += ROUNDUP16(IDT_64_SIZE);
  1958. sysTss64 = (PKTSS64_64)processorData;
  1959. processorData += ROUNDUP16(sizeof(KTSS64_64));
  1960. //
  1961. // Build the GDT. This is done in amd64.c as it involves AMD64
  1962. // structure definitions. The IDT remains zeroed.
  1963. //
  1964. BlAmd64BuildAmd64GDT( sysTss64, gdt64 );
  1965. //
  1966. // Build the pseudo-descriptors for the GDT and IDT. These will
  1967. // be referenced during the long-mode transition in amd64s.asm.
  1968. //
  1969. BlAmd64GdtDescriptor.Limit = (USHORT)(GDT_64_SIZE - 1);
  1970. BlAmd64GdtDescriptor.Base = PTR_64(gdt64);
  1971. BlAmd64IdtDescriptor.Limit = (USHORT)(IDT_64_SIZE - 1);
  1972. BlAmd64IdtDescriptor.Base = PTR_64(idt64);
  1973. //
  1974. // Build another GDT pseudo-descriptor, this one with a 32-bit
  1975. // base. This base address must be a 32-bit address that is addressible
  1976. // from long mode during init, so use the mapping in the identity mapped
  1977. // region.
  1978. //
  1979. BlAmd32GdtDescriptor.Limit = (USHORT)(GDT_64_SIZE - 1);
  1980. BlAmd32GdtDescriptor.Base = (ULONG)gdt64 ^ KSEG0_BASE_X86;
  1981. //
  1982. // Initialize the system TSS
  1983. //
  1984. sysTss64->Rsp0 = PTR_64(idleStack);
  1985. sysTss64->Ist[TSS64_IST_PANIC] = PTR_64(doubleFaultStack);
  1986. sysTss64->Ist[TSS64_IST_MCA] = PTR_64(mcaStack);
  1987. //
  1988. // Fill required fields within the loader block
  1989. //
  1990. BlAmd64LoaderBlock64->KernelStack = PTR_64(dpcStack);
  1991. return ESUCCESS;
  1992. }
  1993. VOID
  1994. BlAmd64ReplaceMemoryDescriptorType(
  1995. IN TYPE_OF_MEMORY Target,
  1996. IN TYPE_OF_MEMORY Replacement,
  1997. IN BOOLEAN Coallesce
  1998. )
  1999. /*++
  2000. Routine Description:
  2001. This routine walks the 32-bit memory allocation descriptor list and
  2002. performs a "search and replace" of the types therein.
  2003. Optionally, it will coallesce each successful replacement with
  2004. adjacent descriptors of like type.
  2005. Arguments:
  2006. Target - The descriptor type to search for
  2007. Replacement - The type with which to replace each located Target type.
  2008. Coallesce - If !FALSE, indicates that each successful replacement should
  2009. be coallesced with any like-typed neighbors.
  2010. Return Value:
  2011. None.
  2012. --*/
  2013. {
  2014. PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
  2015. PMEMORY_ALLOCATION_DESCRIPTOR adjacentDescriptor;
  2016. PLIST_ENTRY listHead;
  2017. PLIST_ENTRY listEntry;
  2018. PLIST_ENTRY adjacentListEntry;
  2019. listHead = &BlAmd64LoaderBlock32->MemoryDescriptorListHead;
  2020. listEntry = listHead;
  2021. while (TRUE) {
  2022. listEntry = listEntry->Flink;
  2023. if (listEntry == listHead) {
  2024. break;
  2025. }
  2026. descriptor = CONTAINING_RECORD(listEntry,
  2027. MEMORY_ALLOCATION_DESCRIPTOR,
  2028. ListEntry);
  2029. if (descriptor->MemoryType != Target) {
  2030. continue;
  2031. }
  2032. descriptor->MemoryType = Replacement;
  2033. if (Coallesce == FALSE) {
  2034. //
  2035. // Do not attempt to coallesce
  2036. //
  2037. continue;
  2038. }
  2039. //
  2040. // Now attempt to coallesce the descriptor. First try the
  2041. // next descriptor.
  2042. //
  2043. adjacentListEntry = listEntry->Flink;
  2044. if (adjacentListEntry != listHead) {
  2045. adjacentDescriptor = CONTAINING_RECORD(adjacentListEntry,
  2046. MEMORY_ALLOCATION_DESCRIPTOR,
  2047. ListEntry);
  2048. if (adjacentDescriptor->MemoryType == descriptor->MemoryType &&
  2049. descriptor->BasePage + descriptor->PageCount ==
  2050. adjacentDescriptor->BasePage) {
  2051. descriptor->PageCount += adjacentDescriptor->PageCount;
  2052. BlRemoveDescriptor(adjacentDescriptor);
  2053. }
  2054. }
  2055. //
  2056. // Now try the previous descriptor.
  2057. //
  2058. adjacentListEntry = listEntry->Blink;
  2059. if (adjacentListEntry != listHead) {
  2060. adjacentDescriptor = CONTAINING_RECORD(adjacentListEntry,
  2061. MEMORY_ALLOCATION_DESCRIPTOR,
  2062. ListEntry);
  2063. if (adjacentDescriptor->MemoryType == descriptor->MemoryType &&
  2064. adjacentDescriptor->BasePage + adjacentDescriptor->PageCount ==
  2065. descriptor->BasePage) {
  2066. descriptor->PageCount += adjacentDescriptor->PageCount;
  2067. descriptor->BasePage -= adjacentDescriptor->PageCount;
  2068. BlRemoveDescriptor(adjacentDescriptor);
  2069. }
  2070. }
  2071. }
  2072. }
  2073. ARC_STATUS
  2074. BlAmd64FixSharedUserPage(
  2075. VOID
  2076. )
  2077. {
  2078. PFN_NUMBER pfn;
  2079. PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
  2080. ARC_STATUS status;
  2081. //
  2082. // The shared user page is allocated as LoaderMemoryData. All
  2083. // LoaderMemoryData descriptors will be converted to LoaderOsloaderHeap
  2084. // during the transition to 64-bit mode, as the assumption is made that
  2085. // all of the old structures will no longer be needed.
  2086. //
  2087. // The shared user page is the exception to this rule, so it must be
  2088. // found and placed into an appropriately marked descriptor.
  2089. //
  2090. //
  2091. // Get the pfn of the shared user page, find its descriptor,
  2092. // carve out a new descriptor that contains just that page and give
  2093. // it a type of LoaderAmd64MemoryData.
  2094. //
  2095. BlAmd64IsPageMapped( KI_USER_SHARED_DATA, &pfn, NULL );
  2096. descriptor = BlFindMemoryDescriptor( pfn );
  2097. status = BlGenerateDescriptor(descriptor,
  2098. LoaderAmd64MemoryData,
  2099. pfn,
  2100. 1);
  2101. return status;
  2102. }
  2103. BOOLEAN
  2104. BlAmd64Setup (
  2105. IN PCHAR SetupDevice
  2106. )
  2107. /*++
  2108. Routine Description:
  2109. This routine determines whether we are installing an I386 or AMD64 build.
  2110. If the directory "\\AMD64" exists at the root of DriveId then it is
  2111. assumed that an AMD64 installation is being performed.
  2112. Arguments:
  2113. SetupDevice - Supplies the ARC path to the setup device. This parameter
  2114. need only be supplied on the first invocation of this routine. The
  2115. result of the first call is cached for subsequent invocations.
  2116. Return Value:
  2117. TRUE - An AMD64 installation is being performed.
  2118. FALSE - An I386 installation is being performed.
  2119. --*/
  2120. {
  2121. ULONG deviceId;
  2122. ULONG dirId;
  2123. ARC_STATUS status;
  2124. static BOOLEAN alreadyDetected = FALSE;
  2125. static BOOLEAN detectedAmd64 = FALSE;
  2126. if (alreadyDetected == FALSE) {
  2127. ASSERT(SetupDevice != NULL);
  2128. status = ArcOpen(SetupDevice, ArcOpenReadOnly, &deviceId);
  2129. if (status == ESUCCESS) {
  2130. status = BlOpen(deviceId, "\\AMD64", ArcOpenDirectory, &dirId);
  2131. if (status == ESUCCESS) {
  2132. detectedAmd64 = TRUE;
  2133. BlClose(dirId);
  2134. }
  2135. ArcClose(deviceId);
  2136. }
  2137. alreadyDetected = TRUE;
  2138. }
  2139. return detectedAmd64;
  2140. }
  2141. VOID
  2142. BlCheckForAmd64Image(
  2143. PPO_MEMORY_IMAGE MemImage
  2144. )
  2145. /*++
  2146. Routine Description:
  2147. This routine determines whether a hibernate file was created for
  2148. Amd64 platform. BlAmd64UseLongMode will be set accordingly.
  2149. Arguments:
  2150. MemImage - Header of hibernate image file.
  2151. Return Value:
  2152. None.
  2153. --*/
  2154. {
  2155. //
  2156. // It is assumed that "version" and "LengthSelf" field can be reference
  2157. // in same way between a x86 and an Amd64 image header.
  2158. //
  2159. if((MemImage->Version == 0) &&
  2160. (MemImage->LengthSelf == sizeof(PO_MEMORY_IMAGE_64))) {
  2161. BlAmd64UseLongMode = TRUE;
  2162. }
  2163. }
  2164. ULONG
  2165. BlAmd64FieldOffset_PO_MEMORY_IMAGE(
  2166. ULONG offset32
  2167. )
  2168. /*++
  2169. Routine Description:
  2170. This routine helps to access 64-bit version of PO_MEMORY_IMAGE from
  2171. its 32-bit definition. It calculates the offset of a field in 64-bit
  2172. definition from the offset of same field in 32-bit definiation.
  2173. Arguments:
  2174. offset32 - Field offset of 32-bit definiation.
  2175. Return Value:
  2176. Field offset of 64-bit definiation.
  2177. --*/
  2178. {
  2179. PCOPY_REC copyRec;
  2180. copyRec = cr3264_PO_MEMORY_IMAGE;
  2181. while (copyRec->Size32 != 0) {
  2182. if (copyRec->Offset32 == offset32) {
  2183. return copyRec->Offset64;
  2184. }
  2185. copyRec++;
  2186. }
  2187. return 0;
  2188. }
  2189. ULONG
  2190. BlAmd64FieldOffset_PO_MEMORY_RANGE_ARRAY_LINK(
  2191. ULONG offset32
  2192. )
  2193. /*++
  2194. Routine Description:
  2195. This routine helps to access 64-bit version of PO_MEMORY_RANGE_ARRAY_LINK
  2196. from its 32-bit definition. It calculates the offset of a field in 64-bit
  2197. definition from the offset of same field in 32-bit definiation.
  2198. Arguments:
  2199. offset32 - Field offset of 32-bit definiation.
  2200. Return Value:
  2201. Field offset of 64-bit definiation.
  2202. --*/
  2203. {
  2204. PCOPY_REC copyRec;
  2205. copyRec = cr3264_PO_MEMORY_RANGE_ARRAY_LINK;
  2206. while (copyRec->Size32 != 0) {
  2207. if (copyRec->Offset32 == offset32) {
  2208. return copyRec->Offset64;
  2209. }
  2210. copyRec++;
  2211. }
  2212. return 0;
  2213. }
  2214. ULONG
  2215. BlAmd64FieldOffset_PO_MEMORY_RANGE_ARRAY_RANGE(
  2216. ULONG offset32
  2217. )
  2218. /*++
  2219. Routine Description:
  2220. This routine helps to access 64-bit version of PO_MEMORY_RANGE_ARRAY_RANGE
  2221. from its 32-bit definition. It calculates the offset of a field in 64-bit
  2222. definition from the offset of same field in 32-bit definiation.
  2223. Arguments:
  2224. offset32 - Field offset of 32-bit definiation.
  2225. Return Value:
  2226. Field offset of 64-bit definiation.
  2227. --*/
  2228. {
  2229. PCOPY_REC copyRec;
  2230. copyRec = cr3264_PO_MEMORY_RANGE_ARRAY_RANGE;
  2231. while (copyRec->Size32 != 0) {
  2232. if (copyRec->Offset32 == offset32) {
  2233. return copyRec->Offset64;
  2234. }
  2235. copyRec++;
  2236. }
  2237. return 0;
  2238. }
  2239. ULONG
  2240. BlAmd64ElementOffset_PO_MEMORY_RANGE_ARRAY_LINK(
  2241. ULONG index
  2242. )
  2243. /*++
  2244. Routine Description:
  2245. This routine calculates the offset of a element in a structure array.
  2246. Each element in this array is defined as PO_MORY_RANGE_ARRAY_LINK in
  2247. it 64-bit format.
  2248. Arguments:
  2249. index - Supplies the index of a element.
  2250. Return Value:
  2251. Offset of the element from base address of the array.
  2252. --*/
  2253. {
  2254. return (ULONG)(&(((PO_MEMORY_RANGE_ARRAY_LINK_64 *)0)[index]));
  2255. }
  2256. ULONG
  2257. BlAmd64ElementOffset_PO_MEMORY_RANGE_ARRAY_RANGE(
  2258. ULONG index
  2259. )
  2260. /*++
  2261. Routine Description:
  2262. This routine calculates the offset of a element in a structure array.
  2263. Each element in this array is defined as PO_MEMORY_RANGE_ARRAY_RANGE
  2264. in its 64-bit format.
  2265. Arguments:
  2266. index - Supplies the index of a element.
  2267. Return Value:
  2268. Offset of the element from base address of the array.
  2269. --*/
  2270. {
  2271. return (ULONG)(&(((PO_MEMORY_RANGE_ARRAY_RANGE_64 *)0)[index]));
  2272. }
  2273. #define BL_ENABLE_REMAP
  2274. #if defined(BL_ENABLE_REMAP)
  2275. #include "hammernb.h"
  2276. #include "acpitabl.h"
  2277. #include "pci.h"
  2278. #include "ntacpi.h"
  2279. #if !defined(_4G)
  2280. #define _4G (1UI64 << 32)
  2281. #endif
  2282. extern PRSDP BlRsdp;
  2283. extern PRSDT BlRsdt;
  2284. extern PXSDT BlXsdt;
  2285. BOOLEAN
  2286. BlAmd64GetNode1Info (
  2287. OUT ULONG *Base,
  2288. OUT ULONG *Size
  2289. );
  2290. BOOLEAN
  2291. BlAmd64RelocateAcpi (
  2292. ULONG Node0Base,
  2293. ULONG Node0Limit,
  2294. ULONG Node1Base,
  2295. ULONG Node1Limit
  2296. );
  2297. BOOLEAN
  2298. BlAmd64RemapMTRRs (
  2299. IN ULONG OldBase,
  2300. IN ULONG NewBase,
  2301. IN ULONG Size
  2302. );
  2303. BOOLEAN
  2304. BlAmd64RemapNode1Dram (
  2305. IN ULONG NewBase
  2306. );
  2307. ULONG
  2308. StringToUlong (
  2309. IN PCHAR String
  2310. );
  2311. BOOLEAN
  2312. BlAmd64RemapDram (
  2313. IN PCHAR LoaderOptions
  2314. )
  2315. /*++
  2316. Routine Description:
  2317. This routine looks for the /RELOCATEPHYSICAL= switch supplied as a loader
  2318. option. The option directs the loader to relocate node 1's physical memory
  2319. to the address supplied.
  2320. The address represents the new physical memory base in 1GB units.
  2321. For example, to relocate node 1's physical memory to 128GB, use:
  2322. /RELOCATEPHYSICAL=128
  2323. Arguments:
  2324. LoaderOptions - Supplies a pointer to the loader option string
  2325. Return Value:
  2326. TRUE if the relocation was performed, FALSE otherwise
  2327. --*/
  2328. {
  2329. BOOLEAN result;
  2330. ULONG oldBase;
  2331. ULONG oldLimit;
  2332. ULONG newBase;
  2333. ULONG newBasePage;
  2334. ULONG size;
  2335. PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
  2336. PLIST_ENTRY listHead;
  2337. PLIST_ENTRY listEntry;
  2338. ULONG descriptorBase;
  2339. ULONG descriptorLimit;
  2340. ARC_STATUS status;
  2341. PCHAR pch;
  2342. ULONG type;
  2343. newBase = 0;
  2344. if (LoaderOptions != NULL) {
  2345. pch = strstr(LoaderOptions,"RELOCATEPHYSICAL=");
  2346. if (pch != NULL) {
  2347. newBase = StringToUlong( pch + strlen( "RELOCATEPHYSICAL=" ));
  2348. }
  2349. }
  2350. if (newBase == 0) {
  2351. return FALSE;
  2352. }
  2353. //
  2354. // The parameter is supplied in GB, convert to 16MB chunks for internal
  2355. // use
  2356. //
  2357. newBase *= 64;
  2358. //
  2359. // Determine the chunk of physical memory associated with node 1.
  2360. // Note that this routine will relocate the ACPI tables if a suitable
  2361. // node 1 bridge device was found.
  2362. //
  2363. result = BlAmd64GetNode1Info( &oldBase, &size );
  2364. if (result == FALSE) {
  2365. return FALSE;
  2366. }
  2367. newBasePage = newBase << (24 - 12);
  2368. oldLimit = oldBase + size - 1;
  2369. //
  2370. // Make sure that the descriptors describing that physical memory
  2371. // haven't already been allocated. Acceptable descriptor
  2372. // types are Free, LoaderReserve and SpecialMemory.
  2373. //
  2374. listHead = &BlLoaderBlock->MemoryDescriptorListHead;
  2375. listEntry = listHead->Flink;
  2376. while (listEntry != listHead) {
  2377. descriptor = CONTAINING_RECORD(listEntry,
  2378. MEMORY_ALLOCATION_DESCRIPTOR,
  2379. ListEntry);
  2380. descriptorBase = descriptor->BasePage;
  2381. descriptorLimit = descriptorBase + descriptor->PageCount - 1;
  2382. if ((descriptorBase <= oldLimit) && (descriptorLimit >= oldBase)) {
  2383. //
  2384. // Some or all of this memory descriptor lies within the
  2385. // relocated region.
  2386. //
  2387. if (descriptor->MemoryType != LoaderFree &&
  2388. descriptor->MemoryType != LoaderSpecialMemory &&
  2389. descriptor->MemoryType != LoaderReserve) {
  2390. return FALSE;
  2391. }
  2392. }
  2393. listEntry = listEntry->Flink;
  2394. }
  2395. //
  2396. // From the loader perspective everything looks good, perform the remap.
  2397. //
  2398. result = BlAmd64RemapNode1Dram( newBase );
  2399. if (result == FALSE) {
  2400. return FALSE;
  2401. }
  2402. //
  2403. // The bridge(s) have been reprogrammed. Now walk the memory descriptor
  2404. // lists, performing necessary relocations.
  2405. //
  2406. listHead = &BlLoaderBlock->MemoryDescriptorListHead;
  2407. listEntry = listHead->Flink;
  2408. while (listEntry != listHead) {
  2409. descriptor = CONTAINING_RECORD(listEntry,
  2410. MEMORY_ALLOCATION_DESCRIPTOR,
  2411. ListEntry);
  2412. descriptorBase = descriptor->BasePage;
  2413. descriptorLimit = descriptorBase + descriptor->PageCount - 1;
  2414. if ((descriptorBase <= oldLimit) && (descriptorLimit >= oldBase)) {
  2415. //
  2416. // Some or all of this memory descriptor lies within the
  2417. // relocated region.
  2418. //
  2419. if (descriptorBase >= oldBase && descriptorLimit <= oldLimit) {
  2420. //
  2421. // The descriptor lies entirely within the relocation range
  2422. // so relocate the whole thing.
  2423. //
  2424. } else {
  2425. //
  2426. // Only part of the descriptor lies within the relocation
  2427. // range, so a new descriptor must be allocated.
  2428. //
  2429. if (descriptorBase < oldBase) {
  2430. descriptorBase = oldBase;
  2431. }
  2432. if (descriptorLimit > oldLimit) {
  2433. descriptorLimit = oldLimit;
  2434. }
  2435. type = descriptor->MemoryType;
  2436. status = BlGenerateDescriptor( descriptor,
  2437. LoaderSpecialMemory,
  2438. descriptorBase,
  2439. descriptorLimit - descriptorBase + 1 );
  2440. ASSERT(status == ESUCCESS);
  2441. listEntry = listEntry->Flink;
  2442. descriptor = CONTAINING_RECORD(listEntry,
  2443. MEMORY_ALLOCATION_DESCRIPTOR,
  2444. ListEntry);
  2445. descriptor->MemoryType = type;
  2446. }
  2447. listEntry = listEntry->Flink;
  2448. BlRemoveDescriptor( descriptor );
  2449. descriptor->BasePage = descriptor->BasePage - oldBase + newBasePage;
  2450. BlInsertDescriptor( descriptor );
  2451. } else {
  2452. listEntry = listEntry->Flink;
  2453. }
  2454. }
  2455. //
  2456. // Recalculate BlHighestPage
  2457. //
  2458. BlHighestPage = 0;
  2459. listHead = &BlLoaderBlock->MemoryDescriptorListHead;
  2460. listEntry = listHead->Flink;
  2461. while (listEntry != listHead) {
  2462. descriptor = CONTAINING_RECORD(listEntry,
  2463. MEMORY_ALLOCATION_DESCRIPTOR,
  2464. ListEntry);
  2465. descriptorBase = descriptor->BasePage;
  2466. descriptorLimit = descriptorBase + descriptor->PageCount - 1;
  2467. if (descriptor->MemoryType != LoaderSpecialMemory &&
  2468. descriptor->MemoryType != LoaderReserve &&
  2469. descriptorLimit > BlHighestPage) {
  2470. BlHighestPage = descriptorLimit;
  2471. }
  2472. listEntry = listEntry->Flink;
  2473. }
  2474. //
  2475. // Remap the MTRRs
  2476. //
  2477. result = BlAmd64RemapMTRRs( oldBase, newBase, oldLimit - oldBase + 1 );
  2478. if (result == FALSE) {
  2479. return FALSE;
  2480. }
  2481. return TRUE;
  2482. }
  2483. ULONG
  2484. StringToUlong (
  2485. IN PCHAR String
  2486. )
  2487. /*++
  2488. Routine Description:
  2489. This routine converts a hexadecimal or decimal string to
  2490. a 32-bit unsigned integer.
  2491. Arguments:
  2492. String - Supplies a null-terminated ASCII string in decimal or
  2493. hexadecimal format.
  2494. 01234567 - decimal format
  2495. 0x01234567 - hexadecimal format
  2496. The input string is processed until an invalid character or
  2497. the end of the string is encountered.
  2498. Return Value:
  2499. Returns the value of the parsed string.
  2500. --*/
  2501. {
  2502. CHAR ch;
  2503. PCHAR pch;
  2504. ULONG result;
  2505. int radix;
  2506. UCHAR digit;
  2507. pch = String;
  2508. result = 0;
  2509. radix = 10;
  2510. while (TRUE) {
  2511. ch = (char)toupper(*pch);
  2512. if ((ch >= '0' && ch <= '9') ||
  2513. (ch >= 'A' && ch <= 'F')) {
  2514. if (ch >= '0' && ch <= '9') {
  2515. digit = ch - '0';
  2516. } else {
  2517. digit = ch - 'A' + 10;
  2518. }
  2519. result = result * radix + digit;
  2520. } else if (ch == 'X') {
  2521. if (result == 0) {
  2522. radix = 16;
  2523. } else {
  2524. break;
  2525. }
  2526. } else {
  2527. break;
  2528. }
  2529. pch += 1;
  2530. }
  2531. return result;
  2532. }
  2533. BOOLEAN
  2534. BlAmd64RemapNode1Dram (
  2535. IN ULONG NewBase
  2536. )
  2537. /*++
  2538. Routine Description:
  2539. Relocates node 1 memory to a new physical address and reprograms
  2540. MSRs related to the physical memory map.
  2541. Arguments:
  2542. NewBase - Supplies bits [39:24] of the desired new physical base address
  2543. of the memory associated with node 1.
  2544. Return Value:
  2545. TRUE if the operation was successful, FALSE otherwise.
  2546. --*/
  2547. {
  2548. AMD_NB_FUNC1_CONFIG nodeConfigArray[8];
  2549. PAMD_NB_FUNC1_CONFIG nodeConfig;
  2550. PAMD_NB_DRAM_MAP dramMap;
  2551. ULONG length;
  2552. PCI_SLOT_NUMBER slotNumber;
  2553. ULONG nodeCount;
  2554. ULONG nodeIndex;
  2555. ULONG span;
  2556. ULONG oldBase;
  2557. ULONG oldLimit;
  2558. ULONG newLimit;
  2559. ULONG64 topMem;
  2560. ULONG64 topMem4G;
  2561. ULONG64 msrValue;
  2562. ULONG64 base64;
  2563. ULONG64 limit64;
  2564. //
  2565. // NewBase supplies the new DRAM base[39:24]
  2566. //
  2567. nodeCount = 0;
  2568. nodeConfig = nodeConfigArray;
  2569. do {
  2570. slotNumber.u.AsULONG = 0;
  2571. slotNumber.u.bits.DeviceNumber = NB_DEVICE_BASE + nodeCount;
  2572. slotNumber.u.bits.FunctionNumber = 1;
  2573. length = HalGetBusDataByOffset( PCIConfiguration,
  2574. 0,
  2575. slotNumber.u.AsULONG,
  2576. nodeConfig,
  2577. 0,
  2578. sizeof(*nodeConfig) );
  2579. if (length != sizeof(*nodeConfig)) {
  2580. break;
  2581. }
  2582. if (BlAmd64ValidateBridgeDevice( nodeConfig ) == FALSE) {
  2583. break;
  2584. }
  2585. #if 0
  2586. for (mapIndex = 0; mapIndex < 8; mapIndex += 1) {
  2587. if (nodeConfig->DRAMMap[mapIndex].ReadEnable != 0) {
  2588. limit = nodeConfig->DRAMMap[mapIndex].Limit;
  2589. if (limit > NewBase) {
  2590. //
  2591. // The new base was found to conflict with existing
  2592. // ram.
  2593. //
  2594. return FALSE;
  2595. }
  2596. }
  2597. }
  2598. #endif
  2599. nodeCount += 1;
  2600. nodeConfig += 1;
  2601. } while (nodeCount <= 8);
  2602. if (nodeCount < 2) {
  2603. //
  2604. // This remap can only be performed on systems with more than
  2605. // two nodes.
  2606. //
  2607. return FALSE;
  2608. }
  2609. //
  2610. // We always remap the second node's memory (node 1).
  2611. //
  2612. nodeConfig = nodeConfigArray;
  2613. dramMap = &nodeConfig->DRAMMap[1];
  2614. oldBase = dramMap->Base;
  2615. oldLimit = dramMap->Limit;
  2616. span = oldLimit - oldBase;
  2617. newLimit = NewBase + span;
  2618. for (nodeIndex = 0; nodeIndex < nodeCount; nodeIndex += 1) {
  2619. ASSERT(dramMap->Base == oldBase);
  2620. ASSERT(dramMap->Limit == oldLimit);
  2621. dramMap->Base = NewBase;
  2622. dramMap->Limit = newLimit;
  2623. slotNumber.u.AsULONG = 0;
  2624. slotNumber.u.bits.DeviceNumber = NB_DEVICE_BASE + nodeIndex;
  2625. slotNumber.u.bits.FunctionNumber = 1;
  2626. length = HalSetBusDataByOffset( PCIConfiguration,
  2627. 0,
  2628. slotNumber.u.AsULONG,
  2629. dramMap,
  2630. FIELD_OFFSET(AMD_NB_FUNC1_CONFIG,DRAMMap[1]),
  2631. sizeof(*dramMap) );
  2632. if (length != sizeof(*dramMap)) {
  2633. //
  2634. // We may be severely hosed here, if we have already
  2635. // reprogrammed some of the bridges.
  2636. //
  2637. return FALSE;
  2638. }
  2639. nodeConfig += 1;
  2640. dramMap = &nodeConfig->DRAMMap[1];
  2641. }
  2642. //
  2643. // Determine the address of the last byte of ram under 4G and the last
  2644. // byte of ram overall.
  2645. //
  2646. topMem = 0;
  2647. topMem4G = 0;
  2648. for (nodeIndex = 0; nodeIndex < nodeCount; nodeIndex += 1) {
  2649. base64 = nodeConfigArray[0].DRAMMap[nodeIndex].Base;
  2650. base64 <<= 24;
  2651. limit64 = nodeConfigArray[0].DRAMMap[nodeIndex].Limit;
  2652. limit64 = (limit64 + 1) << 24;
  2653. if (base64 < _4G) {
  2654. if (topMem4G < limit64) {
  2655. topMem4G = limit64;
  2656. }
  2657. }
  2658. if (topMem < limit64) {
  2659. topMem = limit64;
  2660. }
  2661. }
  2662. //
  2663. // Indicate whether a memory hole exists below 4G.
  2664. //
  2665. if (topMem4G < _4G) {
  2666. msrValue = RDMSR(MSR_TOP_MEM);
  2667. WRMSR(MSR_TOP_MEM,topMem4G & MSR_TOP_MEM_MASK);
  2668. }
  2669. //
  2670. // If memory above _4G was located then enable and program TOP_MEM_2
  2671. //
  2672. if (topMem > _4G) {
  2673. msrValue = RDMSR(MSR_SYSCFG);
  2674. msrValue |= SYSCFG_MTRRTOM2EN;
  2675. WRMSR(MSR_TOP_MEM_2, topMem & MSR_TOP_MEM_MASK);
  2676. WRMSR(MSR_SYSCFG,msrValue);
  2677. }
  2678. return TRUE;
  2679. }
  2680. BOOLEAN
  2681. BlAmd64GetNode1Info (
  2682. OUT ULONG *Base,
  2683. OUT ULONG *Size
  2684. )
  2685. /*++
  2686. Routine Description:
  2687. This routine determines the configuration of the block of physical
  2688. memory associated with node 1 (the second northbridge).
  2689. It also relocates the ACPI tables in node 1 to memory in node 0.
  2690. Arguments:
  2691. Base - supplies a pointer to the location in which to store the base
  2692. PFN of the node 1 memory block.
  2693. Size - supplies a pointer to the location in which to store the size,
  2694. in pages, of the node 1 memory block.
  2695. Return Value:
  2696. TRUE - A suitable second northbridge was found and the ACPI tables therein
  2697. were relocated if necessary.
  2698. FALSE - A suitable second northbridge was not found.
  2699. --*/
  2700. {
  2701. AMD_NB_FUNC1_CONFIG nodeConfig;
  2702. PCI_SLOT_NUMBER slotNumber;
  2703. ULONG length;
  2704. ULONG base;
  2705. ULONG size;
  2706. ULONG node0Base;
  2707. ULONG node0Size;
  2708. //
  2709. // Get the configuration of northbridge 1.
  2710. //
  2711. slotNumber.u.AsULONG = 0;
  2712. slotNumber.u.bits.DeviceNumber = NB_DEVICE_BASE + 1;
  2713. slotNumber.u.bits.FunctionNumber = 1;
  2714. length = HalGetBusDataByOffset( PCIConfiguration,
  2715. 0,
  2716. slotNumber.u.AsULONG,
  2717. &nodeConfig,
  2718. 0,
  2719. sizeof(nodeConfig) );
  2720. if (length != sizeof(nodeConfig)) {
  2721. return FALSE;
  2722. }
  2723. if (BlAmd64ValidateBridgeDevice( &nodeConfig ) == FALSE) {
  2724. return FALSE;
  2725. }
  2726. //
  2727. // A second northbridge exists, the relocation can be performed.
  2728. //
  2729. base = nodeConfig.DRAMMap[1].Base;
  2730. size = nodeConfig.DRAMMap[1].Limit - base + 1;
  2731. *Base = base << (24 - 12);
  2732. *Size = size << (24 - 12);
  2733. node0Base = nodeConfig.DRAMMap[0].Base;
  2734. node0Size = nodeConfig.DRAMMap[0].Limit - node0Base + 1;
  2735. node0Base <<= (24 - 12);
  2736. node0Size <<= (24 - 12);
  2737. BlAmd64RelocateAcpi( node0Base,
  2738. node0Base + node0Size - 1,
  2739. *Base,
  2740. *Base + *Size - 1 );
  2741. return TRUE;
  2742. }
  2743. BOOLEAN
  2744. BlAmd64RemapMTRRs (
  2745. IN ULONG OldBase,
  2746. IN ULONG NewBase,
  2747. IN ULONG Size
  2748. )
  2749. /*++
  2750. Routine Description:
  2751. Arguments:
  2752. Return Value:
  2753. --*/
  2754. {
  2755. //
  2756. // All parameters expressed in pages
  2757. //
  2758. ULONG mtrrCount;
  2759. ULONG index;
  2760. MTRR_CAPABILITIES mtrrCapabilities;
  2761. PMTRR_VARIABLE_BASE baseArray;
  2762. PMTRR_VARIABLE_MASK maskArray;
  2763. ULONG allocationSize;
  2764. UNREFERENCED_PARAMETER(Size);
  2765. UNREFERENCED_PARAMETER(OldBase);
  2766. UNREFERENCED_PARAMETER(NewBase);
  2767. //
  2768. // Determine how many variable MTRRs are supported and
  2769. // allocate enough storage for all of them
  2770. //
  2771. mtrrCapabilities.QuadPart = RDMSR(MTRR_MSR_CAPABILITIES);
  2772. mtrrCount = (ULONG)mtrrCapabilities.Vcnt;
  2773. allocationSize = sizeof(*baseArray) * mtrrCount * 2;
  2774. baseArray = _alloca(allocationSize);
  2775. maskArray = (PMTRR_VARIABLE_MASK)(baseArray + mtrrCount);
  2776. RtlZeroMemory(baseArray,allocationSize);
  2777. //
  2778. // Read the variable MTRRSs. At the same time, look for the
  2779. // MTRR register that contains the old region, and a free
  2780. // one as well.
  2781. //
  2782. for (index = 0; index < mtrrCount; index += 1) {
  2783. baseArray[index].QuadPart = RDMSR(MTRR_MSR_VARIABLE_BASE + index * 2);
  2784. maskArray[index].QuadPart = RDMSR(MTRR_MSR_VARIABLE_MASK + index * 2);
  2785. }
  2786. //
  2787. // For now just clear the mask bits in MTRR register 0. This expands the
  2788. // first MTRR region so that it covers all memory.
  2789. //
  2790. maskArray[0].Mask = 0;
  2791. //
  2792. // Now reprogram the modified MTRR table
  2793. //
  2794. for (index = 0; index < mtrrCount; index += 1) {
  2795. WRMSR(MTRR_MSR_VARIABLE_BASE + index * 2,baseArray[index].QuadPart);
  2796. WRMSR(MTRR_MSR_VARIABLE_MASK + index * 2,maskArray[index].QuadPart);
  2797. }
  2798. return TRUE;
  2799. }
  2800. BOOLEAN
  2801. BlAmd64UpdateAcpiConfigurationEntry (
  2802. ULONG NewPhysical
  2803. )
  2804. /*++
  2805. Routine Description:
  2806. NTDETECT located the physical pointer to the ACPI RSDT table and passed it
  2807. up as a configuration node.
  2808. This routine finds that configuration node and replaces the physical address
  2809. therein with a new address.
  2810. This routine would be called after relocating the ACPI tables.
  2811. Arguments:
  2812. NewPhysical - Supplies the new physical address of the relocated ACPI tables.
  2813. Return Value:
  2814. TRUE if the relocation was performed, FALSE otherwise.
  2815. --*/
  2816. {
  2817. PCONFIGURATION_COMPONENT_DATA component;
  2818. PCONFIGURATION_COMPONENT_DATA resume;
  2819. PCM_PARTIAL_RESOURCE_LIST prl;
  2820. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  2821. PACPI_BIOS_MULTI_NODE rsdp;
  2822. resume = NULL;
  2823. while (TRUE) {
  2824. component = KeFindConfigurationNextEntry( BlLoaderBlock->ConfigurationRoot,
  2825. AdapterClass,
  2826. MultiFunctionAdapter,
  2827. NULL,
  2828. &resume );
  2829. if (component == NULL) {
  2830. return FALSE;
  2831. }
  2832. if (strcmp(component->ComponentEntry.Identifier,"ACPI BIOS") == 0) {
  2833. break;
  2834. }
  2835. resume = component;
  2836. }
  2837. prl = (PCM_PARTIAL_RESOURCE_LIST)component->ConfigurationData;
  2838. prd = prl->PartialDescriptors;
  2839. rsdp = (PACPI_BIOS_MULTI_NODE)(prd + 1);
  2840. rsdp->RsdtAddress.QuadPart = NewPhysical;
  2841. return TRUE;
  2842. }
  2843. BOOLEAN
  2844. BlAmd64RelocateAcpi (
  2845. ULONG Node0Base,
  2846. ULONG Node0Limit,
  2847. ULONG Node1Base,
  2848. ULONG Node1Limit
  2849. )
  2850. /*++
  2851. Routine Description:
  2852. This routine looks for ACPI tables within node 1's physical memory and,
  2853. if found, relocates them to node 0 memory.
  2854. Arguments:
  2855. Node0Base - Supplies the lowest PFN of node 0 memory
  2856. Node0Limit - Supplies the highest PFN of node 0 memory
  2857. Node1Base - Supplies the lowest PFN of node 1 memory (before relocation)
  2858. Node1Limit - Supplies the highest PFN of node 1 memory (before relocation)
  2859. Return Value:
  2860. Returns TRUE if successful, FALSE if a problem was encountered.
  2861. --*/
  2862. {
  2863. ULONG oldRsdtPhysical;
  2864. ULONG oldRsdtPhysicalPage;
  2865. ULONG newBasePage;
  2866. ULONG descriptorSize;
  2867. PLIST_ENTRY listHead;
  2868. PLIST_ENTRY listEntry;
  2869. PMEMORY_ALLOCATION_DESCRIPTOR oldAcpiDescriptor;
  2870. PMEMORY_ALLOCATION_DESCRIPTOR newAcpiDescriptor;
  2871. PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
  2872. PCHAR oldAcpiVa;
  2873. PCHAR newAcpiVa;
  2874. PHYSICAL_ADDRESS physicalAddress;
  2875. ULONG vaBias;
  2876. PDESCRIPTION_HEADER descriptionHeader;
  2877. ULONG physAddr;
  2878. PFADT fadt;
  2879. ARC_STATUS status;
  2880. ULONG index;
  2881. ULONG rsdtPhysical;
  2882. ULONG rsdtLength;
  2883. //
  2884. // Add physicalBias to an ACPI physical pointer to relocate it
  2885. //
  2886. ULONG physicalBias;
  2887. oldRsdtPhysical = BlRsdp->RsdtAddress;
  2888. oldRsdtPhysicalPage = oldRsdtPhysical >> PAGE_SHIFT;
  2889. //
  2890. // Determine whether the descriptor resides in node 1's physical memory.
  2891. // If it does not then it does not need to be relocated.
  2892. //
  2893. if (oldRsdtPhysicalPage < Node1Base ||
  2894. oldRsdtPhysicalPage > Node1Limit) {
  2895. return TRUE;
  2896. }
  2897. //
  2898. // Find the descriptor that contains the ACPI tables
  2899. //
  2900. oldAcpiDescriptor = BlFindMemoryDescriptor( oldRsdtPhysicalPage );
  2901. //
  2902. // Find a descriptor in node 0 memory that is suitable for
  2903. // allocating the new ACPI tables from
  2904. //
  2905. listHead = &BlLoaderBlock->MemoryDescriptorListHead;
  2906. listEntry = listHead->Blink;
  2907. while (TRUE) {
  2908. descriptor = CONTAINING_RECORD(listEntry,
  2909. MEMORY_ALLOCATION_DESCRIPTOR,
  2910. ListEntry);
  2911. if ((descriptor->MemoryType == LoaderReserve) &&
  2912. (descriptor->BasePage > Node0Base) &&
  2913. ((descriptor->BasePage + oldAcpiDescriptor->PageCount) < Node0Limit)) {
  2914. break;
  2915. }
  2916. listEntry = listEntry->Blink;
  2917. if (listEntry == listHead) {
  2918. return FALSE;
  2919. }
  2920. }
  2921. //
  2922. // Carve out the new ACPI descriptor
  2923. //
  2924. newBasePage = Node0Limit - oldAcpiDescriptor->PageCount + 1;
  2925. if ((newBasePage + oldAcpiDescriptor->PageCount) >
  2926. (descriptor->BasePage + descriptor->PageCount)) {
  2927. newBasePage = descriptor->BasePage +
  2928. descriptor->PageCount -
  2929. oldAcpiDescriptor->PageCount;
  2930. }
  2931. status = BlGenerateDescriptor( descriptor,
  2932. LoaderSpecialMemory,
  2933. newBasePage,
  2934. oldAcpiDescriptor->PageCount );
  2935. ASSERT( status == ESUCCESS );
  2936. newAcpiDescriptor = BlFindMemoryDescriptor( newBasePage );
  2937. ASSERT( newAcpiDescriptor != NULL );
  2938. //
  2939. // Unmap the old RSDT
  2940. //
  2941. MmUnmapIoSpace( BlRsdt, BlRsdt->Header.Length );
  2942. //
  2943. // Map both descriptors, copy data from new to old, then unmap
  2944. // and free the old descriptor.
  2945. //
  2946. descriptorSize = oldAcpiDescriptor->PageCount << PAGE_SHIFT;
  2947. physicalAddress.QuadPart = oldAcpiDescriptor->BasePage << PAGE_SHIFT;
  2948. oldAcpiVa = MmMapIoSpace (physicalAddress, descriptorSize, MmCached);
  2949. physicalAddress.QuadPart = newAcpiDescriptor->BasePage << PAGE_SHIFT;
  2950. newAcpiVa = MmMapIoSpace (physicalAddress, descriptorSize, MmCached);
  2951. RtlCopyMemory( newAcpiVa, oldAcpiVa, descriptorSize );
  2952. MmUnmapIoSpace( oldAcpiVa, descriptorSize );
  2953. oldAcpiDescriptor->MemoryType = LoaderReserve;
  2954. //
  2955. // Now thunk the new ACPI tables.
  2956. //
  2957. physicalBias = (newAcpiDescriptor->BasePage - oldAcpiDescriptor->BasePage) << PAGE_SHIFT;
  2958. vaBias = (ULONG)newAcpiVa - (newAcpiDescriptor->BasePage << PAGE_SHIFT);
  2959. #define PHYS_TO_VA(p) (PVOID)(p + vaBias)
  2960. rsdtPhysical = BlRsdp->RsdtAddress + physicalBias;
  2961. BlRsdp->RsdtAddress = rsdtPhysical;
  2962. ASSERT(BlXsdt == NULL);
  2963. BlRsdt = (PRSDT)PHYS_TO_VA(rsdtPhysical);
  2964. //
  2965. // Thunk the phys mem pointer array at the end of the RSDT
  2966. //
  2967. for (index = 0; index < NumTableEntriesFromRSDTPointer(BlRsdt); index += 1) {
  2968. physAddr = BlRsdt->Tables[index];
  2969. physAddr += physicalBias;
  2970. BlRsdt->Tables[index] = physAddr;
  2971. //
  2972. // Look for tables that themselves have physical pointers that require thunking
  2973. //
  2974. descriptionHeader = (PDESCRIPTION_HEADER)(PHYS_TO_VA(physAddr));
  2975. if (descriptionHeader->Signature == FADT_SIGNATURE) {
  2976. fadt = (PFADT)descriptionHeader;
  2977. fadt->facs += physicalBias;
  2978. fadt->dsdt += physicalBias;
  2979. }
  2980. }
  2981. //
  2982. // Now unmap the ACPI tables and remap just the RSDT table
  2983. //
  2984. rsdtLength = BlRsdt->Header.Length;
  2985. MmUnmapIoSpace( newAcpiVa, descriptorSize );
  2986. physicalAddress.QuadPart = rsdtPhysical;
  2987. BlRsdt = MmMapIoSpace( physicalAddress, rsdtLength, MmCached );
  2988. //
  2989. // Find the ACPI BIOS configuration entry and update it with the new
  2990. // RSDT physical address
  2991. //
  2992. BlAmd64UpdateAcpiConfigurationEntry( rsdtPhysical );
  2993. //
  2994. // That's it.
  2995. //
  2996. return TRUE;
  2997. }
  2998. #else // BL_ENABLE_REMAP
  2999. BOOLEAN
  3000. BlAmd64RemapDram (
  3001. IN PCHAR LoaderOptions
  3002. )
  3003. {
  3004. return FALSE;
  3005. }
  3006. #endif // BL_ENABLE_REMAP