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

2855 lines
64 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. #define WANT_BLDRTHNK_FUNCTIONS
  23. #define COPYBUF_MALLOC BlAllocateHeap
  24. #include <amd64thk.h>
  25. #define IMAGE_DEFINITIONS 0
  26. #include <ximagdef.h>
  27. //
  28. // Private, tempory memory descriptor type
  29. //
  30. #define LoaderAmd64MemoryData (LoaderMaximum + 10)
  31. //
  32. // Array of 64-bit memory descriptors
  33. //
  34. PMEMORY_ALLOCATION_DESCRIPTOR_64 BlAmd64DescriptorArray;
  35. LONG BlAmd64DescriptorArraySize;
  36. //
  37. // Forward declarations for functions local to this module
  38. //
  39. ARC_STATUS
  40. BlAmd64AllocateMemoryAllocationDescriptors(
  41. VOID
  42. );
  43. ARC_STATUS
  44. BlAmd64BuildLdrDataTableEntry64(
  45. IN PLDR_DATA_TABLE_ENTRY DataTableEntry32,
  46. OUT PLDR_DATA_TABLE_ENTRY_64 *DataTableEntry64
  47. );
  48. ARC_STATUS
  49. BlAmd64BuildLoaderBlock64(
  50. VOID
  51. );
  52. ARC_STATUS
  53. BlAmd64BuildLoaderBlockExtension64(
  54. VOID
  55. );
  56. ARC_STATUS
  57. BlAmd64BuildMappingPhase1(
  58. VOID
  59. );
  60. ARC_STATUS
  61. BlAmd64BuildMappingPhase2(
  62. VOID
  63. );
  64. ARC_STATUS
  65. BlAmd64BuildMappingWorker(
  66. VOID
  67. );
  68. BOOLEAN
  69. BlAmd64ContainsResourceList(
  70. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  71. OUT PULONG ResourceListSize64
  72. );
  73. BOOLEAN
  74. BlAmd64IsPageMapped(
  75. IN ULONG Va,
  76. OUT PFN_NUMBER *Pfn,
  77. OUT PBOOLEAN PageTableMapped
  78. );
  79. ARC_STATUS
  80. BlAmd64PrepareSystemStructures(
  81. VOID
  82. );
  83. VOID
  84. BlAmd64ReplaceMemoryDescriptorType(
  85. IN TYPE_OF_MEMORY Target,
  86. IN TYPE_OF_MEMORY Replacement,
  87. IN BOOLEAN Coallesce
  88. );
  89. VOID
  90. BlAmd64ResetPageTableHeap(
  91. VOID
  92. );
  93. VOID
  94. BlAmd64SwitchToLongMode(
  95. VOID
  96. );
  97. ARC_STATUS
  98. BlAmd64TransferArcDiskInformation(
  99. VOID
  100. );
  101. ARC_STATUS
  102. BlAmd64TransferBootDriverNodes(
  103. VOID
  104. );
  105. ARC_STATUS
  106. BlAmd64TransferConfigurationComponentData(
  107. VOID
  108. );
  109. PCONFIGURATION_COMPONENT_DATA_64
  110. BlAmd64TransferConfigWorker(
  111. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  112. IN PCONFIGURATION_COMPONENT_DATA_64 ComponentDataParent64
  113. );
  114. ARC_STATUS
  115. BlAmd64TransferHardwareIdList(
  116. IN PPNP_HARDWARE_ID HardwareId,
  117. OUT POINTER64 *HardwareIdDatabaseList64
  118. );
  119. ARC_STATUS
  120. BlAmd64TransferLoadedModuleState(
  121. VOID
  122. );
  123. ARC_STATUS
  124. BlAmd64TransferMemoryAllocationDescriptors(
  125. VOID
  126. );
  127. ARC_STATUS
  128. BlAmd64TransferNlsData(
  129. VOID
  130. );
  131. VOID
  132. BlAmd64TransferResourceList(
  133. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  134. OUT PCONFIGURATION_COMPONENT_DATA_64 ComponentData64
  135. );
  136. ARC_STATUS
  137. BlAmd64TransferSetupLoaderBlock(
  138. VOID
  139. );
  140. #if DBG
  141. PCHAR BlAmd64MemoryDescriptorText[] = {
  142. "LoaderExceptionBlock",
  143. "LoaderSystemBlock",
  144. "LoaderFree",
  145. "LoaderBad",
  146. "LoaderLoadedProgram",
  147. "LoaderFirmwareTemporary",
  148. "LoaderFirmwarePermanent",
  149. "LoaderOsloaderHeap",
  150. "LoaderOsloaderStack",
  151. "LoaderSystemCode",
  152. "LoaderHalCode",
  153. "LoaderBootDriver",
  154. "LoaderConsoleInDriver",
  155. "LoaderConsoleOutDriver",
  156. "LoaderStartupDpcStack",
  157. "LoaderStartupKernelStack",
  158. "LoaderStartupPanicStack",
  159. "LoaderStartupPcrPage",
  160. "LoaderStartupPdrPage",
  161. "LoaderRegistryData",
  162. "LoaderMemoryData",
  163. "LoaderNlsData",
  164. "LoaderSpecialMemory",
  165. "LoaderBBTMemory",
  166. "LoaderReserve"
  167. };
  168. #endif
  169. VOID
  170. NSUnmapFreeDescriptors(
  171. IN PLIST_ENTRY ListHead
  172. );
  173. //
  174. // Data declarations
  175. //
  176. PLOADER_PARAMETER_BLOCK BlAmd64LoaderBlock32;
  177. PLOADER_PARAMETER_BLOCK_64 BlAmd64LoaderBlock64;
  178. //
  179. // Pointer to the top of the 64-bit stack frame to use upon transition
  180. // to long mode.
  181. //
  182. POINTER64 BlAmd64IdleStack64;
  183. //
  184. // GDT and IDT pseudo-descriptor for use with LGDT/LIDT
  185. //
  186. DESCRIPTOR_TABLE_DESCRIPTOR BlAmd64GdtDescriptor;
  187. DESCRIPTOR_TABLE_DESCRIPTOR BlAmd64IdtDescriptor;
  188. DESCRIPTOR_TABLE_DESCRIPTOR BlAmd32GdtDescriptor;
  189. //
  190. // 64-bit pointers to the KPCR, loader parameter block and kernel
  191. // entry routine
  192. //
  193. POINTER64 BlAmd64LoaderParameterBlock;
  194. POINTER64 BlAmd64KernelEntry;
  195. //
  196. // A private list of page tables used to build the long mode paging
  197. // structures is kept. This is in order to avoid memory allocations while
  198. // the structures are being assembled.
  199. //
  200. // The PT_NODE type as well as the BlAmd64FreePfnList and BlAmd64BusyPfnList
  201. // globals are used to that end.
  202. //
  203. typedef struct _PT_NODE *PPT_NODE;
  204. typedef struct _PT_NODE {
  205. PPT_NODE Next;
  206. PAMD64_PAGE_TABLE PageTable;
  207. } PT_NODE;
  208. PPT_NODE BlAmd64FreePfnList = NULL;
  209. PPT_NODE BlAmd64BusyPfnList = NULL;
  210. //
  211. // External data
  212. //
  213. extern ULONG64 BlAmd64_LOCALAPIC;
  214. ARC_STATUS
  215. BlAmd64MapMemoryRegion(
  216. IN ULONG RegionVa,
  217. IN ULONG RegionSize
  218. )
  219. /*++
  220. Routine Description:
  221. This function creates long mode mappings for all valid x86 mappings
  222. within the region described by RegionVa and RegionSize.
  223. Arguments:
  224. RegionVa - Supplies the starting address of the VA region.
  225. RegionSize - Supplies the size of the VA region.
  226. Return Value:
  227. ARC_STATUS - Status of operation.
  228. --*/
  229. {
  230. ULONG va32;
  231. ULONG va32End;
  232. POINTER64 va64;
  233. ARC_STATUS status;
  234. PFN_NUMBER pfn;
  235. BOOLEAN pageMapped;
  236. BOOLEAN pageTableMapped;
  237. ULONG increment;
  238. va32 = RegionVa;
  239. va32End = va32 + RegionSize;
  240. while (va32 < va32End) {
  241. pageMapped = BlAmd64IsPageMapped( va32, &pfn, &pageTableMapped );
  242. if (pageTableMapped != FALSE) {
  243. //
  244. // The page table corresponding to this address is present.
  245. //
  246. if (pageMapped != FALSE) {
  247. //
  248. // The page corresponding to this address is present.
  249. //
  250. if ((va32 & KSEG0_BASE_X86) != 0) {
  251. //
  252. // The address lies within the X86 KSEG0 region. Map
  253. // it to the corresponding address within the AMD64
  254. // KSEG0 region.
  255. //
  256. va64 = PTR_64( (PVOID)va32 );
  257. } else {
  258. //
  259. // Map the VA directly.
  260. //
  261. va64 = (POINTER64)va32;
  262. }
  263. //
  264. // Now create the mapping in the AMD64 page table structure.
  265. //
  266. status = BlAmd64CreateMapping( va64, pfn );
  267. if (status != ESUCCESS) {
  268. return status;
  269. }
  270. }
  271. //
  272. // Check the next page.
  273. //
  274. increment = PAGE_SIZE;
  275. } else {
  276. //
  277. // Not only is the page not mapped but neither is the page table.
  278. // Skip to the next page table address boundary.
  279. //
  280. increment = 1 << PDI_SHIFT;
  281. }
  282. //
  283. // Advance to the next VA to check, checking for overflow.
  284. //
  285. va32 = (va32 + increment) & ~(increment - 1);
  286. if (va32 == 0) {
  287. break;
  288. }
  289. }
  290. return ESUCCESS;
  291. }
  292. BOOLEAN
  293. BlAmd64IsPageMapped(
  294. IN ULONG Va,
  295. OUT PFN_NUMBER *Pfn,
  296. OUT PBOOLEAN PageTableMapped
  297. )
  298. /*++
  299. Routine Description:
  300. This function accepts a 32-bit virtual address, determines whether it
  301. is a valid address, and if so returns the Pfn associated with it.
  302. Addresses that are within the recursive mapping are treated as NOT
  303. mapped.
  304. Arguments:
  305. None.
  306. Return Value:
  307. ARC_STATUS - Status of operation.
  308. --*/
  309. {
  310. ULONG pdeIndex;
  311. ULONG pteIndex;
  312. PHARDWARE_PTE pde;
  313. PHARDWARE_PTE pte;
  314. BOOLEAN dummy;
  315. PBOOLEAN pageTableMapped;
  316. //
  317. // Point the output parameter pointer as appropriate.
  318. //
  319. if (ARGUMENT_PRESENT(PageTableMapped)) {
  320. pageTableMapped = PageTableMapped;
  321. } else {
  322. pageTableMapped = &dummy;
  323. }
  324. //
  325. // Pages that are a part of the X86 32-bit mapping structure ARE
  326. // IGNORED.
  327. //
  328. if (Va >= PTE_BASE && Va <= PTE_TOP) {
  329. *pageTableMapped = TRUE;
  330. return FALSE;
  331. }
  332. //
  333. // Determine whether the mapping PDE is present
  334. //
  335. pdeIndex = Va >> PDI_SHIFT;
  336. pde = &((PHARDWARE_PTE)PDE_BASE)[ pdeIndex ];
  337. if (pde->Valid == 0) {
  338. *pageTableMapped = FALSE;
  339. return FALSE;
  340. }
  341. //
  342. // Indicate that the page table for this address is mapped.
  343. //
  344. *pageTableMapped = TRUE;
  345. //
  346. // It is, now get the page present status
  347. //
  348. pteIndex = Va >> PTI_SHIFT;
  349. pte = &((PHARDWARE_PTE)PTE_BASE)[ pteIndex ];
  350. if (pte->Valid == 0) {
  351. return FALSE;
  352. }
  353. *Pfn = pte->PageFrameNumber;
  354. return TRUE;
  355. }
  356. PAMD64_PAGE_TABLE
  357. BlAmd64AllocatePageTable(
  358. VOID
  359. )
  360. /*++
  361. Routine Description:
  362. This function allocates and initializes a PAGE_TABLE structure.
  363. Arguments:
  364. None.
  365. Return Value:
  366. Returns a pointer to the allocated page table structure, or NULL
  367. if the allocation failed.
  368. --*/
  369. {
  370. ARC_STATUS status;
  371. ULONG descriptor;
  372. PPT_NODE ptNode;
  373. PAMD64_PAGE_TABLE pageTable;
  374. //
  375. // Pull a page table off of the free list, if one exists
  376. //
  377. ptNode = BlAmd64FreePfnList;
  378. if (ptNode != NULL) {
  379. BlAmd64FreePfnList = ptNode->Next;
  380. } else {
  381. //
  382. // The free page table list is empty, allocate a new
  383. // page table and node to track it with.
  384. //
  385. status = BlAllocateDescriptor( LoaderAmd64MemoryData,
  386. 0,
  387. 1,
  388. &descriptor );
  389. if (status != ESUCCESS) {
  390. return NULL;
  391. }
  392. ptNode = BlAllocateHeap( sizeof(PT_NODE) );
  393. if (ptNode == NULL) {
  394. return NULL;
  395. }
  396. ptNode->PageTable = (PAMD64_PAGE_TABLE)(descriptor << PAGE_SHIFT);
  397. }
  398. ptNode->Next = BlAmd64BusyPfnList;
  399. BlAmd64BusyPfnList = ptNode;
  400. pageTable = ptNode->PageTable;
  401. RtlZeroMemory( pageTable, PAGE_SIZE );
  402. return pageTable;
  403. }
  404. ARC_STATUS
  405. BlAmd64TransferToKernel(
  406. IN PTRANSFER_ROUTINE SystemEntry,
  407. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  408. )
  409. /*++
  410. Routine Description:
  411. This routine prepares the AMD64 data structures required for kernel
  412. execution, including page table structures and 64-bit loader block,
  413. and transfers control to the kernel.
  414. This routine returns only upon an error.
  415. Arguments:
  416. SystemEntry - Pointer to the kernel entry point.
  417. BlLoaderBlock - Pointer to the 32-bit loader block structure.
  418. Return Value:
  419. No return on success. On failure, returns the status of the operation.
  420. --*/
  421. {
  422. BlAmd64LoaderParameterBlock = PTR_64(BlAmd64LoaderBlock64);
  423. BlAmd64KernelEntry = PTR_64(SystemEntry);
  424. DbgPrint("BlAmd64TransferToKernel():\n"
  425. " BlAmd64LoaderParameterBlock = 0x%08x%08x\n"
  426. " BlAmd64KernelEntry = 0x%08x%08x\n",
  427. (ULONG)(BlAmd64LoaderParameterBlock >> 32),
  428. (ULONG)BlAmd64LoaderParameterBlock,
  429. (ULONG)(BlAmd64KernelEntry >> 32),
  430. (ULONG)BlAmd64KernelEntry );
  431. BlAmd64SwitchToLongMode();
  432. return EINVAL;
  433. }
  434. ARC_STATUS
  435. BlAmd64PrepForTransferToKernelPhase1(
  436. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  437. )
  438. /*++
  439. Routine Description:
  440. This routine prepares the AMD64 data structures required for kernel
  441. execution, including page table structures and 64-bit loader block.
  442. This is the first of two phases of preperation. This phase is executed
  443. while heap and descriptor allocations are still permitted.
  444. Arguments:
  445. BlLoaderBlock - Pointer to the 32-bit loader block structure.
  446. Return Value:
  447. No return on success. On failure, returns the status of the operation.
  448. --*/
  449. {
  450. ARC_STATUS status;
  451. //
  452. // This is the main routine called to do preperatory work before
  453. // transitioning into the AMD64 kernel.
  454. //
  455. BlAmd64LoaderBlock32 = BlLoaderBlock;
  456. //
  457. // Build a 64-bit copy of the loader parameter block.
  458. //
  459. status = BlAmd64BuildLoaderBlock64();
  460. if (status != ESUCCESS) {
  461. return status;
  462. }
  463. //
  464. // Process the loaded modules.
  465. //
  466. status = BlAmd64TransferLoadedModuleState();
  467. if (status != ESUCCESS) {
  468. return status;
  469. }
  470. //
  471. // Next the boot driver nodes
  472. //
  473. status = BlAmd64TransferBootDriverNodes();
  474. if (status != ESUCCESS) {
  475. return status;
  476. }
  477. //
  478. // NLS data
  479. //
  480. status = BlAmd64TransferNlsData();
  481. if (status != ESUCCESS) {
  482. return status;
  483. }
  484. //
  485. // Configuration component data tree
  486. //
  487. status = BlAmd64TransferConfigurationComponentData();
  488. if (status != ESUCCESS) {
  489. return status;
  490. }
  491. //
  492. // ARC disk information
  493. //
  494. status = BlAmd64TransferArcDiskInformation();
  495. if (status != ESUCCESS) {
  496. return status;
  497. }
  498. //
  499. // Setup loader block
  500. //
  501. status = BlAmd64TransferSetupLoaderBlock();
  502. if (status != ESUCCESS) {
  503. return status;
  504. }
  505. //
  506. // Allocate structures needed by the kernel: KPCR etc.
  507. //
  508. status = BlAmd64PrepareSystemStructures();
  509. if (status != ESUCCESS) {
  510. return status;
  511. }
  512. //
  513. // Pre-allocate any pages needed for the long mode paging structures.
  514. //
  515. status = BlAmd64BuildMappingPhase1();
  516. if (status != ESUCCESS) {
  517. return status;
  518. }
  519. //
  520. // Pre-allocate the 64-bit memory allocation descriptors that will be
  521. // used by BlAmd64TransferMemoryAllocationDescriptors().
  522. //
  523. status = BlAmd64AllocateMemoryAllocationDescriptors();
  524. if (status != ESUCCESS) {
  525. return status;
  526. }
  527. return status;
  528. }
  529. VOID
  530. BlAmd64PrepForTransferToKernelPhase2(
  531. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  532. )
  533. /*++
  534. Routine Description:
  535. This routine prepares the AMD64 data structures required for kernel
  536. execution, including page table structures and 64-bit loader block.
  537. This is the second of two phases of preperation. This phase is executed
  538. after the 32-bit page tables have been purged of any unused mappings.
  539. Note that descriptor and heap allocations are not permitted at this
  540. point. Any necessary storage must have been preallocated during phase 1.
  541. Arguments:
  542. BlLoaderBlock - Pointer to the 32-bit loader block structure.
  543. Return Value:
  544. No return on success. On failure, returns the status of the operation.
  545. --*/
  546. {
  547. PLOADER_PARAMETER_EXTENSION_64 extension;
  548. ARC_STATUS status;
  549. //
  550. // At this point everything has been preallocated, nothing can fail.
  551. //
  552. status = BlAmd64BuildMappingPhase2();
  553. ASSERT(status == ESUCCESS);
  554. //
  555. // Transfer the memory descriptor state.
  556. //
  557. status = BlAmd64TransferMemoryAllocationDescriptors();
  558. ASSERT(status == ESUCCESS);
  559. //
  560. // Set LoaderPagesSpanned in the 64-bit loader block.
  561. //
  562. extension = PTR_32(BlAmd64LoaderBlock64->Extension);
  563. extension->LoaderPagesSpanned = BlHighestPage+1;
  564. }
  565. ARC_STATUS
  566. BlAmd64BuildMappingPhase1(
  567. VOID
  568. )
  569. /*++
  570. Routine Description:
  571. This routine performs the first of the two-phase long mode mapping
  572. structure creation process now, while memory allocations are still
  573. possible. It simply calls BlAmd64BuilMappingWorker() which in fact
  574. creates the mapping structures, and (more importantly) allocates all
  575. of the page tables required to do so.
  576. Arguments:
  577. None.
  578. Return Value:
  579. None.
  580. --*/
  581. {
  582. ARC_STATUS status;
  583. //
  584. // While it is possible to perform memory allocations, reserve enough
  585. // page tables to build the AMD64 paging structures.
  586. //
  587. // The easiest way to calculate the maximum number of pages needed is
  588. // to actually build the structures. We do that now with the first of
  589. // two calls to BlAmd64BuildMappingWorker().
  590. //
  591. status = BlAmd64BuildMappingWorker();
  592. if (status != ESUCCESS) {
  593. return status;
  594. }
  595. return ESUCCESS;
  596. }
  597. ARC_STATUS
  598. BlAmd64BuildMappingPhase2(
  599. VOID
  600. )
  601. /*++
  602. Routine Description:
  603. This routine performs the second of the two-phase long mode mapping
  604. structure creation process. All page tables will have been preallocated
  605. as a result of the work performed by BlAmd64BuildMappingPhase1().
  606. Arguments:
  607. None.
  608. Return Value:
  609. None.
  610. --*/
  611. {
  612. ARC_STATUS status;
  613. //
  614. // Reset the Amd64 paging structures
  615. //
  616. BlAmd64ResetPageTableHeap();
  617. //
  618. // All necessary page tables can now be found on BlAmd64FreePfnList.
  619. // On this, the second call to BlAmd64BuildMappingWorker(), those are the
  620. // pages that will be used to perform the mapping.
  621. //
  622. status = BlAmd64BuildMappingWorker();
  623. if (status != ESUCCESS) {
  624. return status;
  625. }
  626. return ESUCCESS;
  627. }
  628. ARC_STATUS
  629. BlAmd64BuildMappingWorker(
  630. VOID
  631. )
  632. /*++
  633. Routine Description:
  634. This routine creates any necessary memory mappings in the long-mode
  635. page table structure. It is called twice, once from
  636. BlAmd64BuildMappingPhase1() and again from BlAmd64BuildMappingPhase2().
  637. Any additional memory mapping that must be carried out should go in
  638. this routine.
  639. Arguments:
  640. None.
  641. Return Value:
  642. None.
  643. --*/
  644. {
  645. ARC_STATUS status;
  646. PFN_NUMBER pfn;
  647. //
  648. // Any long mode mapping code goes here. This routine is called twice:
  649. // once from BlAmd64BuildMappingPhase1(), and again from
  650. // BlAmd64BuildMappingPhase2().
  651. //
  652. //
  653. // Transfer any mappings in the first 32MB of identity mapping.
  654. //
  655. status = BlAmd64MapMemoryRegion( 0,
  656. 32 * 1024 * 1024 );
  657. if (status != ESUCCESS) {
  658. return status;
  659. }
  660. //
  661. // Transfer any mappings in the 1GB region starting at KSEG0_BASE_X86.
  662. //
  663. status = BlAmd64MapMemoryRegion( KSEG0_BASE_X86,
  664. 0x40000000 );
  665. if (status != ESUCCESS) {
  666. return status;
  667. }
  668. //
  669. // "Map" the HAL va
  670. //
  671. status = BlAmd64MapHalVaSpace();
  672. if (status != ESUCCESS) {
  673. return status;
  674. }
  675. //
  676. // Map the shared user data page
  677. //
  678. BlAmd64IsPageMapped( KI_USER_SHARED_DATA, &pfn, NULL );
  679. status = BlAmd64CreateMapping( KI_USER_SHARED_DATA_64, pfn );
  680. if (status != ESUCCESS) {
  681. return status;
  682. }
  683. return ESUCCESS;
  684. }
  685. VOID
  686. BlAmd64ResetPageTableHeap(
  687. VOID
  688. )
  689. /*++
  690. Routine Description:
  691. This function is called as part of the two-phase page table creation
  692. process. Its purpose is to move all of the PFNs required to build
  693. the long mode page tables back to the free list, and to otherwise
  694. initialize the long mode paging structure.
  695. Arguments:
  696. None.
  697. Return Value:
  698. None.
  699. --*/
  700. {
  701. PPT_NODE ptNodeLast;
  702. //
  703. // Move the page table nodes from the busy list to the free list.
  704. //
  705. if (BlAmd64BusyPfnList != NULL) {
  706. //
  707. // A tail pointer is not kept, so find the tail node here.
  708. //
  709. ptNodeLast = BlAmd64BusyPfnList;
  710. while (ptNodeLast->Next != NULL) {
  711. ptNodeLast = ptNodeLast->Next;
  712. }
  713. ptNodeLast->Next = BlAmd64FreePfnList;
  714. BlAmd64FreePfnList = BlAmd64BusyPfnList;
  715. BlAmd64BusyPfnList = NULL;
  716. }
  717. //
  718. // Zero the top-level pte declared in amd64.c
  719. //
  720. BlAmd64ClearTopLevelPte();
  721. }
  722. ARC_STATUS
  723. BlAmd64TransferHardwareIdList(
  724. IN PPNP_HARDWARE_ID HardwareId,
  725. OUT POINTER64 *HardwareIdDatabaseList64
  726. )
  727. /*++
  728. Routine Description:
  729. This routine walks the singly-linked list of PNP_HARDWARE_ID structures
  730. and for each one found, creates a 64-bit PNP_HARDWARE_ID_64 structure and
  731. inserts it on a list of same.
  732. The resultant 64-bit list is in the same order as the supplied 32-bit
  733. list.
  734. Arguments:
  735. HardwareId - Supplies a pointer to the head of the singly-linked list of
  736. PNP_HARDWARE_ID structures.
  737. HardwareIdDatabaseList64 -
  738. Supplies a pointer to a POINTER64 which upon successful
  739. completion of this routine will contain a 64-bit KSEG0
  740. pointer to the created 64-bit PNP_HARDWARE_ID_64 list.
  741. Return Value:
  742. ARC_STATUS - Status of operation.
  743. --*/
  744. {
  745. PPNP_HARDWARE_ID_64 hardwareId64;
  746. ARC_STATUS status;
  747. //
  748. // Walk the id list backwards. To do this we call ourselves
  749. // recursively until we find the end of the list, then process the nodes
  750. // on the way back up.
  751. //
  752. if (HardwareId == NULL) {
  753. return ESUCCESS;
  754. }
  755. status = BlAmd64TransferHardwareIdList( HardwareId->Next,
  756. HardwareIdDatabaseList64 );
  757. if (status != ESUCCESS) {
  758. return status;
  759. }
  760. hardwareId64 = BlAllocateHeap(sizeof(PNP_HARDWARE_ID));
  761. if (hardwareId64 == NULL) {
  762. return ENOMEM;
  763. }
  764. status = Copy_PNP_HARDWARE_ID( HardwareId, hardwareId64 );
  765. if (status != ESUCCESS) {
  766. return status;
  767. }
  768. //
  769. // Link it into the front of the 64-bit list.
  770. //
  771. hardwareId64->Next = *HardwareIdDatabaseList64;
  772. *HardwareIdDatabaseList64 = PTR_64(hardwareId64);
  773. return ESUCCESS;
  774. }
  775. ARC_STATUS
  776. BlAmd64TransferDeviceRegistryList(
  777. IN PDETECTED_DEVICE_REGISTRY DetectedDeviceRegistry32,
  778. OUT POINTER64 *DetectedDeviceRegistry64
  779. )
  780. /*++
  781. Routine Description:
  782. This routine walks the singly-linked list of DETECTED_DEVICE_REGISTRY
  783. structures and for each one found, creates a 64-bit
  784. DETECTED_DEVICE_REGISTRY_64 structure and inserts it on a list of same.
  785. The resultant 64-bit list is in the same order as the supplied 32-bit
  786. list.
  787. Arguments:
  788. DetectedDeviceRegistry32 - Supplies a pointer to the head of the singly-linked list of
  789. DETECTED_DEVICE_REGISTRY structures.
  790. DetectedDeviceRegistry64 -
  791. Supplies a pointer to a POINTER64 which upon successful
  792. completion of this routine will contain a 64-bit KSEG0
  793. pointer to the created 64-bit DETECTED_DEVICE_REGISTRY_64
  794. list.
  795. Return Value:
  796. ARC_STATUS - Status of operation.
  797. --*/
  798. {
  799. PDETECTED_DEVICE_REGISTRY_64 registry64;
  800. ARC_STATUS status;
  801. //
  802. // Walk the registry list backwards. To do this we call ourselves
  803. // recursively until we find the end of the list, then process the nodes
  804. // on the way back up.
  805. //
  806. if (DetectedDeviceRegistry32 == NULL) {
  807. return ESUCCESS;
  808. }
  809. status = BlAmd64TransferDeviceRegistryList( DetectedDeviceRegistry32->Next,
  810. DetectedDeviceRegistry64 );
  811. if (status != ESUCCESS) {
  812. return status;
  813. }
  814. //
  815. // Allocate a 64-bit registry structure and copy the contents
  816. // of the 32-bit one in.
  817. //
  818. registry64 = BlAllocateHeap(sizeof(DETECTED_DEVICE_REGISTRY_64));
  819. if (registry64 == NULL) {
  820. return ENOMEM;
  821. }
  822. status = Copy_DETECTED_DEVICE_REGISTRY( DetectedDeviceRegistry32, registry64 );
  823. if (status != ESUCCESS) {
  824. return status;
  825. }
  826. //
  827. // Link it into the front of the 64-bit list.
  828. //
  829. registry64->Next = *DetectedDeviceRegistry64;
  830. *DetectedDeviceRegistry64 = PTR_64(registry64);
  831. return ESUCCESS;
  832. }
  833. ARC_STATUS
  834. BlAmd64TransferDeviceFileList(
  835. IN PDETECTED_DEVICE_FILE DetectedDeviceFile32,
  836. OUT POINTER64 *DetectedDeviceFile64
  837. )
  838. /*++
  839. Routine Description:
  840. This routine walks the singly-linked list of DETECTED_DEVICE_FILE
  841. structures and for each one found, creates a 64-bit
  842. DETECTED_DEVICE_FILE_64 structure and inserts it on a list of same.
  843. The resultant 64-bit list is in the same order as the supplied 32-bit
  844. list.
  845. Arguments:
  846. DetectedDeviceFile32 - Supplies a pointer to the head of the singly-linked
  847. list of DETECTED_DEVICE_FILE structures.
  848. DetectedDeviceFile64 -
  849. Supplies a pointer to a POINTER64 which upon successful
  850. completion of this routine will contain a 64-bit KSEG0
  851. pointer to the created 64-bit DETECTED_DEVICE_FILE_64
  852. list.
  853. Return Value:
  854. ARC_STATUS - Status of operation.
  855. --*/
  856. {
  857. PDETECTED_DEVICE_FILE_64 file64;
  858. ARC_STATUS status;
  859. //
  860. // Walk the file list backwards. To do this we call ourselves
  861. // recursively until we find the end of the list, then process the nodes
  862. // on the way back up.
  863. //
  864. if (DetectedDeviceFile32 == NULL) {
  865. return ESUCCESS;
  866. }
  867. status = BlAmd64TransferDeviceFileList( DetectedDeviceFile32->Next,
  868. DetectedDeviceFile64 );
  869. if (status != ESUCCESS) {
  870. return status;
  871. }
  872. //
  873. // Allocate a 64-bit file structure and copy the contents
  874. // of the 32-bit one in.
  875. //
  876. file64 = BlAllocateHeap(sizeof(DETECTED_DEVICE_FILE_64));
  877. if (file64 == NULL) {
  878. return ENOMEM;
  879. }
  880. status = Copy_DETECTED_DEVICE_FILE( DetectedDeviceFile32, file64 );
  881. if (status != ESUCCESS) {
  882. return status;
  883. }
  884. //
  885. // Transfer the singly-linked list of DETECTED_DEVICE_REGISTRY structures
  886. // linked to this DETECTED_DEVICE_FILE structure.
  887. //
  888. status = BlAmd64TransferDeviceRegistryList(
  889. DetectedDeviceFile32->RegistryValueList,
  890. &file64->RegistryValueList );
  891. if (status != ESUCCESS) {
  892. return status;
  893. }
  894. //
  895. // Link it into the front of the 64-bit list.
  896. //
  897. file64->Next = *DetectedDeviceFile64;
  898. *DetectedDeviceFile64 = PTR_64(file64);
  899. return ESUCCESS;
  900. }
  901. ARC_STATUS
  902. BlAmd64TransferDeviceList(
  903. IN PDETECTED_DEVICE DetectedDevice32,
  904. OUT POINTER64 *DetectedDeviceList64
  905. )
  906. /*++
  907. Routine Description:
  908. This routine walks the singly-linked list of DETECTED_DEVICE
  909. structures and for each one found, creates a 64-bit
  910. DETECTED_DEVICE_64 structure and inserts it on a list of same.
  911. The resultant 64-bit list is in the same order as the supplied 32-bit
  912. list.
  913. Arguments:
  914. DetectedDevice32 - Supplies a pointer to the head of the singly-linked
  915. list of DETECTED_DEVICE structures.
  916. DetectedDeviceList64 -
  917. Supplies a pointer to a POINTER64 which upon successful
  918. completion of this routine will contain a 64-bit KSEG0
  919. pointer to the created 64-bit DETECTED_DEVICE_64
  920. list.
  921. Return Value:
  922. ARC_STATUS - Status of operation.
  923. --*/
  924. {
  925. PDETECTED_DEVICE_64 device64;
  926. ARC_STATUS status;
  927. //
  928. // Walk the device list backwards. To do this we call ourselves
  929. // recursively until we find the end of the list, then process the nodes
  930. // on the way back up.
  931. //
  932. if (DetectedDevice32 == NULL) {
  933. return ESUCCESS;
  934. }
  935. status = BlAmd64TransferDeviceList( DetectedDevice32->Next,
  936. DetectedDeviceList64 );
  937. if (status != ESUCCESS) {
  938. return status;
  939. }
  940. //
  941. // Allocate a 64-bit device structure and copy the contents
  942. // of the 32-bit one in.
  943. //
  944. device64 = BlAllocateHeap(sizeof(DETECTED_DEVICE_64));
  945. if (device64 == NULL) {
  946. return ENOMEM;
  947. }
  948. status = Copy_DETECTED_DEVICE( DetectedDevice32, device64 );
  949. if (status != ESUCCESS) {
  950. return status;
  951. }
  952. //
  953. // Transfer any PROTECTED_DEVICE_FILE structures
  954. //
  955. status = BlAmd64TransferDeviceFileList( DetectedDevice32->Files,
  956. &device64->Files );
  957. if (status != ESUCCESS) {
  958. return status;
  959. }
  960. //
  961. // Link it into the front of the 64-bit list.
  962. //
  963. device64->Next = *DetectedDeviceList64;
  964. *DetectedDeviceList64 = PTR_64(device64);
  965. return ESUCCESS;
  966. }
  967. ARC_STATUS
  968. BlAmd64TransferSetupLoaderBlock(
  969. VOID
  970. )
  971. /*++
  972. Routine Description:
  973. This routine creates a SETUP_LOADER_BLOCK_64 structure that is the
  974. equivalent of the 32-bit SETUP_LOADER_BLOCK structure referenced within
  975. the 32-bit setup loader block.
  976. Arguments:
  977. None.
  978. Return Value:
  979. ARC_STATUS - Status of operation.
  980. --*/
  981. {
  982. PSETUP_LOADER_BLOCK setupBlock32;
  983. PSETUP_LOADER_BLOCK_64 setupBlock64;
  984. ARC_STATUS status;
  985. setupBlock32 = BlAmd64LoaderBlock32->SetupLoaderBlock;
  986. if (setupBlock32 == NULL) {
  987. return ESUCCESS;
  988. }
  989. setupBlock64 = BlAllocateHeap(sizeof(SETUP_LOADER_BLOCK_64));
  990. if (setupBlock64 == NULL) {
  991. return ENOMEM;
  992. }
  993. status = Copy_SETUP_LOADER_BLOCK( setupBlock32, setupBlock64 );
  994. if (status != ESUCCESS) {
  995. return status;
  996. }
  997. {
  998. #define TRANSFER_DEVICE_LIST(x) \
  999. setupBlock64->x = PTR_64(NULL); \
  1000. status = BlAmd64TransferDeviceList( setupBlock32->x, \
  1001. &setupBlock64->x ); \
  1002. if (status != ESUCCESS) return status;
  1003. TRANSFER_DEVICE_LIST(KeyboardDevices);
  1004. TRANSFER_DEVICE_LIST(ScsiDevices);
  1005. TRANSFER_DEVICE_LIST(BootBusExtenders);
  1006. TRANSFER_DEVICE_LIST(BusExtenders);
  1007. TRANSFER_DEVICE_LIST(InputDevicesSupport);
  1008. #undef TRANSFER_DEVICE_LIST
  1009. }
  1010. setupBlock64->HardwareIdDatabase = PTR_64(NULL);
  1011. status = BlAmd64TransferHardwareIdList( setupBlock32->HardwareIdDatabase,
  1012. &setupBlock64->HardwareIdDatabase );
  1013. return status;
  1014. }
  1015. ARC_STATUS
  1016. BlAmd64TransferArcDiskInformation(
  1017. VOID
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. This routine creates an ARC_DISK_INFORMATION_64 structure that is the
  1022. equivalent of the 32-bit ARC_DISK_INFORMATION structure referenced within
  1023. the 32-bit loader block.
  1024. Arguments:
  1025. None.
  1026. Return Value:
  1027. ARC_STATUS - Status of operation.
  1028. --*/
  1029. {
  1030. ARC_STATUS status;
  1031. PLIST_ENTRY listHead;
  1032. PLIST_ENTRY listEntry;
  1033. PARC_DISK_INFORMATION diskInfo32;
  1034. PARC_DISK_INFORMATION_64 diskInfo64;
  1035. PARC_DISK_SIGNATURE diskSignature32;
  1036. PARC_DISK_SIGNATURE_64 diskSignature64;
  1037. //
  1038. // Create a 64-bit ARC_DISK_INFORMATION structure
  1039. //
  1040. diskInfo32 = BlAmd64LoaderBlock32->ArcDiskInformation;
  1041. if (diskInfo32 == NULL) {
  1042. return ESUCCESS;
  1043. }
  1044. diskInfo64 = BlAllocateHeap(sizeof(ARC_DISK_INFORMATION_64));
  1045. if (diskInfo64 == NULL) {
  1046. return ENOMEM;
  1047. }
  1048. status = Copy_ARC_DISK_INFORMATION( diskInfo32, diskInfo64 );
  1049. if (status != ESUCCESS) {
  1050. return status;
  1051. }
  1052. InitializeListHead64( &diskInfo64->DiskSignatures );
  1053. //
  1054. // Walk the 32-bit list of ARC_DISK_SIGNATURE nodes and create
  1055. // a 64-bit version of each
  1056. //
  1057. listHead = &diskInfo32->DiskSignatures;
  1058. listEntry = listHead->Flink;
  1059. while (listEntry != listHead) {
  1060. diskSignature32 = CONTAINING_RECORD( listEntry,
  1061. ARC_DISK_SIGNATURE,
  1062. ListEntry );
  1063. diskSignature64 = BlAllocateHeap(sizeof(ARC_DISK_SIGNATURE_64));
  1064. if (diskSignature64 == NULL) {
  1065. return ENOMEM;
  1066. }
  1067. status = Copy_ARC_DISK_SIGNATURE( diskSignature32, diskSignature64 );
  1068. if (status != ESUCCESS) {
  1069. return status;
  1070. }
  1071. InsertTailList64( &diskInfo64->DiskSignatures,
  1072. &diskSignature64->ListEntry );
  1073. listEntry = listEntry->Flink;
  1074. }
  1075. BlAmd64LoaderBlock64->ArcDiskInformation = PTR_64(diskInfo64);
  1076. return ESUCCESS;
  1077. }
  1078. ARC_STATUS
  1079. BlAmd64TransferConfigurationComponentData(
  1080. VOID
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. This routine creates a CONFIGURATION_COMPONENT_DATA_64 structure tree
  1085. that is the equivalent of the 32-bit CONFIGURATION_COMPONENT_DATA
  1086. structure tree referenced within the 32-bit loader block.
  1087. Arguments:
  1088. None.
  1089. Return Value:
  1090. ARC_STATUS - Status of operation.
  1091. --*/
  1092. {
  1093. PCONFIGURATION_COMPONENT_DATA_64 rootComponent64;
  1094. if (BlAmd64LoaderBlock32->ConfigurationRoot == NULL) {
  1095. return ESUCCESS;
  1096. }
  1097. rootComponent64 =
  1098. BlAmd64TransferConfigWorker( BlAmd64LoaderBlock32->ConfigurationRoot,
  1099. NULL );
  1100. if (rootComponent64 == NULL) {
  1101. return ENOMEM;
  1102. }
  1103. BlAmd64LoaderBlock64->ConfigurationRoot = PTR_64(rootComponent64);
  1104. return ESUCCESS;
  1105. }
  1106. PCONFIGURATION_COMPONENT_DATA_64
  1107. BlAmd64TransferConfigWorker(
  1108. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  1109. IN PCONFIGURATION_COMPONENT_DATA_64 ComponentDataParent64
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. Given a 32-bit CONFIGURATION_COMPONENT_DATA structure, this routine
  1114. creates an equivalent 64-bit CONFIGURATION_COMPONENT_DATA structure
  1115. for the supplied structure, as well as for all of its children and
  1116. siblings.
  1117. This routine calls itself recursively for each sibling and child.
  1118. Arguments:
  1119. ComponentData32 - Supplies a pointer to the 32-bit structure to transfer.
  1120. ComponentDataParent64 - Supplies a pointer to the current 64-bit parent
  1121. structure.
  1122. Return Value:
  1123. Returns a pointer to the created 64-bit structure, or NULL if a failure
  1124. was encountered.
  1125. --*/
  1126. {
  1127. ARC_STATUS status;
  1128. ULONG componentDataSize64;
  1129. ULONG partialResourceListSize64;
  1130. BOOLEAN thunkResourceList;
  1131. PCONFIGURATION_COMPONENT_DATA componentData32;
  1132. PCONFIGURATION_COMPONENT_DATA_64 componentData64;
  1133. PCONFIGURATION_COMPONENT_DATA_64 newCompData64;
  1134. //
  1135. // Create and copy configuration component data node
  1136. //
  1137. componentDataSize64 = sizeof(CONFIGURATION_COMPONENT_DATA_64);
  1138. thunkResourceList = BlAmd64ContainsResourceList(ComponentData32,
  1139. &partialResourceListSize64);
  1140. if (thunkResourceList != FALSE) {
  1141. //
  1142. // This node contains a CM_PARTIAL_RESOURCE_LIST structure.
  1143. // partialResourceListSize64 contains the number of bytes beyond the
  1144. // CONFIGURATION_COMPONENT_DATA header that must be allocated in order to
  1145. // thunk the CM_PARTIAL_RESOURCE_LIST into a 64-bit version.
  1146. //
  1147. componentDataSize64 += partialResourceListSize64;
  1148. }
  1149. componentData64 = BlAllocateHeap(componentDataSize64);
  1150. if (componentData64 == NULL) {
  1151. return NULL;
  1152. }
  1153. status = Copy_CONFIGURATION_COMPONENT_DATA( ComponentData32,
  1154. componentData64 );
  1155. if (status != ESUCCESS) {
  1156. return NULL;
  1157. }
  1158. if (thunkResourceList != FALSE) {
  1159. //
  1160. // Update the configuration component data size
  1161. //
  1162. componentData64->ComponentEntry.ConfigurationDataLength =
  1163. partialResourceListSize64;
  1164. }
  1165. componentData64->Parent = PTR_64(ComponentDataParent64);
  1166. if (thunkResourceList != FALSE) {
  1167. //
  1168. // Now transfer the resource list.
  1169. //
  1170. BlAmd64TransferResourceList(ComponentData32,componentData64);
  1171. }
  1172. //
  1173. // Process the child (and recursively, all children)
  1174. //
  1175. if (ComponentData32->Child != NULL) {
  1176. newCompData64 = BlAmd64TransferConfigWorker( ComponentData32->Child,
  1177. componentData64 );
  1178. if (newCompData64 == NULL) {
  1179. return newCompData64;
  1180. }
  1181. componentData64->Child = PTR_64(newCompData64);
  1182. }
  1183. //
  1184. // Process the sibling (and recursively, all siblings)
  1185. //
  1186. if (ComponentData32->Sibling != NULL) {
  1187. newCompData64 = BlAmd64TransferConfigWorker( ComponentData32->Sibling,
  1188. ComponentDataParent64 );
  1189. if (newCompData64 == NULL) {
  1190. return newCompData64;
  1191. }
  1192. componentData64->Sibling = PTR_64(newCompData64);
  1193. }
  1194. return componentData64;
  1195. }
  1196. VOID
  1197. BlAmd64TransferResourceList(
  1198. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  1199. OUT PCONFIGURATION_COMPONENT_DATA_64 ComponentData64
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. This routine transfers the 32-bit CM_PARTIAL_RESOURCE_LIST structure that
  1204. immediately follows ComponentData32 to the memory immediately after
  1205. ComponentData64.
  1206. Arguments:
  1207. ComponentData32 - Supplies a pointer to the 32-bit structure to transfer from.
  1208. ComponentData64 - Supplies a pointer to the 64-bit structure to transfer to.
  1209. Return Value:
  1210. None.
  1211. --*/
  1212. {
  1213. PCM_PARTIAL_RESOURCE_LIST resourceList32;
  1214. PCM_PARTIAL_RESOURCE_LIST_64 resourceList64;
  1215. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDesc32;
  1216. PCM_PARTIAL_RESOURCE_DESCRIPTOR_64 resourceDesc64;
  1217. PVOID descBody32;
  1218. PVOID descBody64;
  1219. PUCHAR tail32;
  1220. PUCHAR tail64;
  1221. ULONG tailSize;
  1222. ULONG descriptorCount;
  1223. //
  1224. // Calculate pointers to the source and target descriptor lists.
  1225. //
  1226. resourceList32 = (PCM_PARTIAL_RESOURCE_LIST)ComponentData32->ConfigurationData;
  1227. resourceList64 = (PCM_PARTIAL_RESOURCE_LIST_64)(ComponentData64 + 1);
  1228. //
  1229. // Update ComponentData64 to refer to it's new data area, which will be immediately
  1230. // following the component data structure.
  1231. //
  1232. ComponentData64->ConfigurationData = PTR_64(resourceList64);
  1233. //
  1234. // Copy the resource list header information
  1235. //
  1236. Copy_CM_PARTIAL_RESOURCE_LIST(resourceList32,resourceList64);
  1237. //
  1238. // Now thunk each of the resource descriptors
  1239. //
  1240. descriptorCount = resourceList32->Count;
  1241. resourceDesc32 = resourceList32->PartialDescriptors;
  1242. resourceDesc64 = &resourceList64->PartialDescriptors;
  1243. while (descriptorCount > 0) {
  1244. //
  1245. // Transfer the common header information
  1246. //
  1247. Copy_CM_PARTIAL_RESOURCE_DESCRIPTOR(resourceDesc32,resourceDesc64);
  1248. descBody32 = &resourceDesc32->u;
  1249. descBody64 = &resourceDesc64->u;
  1250. //
  1251. // Transfer the body according to the type
  1252. //
  1253. switch(resourceDesc32->Type) {
  1254. case CmResourceTypeNull:
  1255. break;
  1256. case CmResourceTypePort:
  1257. Copy_CM_PRD_PORT(descBody32,descBody64);
  1258. break;
  1259. case CmResourceTypeInterrupt:
  1260. Copy_CM_PRD_INTERRUPT(descBody32,descBody64);
  1261. break;
  1262. case CmResourceTypeMemory:
  1263. Copy_CM_PRD_MEMORY(descBody32,descBody64);
  1264. break;
  1265. case CmResourceTypeDma:
  1266. Copy_CM_PRD_DMA(descBody32,descBody64);
  1267. break;
  1268. case CmResourceTypeDeviceSpecific:
  1269. Copy_CM_PRD_DEVICESPECIFICDATA(descBody32,descBody64);
  1270. break;
  1271. case CmResourceTypeBusNumber:
  1272. Copy_CM_PRD_BUSNUMBER(descBody32,descBody64);
  1273. break;
  1274. default:
  1275. Copy_CM_PRD_GENERIC(descBody32,descBody64);
  1276. break;
  1277. }
  1278. resourceDesc32 += 1;
  1279. resourceDesc64 += 1;
  1280. descriptorCount -= 1;
  1281. }
  1282. //
  1283. // Calculate how much data, if any, is appended to the resource list.
  1284. //
  1285. tailSize = ComponentData32->ComponentEntry.ConfigurationDataLength +
  1286. (PUCHAR)resourceList32 -
  1287. (PUCHAR)resourceDesc32;
  1288. if (tailSize > 0) {
  1289. //
  1290. // Some data is there, append it as-is to the 64-bit structure.
  1291. //
  1292. tail32 = (PUCHAR)resourceDesc32;
  1293. tail64 = (PUCHAR)resourceDesc64;
  1294. RtlCopyMemory(tail64,tail32,tailSize);
  1295. }
  1296. }
  1297. BOOLEAN
  1298. BlAmd64ContainsResourceList(
  1299. IN PCONFIGURATION_COMPONENT_DATA ComponentData32,
  1300. OUT PULONG ResourceListSize64
  1301. )
  1302. /*++
  1303. Routine Description:
  1304. Given a 32-bit CONFIGURATION_COMPONENT_DATA structure, this routine
  1305. determines whether the data associated with the structure contains a
  1306. CM_PARTIAL_RESOURCE_LIST structure.
  1307. If it does, the size of the 64-bit representation of this structure is calculated,
  1308. added to any data that might be appended to the resource list structure, and
  1309. returned in ResourceListSize64.
  1310. Arguments:
  1311. ComponentData32 - Supplies a pointer to the 32-bit structure to transfer.
  1312. ResourceListSize64 - Supplies a pointer to a ULONG in which the necessary
  1313. additional data size is returned.
  1314. Return Value:
  1315. Returns TRUE if the CONFIGURATION_COMPONENT_DATA stucture refers to a
  1316. CM_PARTIAL_RESOURCE_LIST structure, FALSE otherwise.
  1317. --*/
  1318. {
  1319. ULONG resourceListSize64;
  1320. ULONG configDataLen;
  1321. PCM_PARTIAL_RESOURCE_LIST resourceList;
  1322. ULONG resourceCount;
  1323. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
  1324. PCM_PARTIAL_RESOURCE_DESCRIPTOR lastResourceDescriptor;
  1325. configDataLen = ComponentData32->ComponentEntry.ConfigurationDataLength;
  1326. if (configDataLen < sizeof(CM_PARTIAL_RESOURCE_LIST)) {
  1327. //
  1328. // Data not large enough to contain the smallest possible resource list
  1329. //
  1330. return FALSE;
  1331. }
  1332. resourceList = (PCM_PARTIAL_RESOURCE_LIST)ComponentData32->ConfigurationData;
  1333. if (resourceList->Version != 0 || resourceList->Revision != 0) {
  1334. //
  1335. // Unrecognized version.
  1336. //
  1337. return FALSE;
  1338. }
  1339. configDataLen -= FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,PartialDescriptors);
  1340. resourceCount = resourceList->Count;
  1341. if (configDataLen < sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * resourceCount) {
  1342. //
  1343. // Config data len is not large enough to contain a CM_PARTIAL_RESOURCE_LIST
  1344. // as large as this one claims to be.
  1345. //
  1346. return FALSE;
  1347. }
  1348. //
  1349. // Validate each of the CM_PARTIAL_RESOURCE_DESCRIPTOR structures in the list
  1350. //
  1351. resourceDescriptor = resourceList->PartialDescriptors;
  1352. lastResourceDescriptor = resourceDescriptor + resourceCount;
  1353. while (resourceDescriptor < lastResourceDescriptor) {
  1354. if (resourceDescriptor->Type > CmResourceTypeMaximum) {
  1355. return FALSE;
  1356. }
  1357. resourceDescriptor += 1;
  1358. }
  1359. //
  1360. // Looks like this is an actual resource list. Calculate the size of any remaining
  1361. // data after the CM_PARTIAL_RESOURCE_LIST structure.
  1362. //
  1363. configDataLen -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * resourceCount;
  1364. *ResourceListSize64 = sizeof(CM_PARTIAL_RESOURCE_LIST) +
  1365. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (resourceCount - 1) +
  1366. configDataLen;
  1367. return TRUE;
  1368. }
  1369. ARC_STATUS
  1370. BlAmd64TransferNlsData(
  1371. VOID
  1372. )
  1373. /*++
  1374. Routine Description:
  1375. This routine creates an NLS_DATA_BLOCK64 structure that is the
  1376. equivalent of the 32-bit NLS_DATA_BLOCK structure referenced within
  1377. the 32-bit loader block.
  1378. Arguments:
  1379. None.
  1380. Return Value:
  1381. ARC_STATUS - Status of operation.
  1382. --*/
  1383. {
  1384. ARC_STATUS status;
  1385. PNLS_DATA_BLOCK nlsDataBlock32;
  1386. PNLS_DATA_BLOCK_64 nlsDataBlock64;
  1387. nlsDataBlock32 = BlAmd64LoaderBlock32->NlsData;
  1388. if (nlsDataBlock32 == NULL) {
  1389. return ESUCCESS;
  1390. }
  1391. nlsDataBlock64 = BlAllocateHeap(sizeof(NLS_DATA_BLOCK_64));
  1392. if (nlsDataBlock64 == NULL) {
  1393. return ENOMEM;
  1394. }
  1395. status = Copy_NLS_DATA_BLOCK( nlsDataBlock32, nlsDataBlock64 );
  1396. if (status != ESUCCESS) {
  1397. return status;
  1398. }
  1399. BlAmd64LoaderBlock64->NlsData = PTR_64( nlsDataBlock64 );
  1400. return ESUCCESS;
  1401. }
  1402. ARC_STATUS
  1403. BlAmd64BuildLoaderBlock64(
  1404. VOID
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. This routine allocates a 64-bit loader parameter block and copies the
  1409. contents of the 32-bit loader parameter block into it.
  1410. Arguments:
  1411. None.
  1412. Return Value:
  1413. The status of the operation.
  1414. --*/
  1415. {
  1416. ARC_STATUS status;
  1417. //
  1418. // Allocate the loader block and extension
  1419. //
  1420. BlAmd64LoaderBlock64 = BlAllocateHeap(sizeof(LOADER_PARAMETER_BLOCK_64));
  1421. if (BlAmd64LoaderBlock64 == NULL) {
  1422. return ENOMEM;
  1423. }
  1424. //
  1425. // Copy the contents of the 32-bit loader parameter block to the
  1426. // 64-bit version
  1427. //
  1428. status = Copy_LOADER_PARAMETER_BLOCK( BlAmd64LoaderBlock32, BlAmd64LoaderBlock64 );
  1429. if (status != ESUCCESS) {
  1430. return status;
  1431. }
  1432. //
  1433. // Build the loader block extension
  1434. //
  1435. status = BlAmd64BuildLoaderBlockExtension64();
  1436. if (status != ESUCCESS) {
  1437. return status;
  1438. }
  1439. return ESUCCESS;
  1440. }
  1441. ARC_STATUS
  1442. BlAmd64TransferMemoryAllocationDescriptors(
  1443. VOID
  1444. )
  1445. /*++
  1446. Routine Description:
  1447. This routine transfers all of the 32-bit memory allocation descriptors
  1448. to a 64-bit list.
  1449. The storage for the 64-bit memory allocation descriptors has been
  1450. preallocated by a previous call to
  1451. BlAmd64AllocateMemoryAllocationDescriptors(). This memory is described
  1452. by BlAmd64DescriptorArray and BlAmd64DescriptorArraySize.
  1453. Arguments:
  1454. None.
  1455. Return Value:
  1456. The status of the operation.
  1457. --*/
  1458. {
  1459. ARC_STATUS status;
  1460. PMEMORY_ALLOCATION_DESCRIPTOR memDesc32;
  1461. PMEMORY_ALLOCATION_DESCRIPTOR_64 memDesc64;
  1462. PLIST_ENTRY listHead;
  1463. PLIST_ENTRY listEntry;
  1464. LONG descriptorCount;
  1465. //
  1466. // Modify some descriptor types. All of the descriptors of type
  1467. // LoaderMemoryData really contain things that won't be used in 64-bit
  1468. // mode, such as 32-bit page tables and the like.
  1469. //
  1470. // The descriptors that we really want to stick around are allocated with
  1471. // LoaderAmd64MemoryData.
  1472. //
  1473. // Perform two memory descriptor list search-and-replacements:
  1474. //
  1475. // LoaderMemoryData -> LoaderOSLoaderHeap
  1476. //
  1477. // These desriptors will be freed during kernel init phase 1
  1478. //
  1479. // LoaderAmd64MemoryData -> LoaderMemoryData
  1480. //
  1481. // This stuff will be kept around
  1482. //
  1483. //
  1484. // All existing LoaderMemoryData refers to structures that are not useful
  1485. // once running in long mode. However, we're using some of the structures
  1486. // now (32-bit page tables for example), so convert them to
  1487. // type LoaderOsloaderHeap, which will be eventually freed by the kernel.
  1488. //
  1489. BlAmd64ReplaceMemoryDescriptorType(LoaderMemoryData,
  1490. LoaderOsloaderHeap,
  1491. TRUE);
  1492. //
  1493. // Same for LoaderStartupPcrPage
  1494. //
  1495. BlAmd64ReplaceMemoryDescriptorType(LoaderStartupPcrPage,
  1496. LoaderOsloaderHeap,
  1497. TRUE);
  1498. //
  1499. // All of the permanent structures that need to be around for longmode
  1500. // were temporarily allocated with LoaderAmd64MemoryData. Convert all
  1501. // of those to LoaderMemoryData now.
  1502. //
  1503. BlAmd64ReplaceMemoryDescriptorType(LoaderAmd64MemoryData,
  1504. LoaderMemoryData,
  1505. TRUE);
  1506. //
  1507. // Now walk the 32-bit memory descriptors, filling in and inserting a
  1508. // 64-bit version into BlAmd64LoaderBlock64.
  1509. //
  1510. InitializeListHead64( &BlAmd64LoaderBlock64->MemoryDescriptorListHead );
  1511. memDesc64 = BlAmd64DescriptorArray;
  1512. descriptorCount = BlAmd64DescriptorArraySize;
  1513. listHead = &BlAmd64LoaderBlock32->MemoryDescriptorListHead;
  1514. listEntry = listHead->Flink;
  1515. while (listEntry != listHead && descriptorCount > 0) {
  1516. memDesc32 = CONTAINING_RECORD( listEntry,
  1517. MEMORY_ALLOCATION_DESCRIPTOR,
  1518. ListEntry );
  1519. status = Copy_MEMORY_ALLOCATION_DESCRIPTOR( memDesc32, memDesc64 );
  1520. if (status != ESUCCESS) {
  1521. return status;
  1522. }
  1523. #if DBG
  1524. DbgPrint("Base 0x%08x size 0x%02x %s\n",
  1525. memDesc32->BasePage,
  1526. memDesc32->PageCount,
  1527. BlAmd64MemoryDescriptorText[memDesc32->MemoryType]);
  1528. #endif
  1529. InsertTailList64( &BlAmd64LoaderBlock64->MemoryDescriptorListHead,
  1530. &memDesc64->ListEntry );
  1531. listEntry = listEntry->Flink;
  1532. memDesc64 = memDesc64 + 1;
  1533. descriptorCount -= 1;
  1534. }
  1535. ASSERT( descriptorCount >= 0 && listEntry == listHead );
  1536. return ESUCCESS;
  1537. }
  1538. ARC_STATUS
  1539. BlAmd64AllocateMemoryAllocationDescriptors(
  1540. VOID
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. This routine preallocates a quantity of memory sufficient to contain
  1545. a 64-bit version of each memory allocation descriptor.
  1546. The resultant memory is described in two globals: BlAmd64DescriptorArray
  1547. and BlAmd64DescriptorArrayCount.
  1548. Arguments:
  1549. None.
  1550. Return Value:
  1551. The status of the operation.
  1552. --*/
  1553. {
  1554. PLIST_ENTRY listHead;
  1555. PLIST_ENTRY listEntry;
  1556. ULONG descriptorCount;
  1557. ULONG arraySize;
  1558. PMEMORY_ALLOCATION_DESCRIPTOR_64 descriptorArray;
  1559. //
  1560. // Count the number of descriptors needed.
  1561. //
  1562. descriptorCount = 0;
  1563. listHead = &BlAmd64LoaderBlock32->MemoryDescriptorListHead;
  1564. listEntry = listHead->Flink;
  1565. while (listEntry != listHead) {
  1566. descriptorCount += 1;
  1567. listEntry = listEntry->Flink;
  1568. }
  1569. //
  1570. // Allocate memory sufficient to contain them all in 64-bit form.
  1571. //
  1572. arraySize = descriptorCount *
  1573. sizeof(MEMORY_ALLOCATION_DESCRIPTOR_64);
  1574. descriptorArray = BlAllocateHeap(arraySize);
  1575. if (descriptorArray == NULL) {
  1576. return ENOMEM;
  1577. }
  1578. BlAmd64DescriptorArray = descriptorArray;
  1579. BlAmd64DescriptorArraySize = descriptorCount;
  1580. return ESUCCESS;
  1581. }
  1582. ARC_STATUS
  1583. BlAmd64TransferLoadedModuleState(
  1584. VOID
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. This routine transfers the 32-bit list of LDR_DATA_TABLE_ENTRY structures
  1589. to an equivalent 64-bit list.
  1590. Arguments:
  1591. None.
  1592. Return Value:
  1593. The status of the operation.
  1594. --*/
  1595. {
  1596. PLDR_DATA_TABLE_ENTRY dataTableEntry32;
  1597. PLDR_DATA_TABLE_ENTRY_64 dataTableEntry64;
  1598. PLIST_ENTRY listEntry;
  1599. PLIST_ENTRY listHead;
  1600. ARC_STATUS status;
  1601. InitializeListHead64( &BlAmd64LoaderBlock64->LoadOrderListHead );
  1602. //
  1603. // For each of the LDR_DATA_TABLE_ENTRY structures in the 32-bit
  1604. // loader parameter block, create a 64-bit LDR_DATA_TABLE_ENTRY
  1605. // and queue it on the 64-bit loader parameter block.
  1606. //
  1607. listHead = &BlAmd64LoaderBlock32->LoadOrderListHead;
  1608. listEntry = listHead->Flink;
  1609. while (listEntry != listHead) {
  1610. dataTableEntry32 = CONTAINING_RECORD( listEntry,
  1611. LDR_DATA_TABLE_ENTRY,
  1612. InLoadOrderLinks );
  1613. status = BlAmd64BuildLdrDataTableEntry64( dataTableEntry32,
  1614. &dataTableEntry64 );
  1615. if (status != ESUCCESS) {
  1616. return status;
  1617. }
  1618. //
  1619. // Insert it into the 64-bit loader block's data table queue.
  1620. //
  1621. InsertTailList64( &BlAmd64LoaderBlock64->LoadOrderListHead,
  1622. &dataTableEntry64->InLoadOrderLinks );
  1623. listEntry = listEntry->Flink;
  1624. }
  1625. return ESUCCESS;
  1626. }
  1627. ARC_STATUS
  1628. BlAmd64BuildLdrDataTableEntry64(
  1629. IN PLDR_DATA_TABLE_ENTRY DataTableEntry32,
  1630. OUT PLDR_DATA_TABLE_ENTRY_64 *DataTableEntry64
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. This routine transfers the contents of a single 32-bit
  1635. LDR_DATA_TABLE_ENTRY structure to the 64-bit equivalent.
  1636. Arguments:
  1637. DataTableEntry32 - Supplies a pointer to the source structure.
  1638. DataTableEntry64 - Supplies a pointer to the destination pointer to
  1639. the created structure.
  1640. Return Value:
  1641. The status of the operation.
  1642. --*/
  1643. {
  1644. ARC_STATUS status;
  1645. PLDR_DATA_TABLE_ENTRY_64 dataTableEntry64;
  1646. //
  1647. // Allocate a 64-bit data table entry and transfer the 32-bit
  1648. // contents
  1649. //
  1650. dataTableEntry64 = BlAllocateHeap( sizeof(LDR_DATA_TABLE_ENTRY_64) );
  1651. if (dataTableEntry64 == NULL) {
  1652. return ENOMEM;
  1653. }
  1654. status = Copy_LDR_DATA_TABLE_ENTRY( DataTableEntry32, dataTableEntry64 );
  1655. if (status != ESUCCESS) {
  1656. return status;
  1657. }
  1658. *DataTableEntry64 = dataTableEntry64;
  1659. //
  1660. // Later on, we'll need to determine the 64-bit copy of this data
  1661. // table entry. Store the 64-bit pointer to the copy here.
  1662. //
  1663. *((POINTER64 *)&DataTableEntry32->DllBase) = PTR_64(dataTableEntry64);
  1664. return ESUCCESS;
  1665. }
  1666. ARC_STATUS
  1667. BlAmd64BuildLoaderBlockExtension64(
  1668. VOID
  1669. )
  1670. /*++
  1671. Routine Description:
  1672. This routine transfers the contents of the 32-bit loader block
  1673. extension to a 64-bit equivalent.
  1674. Arguments:
  1675. None.
  1676. Return Value:
  1677. The status of the operation.
  1678. --*/
  1679. {
  1680. PLOADER_PARAMETER_EXTENSION_64 loaderExtension;
  1681. ARC_STATUS status;
  1682. //
  1683. // Allocate the 64-bit extension and transfer the contents of the
  1684. // 32-bit block.
  1685. //
  1686. loaderExtension = BlAllocateHeap( sizeof(LOADER_PARAMETER_EXTENSION_64) );
  1687. if (loaderExtension == NULL) {
  1688. return ENOMEM;
  1689. }
  1690. //
  1691. // Perform automatic copy of most fields
  1692. //
  1693. status = Copy_LOADER_PARAMETER_EXTENSION( BlLoaderBlock->Extension,
  1694. loaderExtension );
  1695. if (status != ESUCCESS) {
  1696. return status;
  1697. }
  1698. //
  1699. // Manually fix up remaining fields
  1700. //
  1701. loaderExtension->Size = sizeof(LOADER_PARAMETER_EXTENSION_64);
  1702. BlAmd64LoaderBlock64->Extension = PTR_64(loaderExtension);
  1703. return ESUCCESS;
  1704. }
  1705. ARC_STATUS
  1706. BlAmd64TransferBootDriverNodes(
  1707. VOID
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. This routine transfers the 32-bit list of BOOT_DRIVER_NODE structures
  1712. to an equivalent 64-bit list.
  1713. Arguments:
  1714. None.
  1715. Return Value:
  1716. The status of the operation.
  1717. --*/
  1718. {
  1719. PBOOT_DRIVER_LIST_ENTRY driverListEntry32;
  1720. PBOOT_DRIVER_LIST_ENTRY_64 driverListEntry64;
  1721. PBOOT_DRIVER_NODE driverNode32;
  1722. PBOOT_DRIVER_NODE_64 driverNode64;
  1723. POINTER64 dataTableEntry64;
  1724. PKLDR_DATA_TABLE_ENTRY dataTableEntry;
  1725. PLIST_ENTRY listEntry;
  1726. PLIST_ENTRY listHead;
  1727. ARC_STATUS status;
  1728. InitializeListHead64( &BlAmd64LoaderBlock64->BootDriverListHead );
  1729. //
  1730. // For each of the BOOT_DRIVER_NODE structures in the 32-bit
  1731. // loader parameter block, create a 64-bit BOOT_DRIVER_NODE
  1732. // and (possibly) associated LDR_DATA_TABLE_ENTRY structure.
  1733. //
  1734. listHead = &BlAmd64LoaderBlock32->BootDriverListHead;
  1735. listEntry = listHead->Flink;
  1736. while (listEntry != listHead) {
  1737. driverListEntry32 = CONTAINING_RECORD( listEntry,
  1738. BOOT_DRIVER_LIST_ENTRY,
  1739. Link );
  1740. driverNode32 = CONTAINING_RECORD( driverListEntry32,
  1741. BOOT_DRIVER_NODE,
  1742. ListEntry );
  1743. driverNode64 = BlAllocateHeap( sizeof(BOOT_DRIVER_NODE_64) );
  1744. if (driverNode64 == NULL) {
  1745. return ENOMEM;
  1746. }
  1747. status = Copy_BOOT_DRIVER_NODE( driverNode32, driverNode64 );
  1748. if (status != ESUCCESS) {
  1749. return status;
  1750. }
  1751. dataTableEntry = driverNode32->ListEntry.LdrEntry;
  1752. if (dataTableEntry != NULL) {
  1753. //
  1754. // There is already a 64-bit copy of this table entry, and we
  1755. // stored a pointer to it at DllBase.
  1756. //
  1757. dataTableEntry64 = *((POINTER64 *)&dataTableEntry->DllBase);
  1758. driverNode64->ListEntry.LdrEntry = dataTableEntry64;
  1759. }
  1760. //
  1761. // Now insert the driver list entry into the 64-bit loader block.
  1762. //
  1763. InsertTailList64( &BlAmd64LoaderBlock64->BootDriverListHead,
  1764. &driverNode64->ListEntry.Link );
  1765. listEntry = listEntry->Flink;
  1766. }
  1767. return ESUCCESS;
  1768. }
  1769. ARC_STATUS
  1770. BlAmd64CheckForLongMode(
  1771. IN ULONG LoadDeviceId,
  1772. IN OUT PCHAR KernelPath,
  1773. IN PCHAR KernelFileName
  1774. )
  1775. /*++
  1776. Routine Description:
  1777. This routine examines a kernel image and determines whether it was
  1778. compiled for AMD64. The global BlAmd64UseLongMode is set to non-zero
  1779. if a long-mode kernel is discovered.
  1780. Arguments:
  1781. LoadDeviceId - Supplies the load device identifier.
  1782. KernelPath - Supplies a pointer to the path to the kernel directory.
  1783. Upon successful return, KernelFileName will be appended
  1784. to this path.
  1785. KernelFileName - Supplies a pointer to the name of the kernel file.
  1786. Return Value:
  1787. The status of the operation. Upon successful completion ESUCCESS
  1788. is returned, whether long mode capability was detected or not.
  1789. --*/
  1790. {
  1791. CHAR localBufferSpace[ SECTOR_SIZE * 2 + SECTOR_SIZE - 1 ];
  1792. PCHAR localBuffer;
  1793. ULONG fileId;
  1794. PIMAGE_NT_HEADERS32 ntHeaders;
  1795. ARC_STATUS status;
  1796. ULONG bytesRead;
  1797. PCHAR kernelNameTarget;
  1798. //
  1799. // File I/O here must be sector-aligned.
  1800. //
  1801. localBuffer = (PCHAR)
  1802. (((ULONG)localBufferSpace + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1));
  1803. //
  1804. // Build the path to the kernel and open it.
  1805. //
  1806. kernelNameTarget = KernelPath + strlen(KernelPath);
  1807. strcpy(kernelNameTarget, KernelFileName);
  1808. status = BlOpen( LoadDeviceId, KernelPath, ArcOpenReadOnly, &fileId );
  1809. *kernelNameTarget = '\0'; // Restore the kernel path, assuming
  1810. // failure.
  1811. if (status != ESUCCESS) {
  1812. return status;
  1813. }
  1814. //
  1815. // Read the PE image header
  1816. //
  1817. status = BlRead( fileId, localBuffer, SECTOR_SIZE * 2, &bytesRead );
  1818. BlClose( fileId );
  1819. //
  1820. // Determine whether the image header is valid, and if so whether
  1821. // the image is AMD64, I386 or something else.
  1822. //
  1823. ntHeaders = RtlImageNtHeader( localBuffer );
  1824. if (ntHeaders == NULL) {
  1825. return EBADF;
  1826. }
  1827. if (IMAGE_64BIT(ntHeaders)) {
  1828. //
  1829. // Return with the kernel name appended to the path
  1830. //
  1831. if (BlIsAmd64Supported() != FALSE) {
  1832. strcpy(kernelNameTarget, KernelFileName);
  1833. BlAmd64UseLongMode = TRUE;
  1834. status = ESUCCESS;
  1835. } else {
  1836. //
  1837. // We have an AMD64 image, but the processor does not support
  1838. // AMD64. There is nothing we can do.
  1839. //
  1840. status = EBADF;
  1841. }
  1842. } else if (IMAGE_32BIT(ntHeaders)) {
  1843. ASSERT( BlAmd64UseLongMode == FALSE );
  1844. status = ESUCCESS;
  1845. } else {
  1846. status = EBADF;
  1847. }
  1848. return status;
  1849. }
  1850. ARC_STATUS
  1851. BlAmd64PrepareSystemStructures(
  1852. VOID
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. This routine allocates and initializes several structures necessary
  1857. for transfer to an AMD64 kernel. These structures include:
  1858. KPCR
  1859. GDT
  1860. IDT
  1861. KTSS64
  1862. EPROCESS
  1863. ETHREAD
  1864. Idle thread stack
  1865. DPC stack
  1866. Arguments:
  1867. None.
  1868. Return Value:
  1869. The status of the operation.
  1870. --*/
  1871. {
  1872. PCHAR processorData;
  1873. ULONG dataSize;
  1874. ULONG descriptor;
  1875. ULONG stackOffset;
  1876. PKTSS64_64 sysTss64;
  1877. PCHAR idleStack;
  1878. PCHAR dpcStack;
  1879. PCHAR doubleFaultStack;
  1880. PCHAR mcaStack;
  1881. PVOID gdt64;
  1882. PVOID idt64;
  1883. ARC_STATUS status;
  1884. //
  1885. // Calculate the cumulative, rounded size of the various structures that
  1886. // we need, and allocate a sufficient number of pages.
  1887. //
  1888. dataSize = ROUNDUP16(GDT_64_SIZE) +
  1889. ROUNDUP16(IDT_64_SIZE) +
  1890. ROUNDUP16(FIELD_OFFSET(KTSS64_64,IoMap));
  1891. dataSize = ROUNDUP_PAGE(dataSize);
  1892. stackOffset = dataSize;
  1893. dataSize += KERNEL_STACK_SIZE_64 + // Idle thread stack
  1894. KERNEL_STACK_SIZE_64 + // DPC stack
  1895. DOUBLE_FAULT_STACK_SIZE_64 + // Double fault stack
  1896. MCA_EXCEPTION_STACK_SIZE_64; // MCA exception stack
  1897. //
  1898. // dataSize is still page aligned.
  1899. //
  1900. status = BlAllocateDescriptor( LoaderAmd64MemoryData,
  1901. 0,
  1902. dataSize / PAGE_SIZE,
  1903. &descriptor );
  1904. if (status != ESUCCESS) {
  1905. return status;
  1906. }
  1907. processorData = (PCHAR)(descriptor * PAGE_SIZE | KSEG0_BASE_X86);
  1908. //
  1909. // Zero the block that was just allocated, then get local pointers to the
  1910. // various structures within.
  1911. //
  1912. RtlZeroMemory( processorData, dataSize );
  1913. //
  1914. // Assign the stack pointers. Stack pointers start at the TOP of their
  1915. // respective stack areas.
  1916. //
  1917. idleStack = processorData + stackOffset + KERNEL_STACK_SIZE_64;
  1918. dpcStack = idleStack + KERNEL_STACK_SIZE_64;
  1919. doubleFaultStack = dpcStack + DOUBLE_FAULT_STACK_SIZE_64;
  1920. mcaStack = doubleFaultStack + MCA_EXCEPTION_STACK_SIZE_64;
  1921. //
  1922. // Record the idle stack base so that we can switch to it in amd64s.asm
  1923. //
  1924. BlAmd64IdleStack64 = PTR_64(idleStack);
  1925. //
  1926. // Assign pointers to GDT, IDT and KTSS64.
  1927. //
  1928. gdt64 = (PVOID)processorData;
  1929. processorData += ROUNDUP16(GDT_64_SIZE);
  1930. idt64 = (PVOID)processorData;
  1931. processorData += ROUNDUP16(IDT_64_SIZE);
  1932. sysTss64 = (PKTSS64_64)processorData;
  1933. processorData += ROUNDUP16(FIELD_OFFSET(KTSS64_64,IoMap));
  1934. //
  1935. // Build the GDT. This is done in amd64.c as it involves AMD64
  1936. // structure definitions. The IDT remains zeroed.
  1937. //
  1938. BlAmd64BuildAmd64GDT( sysTss64, gdt64 );
  1939. //
  1940. // Build the pseudo-descriptors for the GDT and IDT. These will
  1941. // be referenced during the long-mode transition in amd64s.asm.
  1942. //
  1943. BlAmd64GdtDescriptor.Limit = (USHORT)(GDT_64_SIZE - 1);
  1944. BlAmd64GdtDescriptor.Base = PTR_64(gdt64);
  1945. BlAmd64IdtDescriptor.Limit = (USHORT)(IDT_64_SIZE - 1);
  1946. BlAmd64IdtDescriptor.Base = PTR_64(idt64);
  1947. //
  1948. // Build another GDT pseudo-descriptor, this one with a 32-bit
  1949. // base. This base address must be a 32-bit address that is addressible
  1950. // from long mode during init, so use the mapping in the identity mapped
  1951. // region.
  1952. //
  1953. BlAmd32GdtDescriptor.Limit = (USHORT)(GDT_64_SIZE - 1);
  1954. BlAmd32GdtDescriptor.Base = (ULONG)gdt64 ^ KSEG0_BASE_X86;
  1955. //
  1956. // Initialize the system TSS
  1957. //
  1958. sysTss64->Rsp0 = PTR_64(idleStack);
  1959. sysTss64->Ist[TSS64_IST_PANIC] = PTR_64(doubleFaultStack);
  1960. sysTss64->Ist[TSS64_IST_MCA] = PTR_64(mcaStack);
  1961. //
  1962. // Fill required fields within the loader block
  1963. //
  1964. BlAmd64LoaderBlock64->KernelStack = PTR_64(dpcStack);
  1965. return ESUCCESS;
  1966. }
  1967. VOID
  1968. BlAmd64ReplaceMemoryDescriptorType(
  1969. IN TYPE_OF_MEMORY Target,
  1970. IN TYPE_OF_MEMORY Replacement,
  1971. IN BOOLEAN Coallesce
  1972. )
  1973. /*++
  1974. Routine Description:
  1975. This routine walks the 32-bit memory allocation descriptor list and
  1976. performs a "search and replace" of the types therein.
  1977. Optionally, it will coallesce each successful replacement with
  1978. adjacent descriptors of like type.
  1979. Arguments:
  1980. Target - The descriptor type to search for
  1981. Replacement - The type with which to replace each located Target type.
  1982. Coallesce - If !FALSE, indicates that each successful replacement should
  1983. be coallesced with any like-typed neighbors.
  1984. Return Value:
  1985. None.
  1986. --*/
  1987. {
  1988. PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
  1989. PMEMORY_ALLOCATION_DESCRIPTOR adjacentDescriptor;
  1990. PLIST_ENTRY listHead;
  1991. PLIST_ENTRY listEntry;
  1992. PLIST_ENTRY adjacentListEntry;
  1993. listHead = &BlAmd64LoaderBlock32->MemoryDescriptorListHead;
  1994. listEntry = listHead;
  1995. while (TRUE) {
  1996. listEntry = listEntry->Flink;
  1997. if (listEntry == listHead) {
  1998. break;
  1999. }
  2000. descriptor = CONTAINING_RECORD(listEntry,
  2001. MEMORY_ALLOCATION_DESCRIPTOR,
  2002. ListEntry);
  2003. if (descriptor->MemoryType != Target) {
  2004. continue;
  2005. }
  2006. descriptor->MemoryType = Replacement;
  2007. if (Coallesce == FALSE) {
  2008. //
  2009. // Do not attempt to coallesce
  2010. //
  2011. continue;
  2012. }
  2013. //
  2014. // Now attempt to coallesce the descriptor. First try the
  2015. // next descriptor.
  2016. //
  2017. adjacentListEntry = listEntry->Flink;
  2018. if (adjacentListEntry != listHead) {
  2019. adjacentDescriptor = CONTAINING_RECORD(adjacentListEntry,
  2020. MEMORY_ALLOCATION_DESCRIPTOR,
  2021. ListEntry);
  2022. if (adjacentDescriptor->MemoryType == descriptor->MemoryType &&
  2023. descriptor->BasePage + descriptor->PageCount ==
  2024. adjacentDescriptor->BasePage) {
  2025. descriptor->PageCount += adjacentDescriptor->PageCount;
  2026. BlRemoveDescriptor(adjacentDescriptor);
  2027. }
  2028. }
  2029. //
  2030. // Now try the previous descriptor.
  2031. //
  2032. adjacentListEntry = listEntry->Blink;
  2033. if (adjacentListEntry != listHead) {
  2034. adjacentDescriptor = CONTAINING_RECORD(adjacentListEntry,
  2035. MEMORY_ALLOCATION_DESCRIPTOR,
  2036. ListEntry);
  2037. if (adjacentDescriptor->MemoryType == descriptor->MemoryType &&
  2038. adjacentDescriptor->BasePage + adjacentDescriptor->PageCount ==
  2039. descriptor->BasePage) {
  2040. descriptor->PageCount += adjacentDescriptor->PageCount;
  2041. descriptor->BasePage -= adjacentDescriptor->PageCount;
  2042. BlRemoveDescriptor(adjacentDescriptor);
  2043. }
  2044. }
  2045. }
  2046. }