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.

2510 lines
80 KiB

  1. /*++
  2. Copyright (c) 1995 Intel Corporation
  3. Module Name:
  4. i64efi.c
  5. Abstract:
  6. This module implements the routines that transfer control
  7. from the kernel to the EFI code.
  8. Author:
  9. Bernard Lint
  10. M. Jayakumar (Muthurajan.Jayakumar@hotmail.com)
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. Neal Vu (neal.vu@intel.com), 03-Apr-2001:
  15. Added HalpGetSmBiosVersion.
  16. --*/
  17. #include "halp.h"
  18. #include "arc.h"
  19. #include "arccodes.h"
  20. #include "i64fw.h"
  21. #include "floatem.h"
  22. #include "fpswa.h"
  23. #include <smbios.h>
  24. extern ULONGLONG PhysicalIOBase;
  25. extern ULONG HalpPlatformPropertiesEfiFlags;
  26. BOOLEAN
  27. HalpCompareEfiGuid (
  28. IN EFI_GUID CheckGuid,
  29. IN EFI_GUID ReferenceGuid
  30. );
  31. BOOLEAN
  32. MmSetPageProtection(
  33. IN PVOID VirtualAddress,
  34. IN SIZE_T NumberOfBytes,
  35. IN ULONG NewProtect
  36. );
  37. EFI_STATUS
  38. HalpCallEfiPhysicalEx(
  39. IN ULONGLONG Arg1,
  40. IN ULONGLONG Arg2,
  41. IN ULONGLONG Arg3,
  42. IN ULONGLONG Arg4,
  43. IN ULONGLONG Arg5,
  44. IN ULONGLONG Arg6,
  45. IN ULONGLONG EP,
  46. IN ULONGLONG GP,
  47. IN ULONGLONG StackPointer,
  48. IN ULONGLONG BackingStorePointer
  49. );
  50. typedef
  51. EFI_STATUS
  52. (*HALP_EFI_CALL)(
  53. IN ULONGLONG Arg1,
  54. IN ULONGLONG Arg2,
  55. IN ULONGLONG Arg3,
  56. IN ULONGLONG Arg4,
  57. IN ULONGLONG Arg5,
  58. IN ULONGLONG Arg6,
  59. IN ULONGLONG EP,
  60. IN ULONGLONG GP
  61. );
  62. EFI_STATUS
  63. HalpCallEfiPhysical(
  64. IN ULONGLONG Arg1,
  65. IN ULONGLONG Arg2,
  66. IN ULONGLONG Arg3,
  67. IN ULONGLONG Arg4,
  68. IN ULONGLONG Arg5,
  69. IN ULONGLONG Arg6,
  70. IN ULONGLONG EP,
  71. IN ULONGLONG GP
  72. );
  73. EFI_STATUS
  74. HalpCallEfiVirtual(
  75. IN ULONGLONG Arg1,
  76. IN ULONGLONG Arg2,
  77. IN ULONGLONG Arg3,
  78. IN ULONGLONG Arg4,
  79. IN ULONGLONG Arg5,
  80. IN ULONGLONG Arg6,
  81. IN ULONGLONG EP,
  82. IN ULONGLONG GP
  83. );
  84. LONG
  85. HalFpEmulate(
  86. ULONG trap_type,
  87. BUNDLE *pbundle,
  88. ULONGLONG *pipsr,
  89. ULONGLONG *pfpsr,
  90. ULONGLONG *pisr,
  91. ULONGLONG *ppreds,
  92. ULONGLONG *pifs,
  93. FP_STATE *fp_state
  94. );
  95. BOOLEAN
  96. HalEFIFpSwa(
  97. VOID
  98. );
  99. VOID
  100. HalpFpswaPlabelFixup(
  101. EFI_MEMORY_DESCRIPTOR *EfiVirtualMemoryMapPtr,
  102. ULONGLONG MapEntries,
  103. ULONGLONG EfiDescriptorSize,
  104. PPLABEL_DESCRIPTOR PlabelPointer
  105. );
  106. PUCHAR
  107. HalpGetSmBiosVersion (
  108. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  109. );
  110. //
  111. // External global data
  112. //
  113. extern HALP_SAL_PAL_DATA HalpSalPalData;
  114. extern ULONGLONG HalpVirtPalProcPointer;
  115. extern ULONGLONG HalpSalProcPointer;
  116. extern ULONGLONG HalpSalProcGlobalPointer;
  117. extern KSPIN_LOCK HalpSalSpinLock;
  118. extern KSPIN_LOCK HalpSalStateInfoSpinLock;
  119. extern KSPIN_LOCK HalpMcaSpinLock;
  120. extern KSPIN_LOCK HalpInitSpinLock;
  121. extern KSPIN_LOCK HalpCmcSpinLock;
  122. extern KSPIN_LOCK HalpCpeSpinLock;
  123. #define VENDOR_SPECIFIC_GUID \
  124. { 0xa3c72e56, 0x4c35, 0x11d3, 0x8a, 0x03, 0x0, 0xa0, 0xc9, 0x06, 0xad, 0xec }
  125. #define ConfigGuidOffset 0x100
  126. #define ConfigTableOffset 0x200
  127. #define VariableNameOffset 0x100
  128. #define VendorGuidOffset 0x200
  129. #define AttributeOffset 0x300
  130. #define DataSizeOffset 0x400
  131. #define DataBufferOffset 0x500
  132. #define EndOfCommonDataOffset 0x600
  133. //
  134. // Read Variable and Write Variable will not be called till the copying out of
  135. // Memory Descriptors is done. Because the lock is released before copying and we are using
  136. // the same offset for read/write variable as well as memory layout calls.
  137. //
  138. #define MemoryMapSizeOffset 0x100
  139. #define DescriptorSizeOffset 0x200
  140. #define DescriptorVersionOffset 0x300
  141. #define MemoryMapOffset 0x400
  142. #define OptionROMAddress 0x100000
  143. #define FP_EMUL_ERROR -1
  144. SST_MEMORY_LIST PalCode;
  145. NTSTATUS EfiInitStatus = STATUS_UNSUCCESSFUL;
  146. ULONGLONG PalTrMask;
  147. EFI_GUID CheckGuid;
  148. EFI_GUID SalGuid = SAL_SYSTEM_TABLE_GUID;
  149. EFI_GUID VendorGuid;
  150. PUCHAR HalpVendorGuidPhysPtr;
  151. PUCHAR HalpVendorGuidVirtualPtr;
  152. EFI_SYSTEM_TABLE *EfiSysTableVirtualPtr;
  153. EFI_SYSTEM_TABLE *EfiSysTableVirtualPtrCpy;
  154. EFI_RUNTIME_SERVICES *EfiRSVirtualPtr;
  155. EFI_BOOT_SERVICES *EfiBootVirtualPtr;
  156. PLABEL_DESCRIPTOR *EfiVirtualGetVariablePtr; // Get Variable
  157. PLABEL_DESCRIPTOR *EfiVirtualGetNextVariableNamePtr; // Get NextVariable Name
  158. PLABEL_DESCRIPTOR *EfiVirtualSetVariablePtr; // Set Variable
  159. PLABEL_DESCRIPTOR *EfiVirtualGetTimePtr; // Get Time
  160. PLABEL_DESCRIPTOR *EfiVirtualSetTimePtr; // Set Time
  161. PLABEL_DESCRIPTOR *EfiSetVirtualAddressMapPtr; // Set Virtual Address Map
  162. PLABEL_DESCRIPTOR *EfiResetSystemPtr; // Reboot
  163. PULONGLONG AttributePtr;
  164. ULONGLONG EfiAttribute;
  165. PULONGLONG DataSizePtr;
  166. ULONGLONG EfiDataSize;
  167. ULONGLONG EfiMemoryMapSize,EfiDescriptorSize,EfiMapEntries;
  168. ULONG EfiDescriptorVersion;
  169. PUCHAR HalpVirtualCommonDataPointer;
  170. PUCHAR HalpPhysCommonDataPointer;
  171. PUCHAR HalpVariableNamePhysPtr;
  172. PUCHAR HalpVariableAttributesPhysPtr;
  173. PUCHAR HalpDataSizePhysPtr;
  174. PUCHAR HalpDataPhysPtr;
  175. PUCHAR HalpMemoryMapSizePhysPtr;
  176. PUCHAR HalpMemoryMapPhysPtr;
  177. PUCHAR HalpDescriptorSizePhysPtr;
  178. PUCHAR HalpDescriptorVersionPhysPtr;
  179. PUCHAR HalpVariableNameVirtualPtr;
  180. PUCHAR HalpVariableAttributesVirtualPtr;
  181. PUCHAR HalpDataSizeVirtualPtr;
  182. PUCHAR HalpDataVirtualPtr;
  183. PUCHAR HalpCommonDataEndPtr;
  184. PUCHAR HalpMemoryMapSizeVirtualPtr;
  185. PVOID HalpMemoryMapVirtualPtr;
  186. PUCHAR HalpDescriptorSizeVirtualPtr;
  187. PUCHAR HalpDescriptorVersionVirtualPtr;
  188. EFI_FPSWA HalpFpEmulate;
  189. KSPIN_LOCK EFIMPLock;
  190. UCHAR HalpSetVirtualAddressMapCount;
  191. ULONG HalpOsBootRendezVector;
  192. BOOLEAN
  193. HalpCompareEfiGuid (
  194. IN EFI_GUID CheckGuid,
  195. IN EFI_GUID ReferenceGuid
  196. )
  197. /*++
  198. --*/
  199. {
  200. USHORT i;
  201. USHORT TotalArrayLength = 8;
  202. if (CheckGuid.Data1 != ReferenceGuid.Data1) {
  203. return FALSE;
  204. } else if (CheckGuid.Data2 != ReferenceGuid.Data2) {
  205. return FALSE;
  206. } else if (CheckGuid.Data3 != ReferenceGuid.Data3) {
  207. return FALSE;
  208. }
  209. for (i = 0; i != TotalArrayLength; i++) {
  210. if (CheckGuid.Data4[i] != ReferenceGuid.Data4[i])
  211. return FALSE;
  212. }
  213. return TRUE;
  214. } // HalpCompareEfiGuid()
  215. BOOLEAN
  216. HalpAllocateProcessorPhysicalCallStacks(
  217. VOID
  218. )
  219. /*++
  220. Routine Description:
  221. This function allocates per-processor memory and backstore stacks
  222. used by FW calls in physical mode.
  223. Arguments:
  224. None.
  225. Return Value:
  226. TRUE : Allocation and Initialization were successful.
  227. FALSE : Failure.
  228. --*/
  229. {
  230. PVOID Addr;
  231. SIZE_T Length;
  232. PHYSICAL_ADDRESS PhysicalAddr;
  233. //
  234. // Allocate stack and backing store space for physical mode firmware
  235. // calls.
  236. //
  237. Length = HALP_FW_MEMORY_STACK_SIZE + HALP_FW_BACKING_STORE_SIZE;
  238. PhysicalAddr.QuadPart = 0xffffffffffffffffI64;
  239. Addr = MmAllocateContiguousMemory(Length, PhysicalAddr);
  240. if (Addr == NULL) {
  241. HalDebugPrint((HAL_ERROR, "SAL_PAL: can't allocate stack space for "
  242. "physical mode firmware calls.\n"));
  243. return FALSE;
  244. }
  245. //
  246. // Store a pointer to the allocated stacks in the PCR.
  247. //
  248. PCR->HalReserved[PROCESSOR_PHYSICAL_FW_STACK_INDEX]
  249. = (ULONGLONG) (MmGetPhysicalAddress(Addr).QuadPart);
  250. return TRUE;
  251. } // HalpAllocateProcessorPhysicalCallStacks()
  252. VOID
  253. HalpInitSalPalWorkArounds(
  254. VOID
  255. )
  256. /*++
  257. Routine Description:
  258. This function determines and initializes the FW workarounds.
  259. Arguments:
  260. None.
  261. Return Value:
  262. None.
  263. Globals:
  264. Notes: This function is being called at the end of HalpInitSalPal.
  265. It should not access SST members if this SAL table is unmapped.
  266. --*/
  267. {
  268. NTSTATUS status;
  269. extern FADT HalpFixedAcpiDescTable;
  270. #define HalpIsIntelOEM() \
  271. ( !_strnicmp( HalpFixedAcpiDescTable.Header.OEMID, "INTEL", 5 ) )
  272. #define HalpIsBigSur() \
  273. ( !strncmp( HalpFixedAcpiDescTable.Header.OEMTableID, "W460GXBS", 8 ) )
  274. #define HalpIsLion() \
  275. ( !strncmp( HalpFixedAcpiDescTable.Header.OEMTableID, "SR460AC", 7 ) )
  276. #define HalpIsIntelBigSur() \
  277. ( HalpIsIntelOEM() && HalpIsBigSur() )
  278. if ( HalpIsIntelOEM() ) {
  279. //
  280. // If Intel BigSur and FW build < 103 (checked as Pal_A_Revision < 0x20),
  281. // enable the SAL_GET_STATE_INFO log id increment workaround.
  282. //
  283. if ( HalpIsBigSur() ) {
  284. if ( HalpSalPalData.PalVersion.PAL_A_Revision < 0x20 ) {
  285. HalpSalPalData.Flags |= HALP_SALPAL_FIX_MCE_LOG_ID;
  286. HalpSalPalData.Flags |= HALP_SALPAL_FIX_MP_SAFE;
  287. }
  288. } else {
  289. //
  290. // If Intel Lion and FW build < 78b (checked as SalRevision < 0x300),
  291. // enable the SAL_GET_STATE_INFO log id increment workaround.
  292. //
  293. if ( HalpSalPalData.SalRevision.Revision < 0x300 ) {
  294. HalpSalPalData.Flags |= HALP_SALPAL_FIX_MCE_LOG_ID;
  295. HalpSalPalData.Flags |= HALP_SALPAL_FIX_MP_SAFE;
  296. }
  297. //
  298. // If the PAL revision isn't greater than 6.23, don't allow
  299. // SAL_GET_STATE_INFO_CALLS
  300. //
  301. if ( HalpIsLion() ) {
  302. if ( ( HalpSalPalData.PalVersion.PAL_B_Model <= 0x66 ) &&
  303. ( HalpSalPalData.PalVersion.PAL_B_Revision <= 0x23 ) ) {
  304. HalpSalPalData.Flags |= HALP_SALPAL_CMC_BROKEN | HALP_SALPAL_CPE_BROKEN;
  305. }
  306. }
  307. }
  308. }
  309. } // HalpInitSalPalWorkArounds()
  310. NTSTATUS
  311. HalpInitializePalTrInfo(
  312. PLOADER_PARAMETER_BLOCK LoaderBlock
  313. )
  314. /*++
  315. Routine Description:
  316. This function builds an entry for the PAL in the LoaderBlock's
  317. DtrInfo and ItrInfo arrays. This is split out into its own function
  318. so we can call it early and build the TR_INFO structure before
  319. phase 0 Mm initialization where it is used to build page tables
  320. for the PAL data.
  321. Arguments:
  322. LoaderBlock - Supplies a pointer to the loader parameter block which
  323. contains the DtrInfo and ItrInfo arrays.
  324. Return Value:
  325. STATUS_SUCCESS is returned in all cases, no sanity checks are done
  326. at this point.
  327. --*/
  328. {
  329. PTR_INFO TrInfo;
  330. ULONG PalPageShift;
  331. ULONGLONG PalTrSize;
  332. ULONGLONG PalEnd;
  333. //
  334. // Zero out our data structures.
  335. //
  336. RtlZeroMemory(&HalpSalPalData, sizeof(HalpSalPalData));
  337. RtlZeroMemory(&PalCode, sizeof(SST_MEMORY_LIST));
  338. //
  339. // Describe the position of the PAL code for the rest of the
  340. // HAL.
  341. //
  342. PalCode.PhysicalAddress =
  343. (ULONGLONG) LoaderBlock->u.Ia64.Pal.PhysicalAddressMemoryDescriptor;
  344. PalCode.Length =
  345. LoaderBlock->u.Ia64.Pal.PageSizeMemoryDescriptor << EFI_PAGE_SHIFT;
  346. PalCode.NeedVaReg = TRUE;
  347. PalCode.VirtualAddress = (ULONGLONG) NULL;
  348. //
  349. // Compute the dimensions of the PAL TR. This will be the smallest
  350. // block that is naturally aligned on an even power of 2 bytes.
  351. //
  352. PalTrSize = SIZE_IN_BYTES_16KB;
  353. PalTrMask = MASK_16KB;
  354. PalPageShift = 14;
  355. PalEnd = PalCode.PhysicalAddress + PalCode.Length;
  356. //
  357. // We don't support PAL TRs larger than 16MB, so stop looping if
  358. // we get to that point.
  359. //
  360. while (PalTrMask >= MASK_16MB) {
  361. //
  362. // Stop looping if the entire PAL fits within the current
  363. // TR boundaries.
  364. //
  365. if (PalEnd <= ((PalCode.PhysicalAddress & PalTrMask) + PalTrSize)) {
  366. break;
  367. }
  368. //
  369. // Bump the TR dimensions one level larger.
  370. //
  371. PalTrMask <<= 2;
  372. PalTrSize <<= 2;
  373. PalPageShift += 2;
  374. }
  375. //
  376. // Store a few values for later consumption elsewhere in the HAL.
  377. //
  378. HalpSalPalData.PalTrSize = PalTrSize;
  379. HalpSalPalData.PalTrBase = PalCode.PhysicalAddress & PalTrMask;
  380. //
  381. // Fill in the ItrInfo entry for the PAL.
  382. //
  383. TrInfo = &LoaderBlock->u.Ia64.ItrInfo[ITR_PAL_INDEX];
  384. RtlZeroMemory(TrInfo, sizeof(*TrInfo));
  385. TrInfo->Index = ITR_PAL_INDEX;
  386. TrInfo->PageSize = PalPageShift;
  387. TrInfo->VirtualAddress = HAL_PAL_VIRTUAL_ADDRESS;
  388. TrInfo->PhysicalAddress = PalCode.PhysicalAddress;
  389. //
  390. // Fill in the DtrInfo entry for the PAL.
  391. //
  392. TrInfo = &LoaderBlock->u.Ia64.DtrInfo[DTR_PAL_INDEX];
  393. RtlZeroMemory(TrInfo, sizeof(*TrInfo));
  394. TrInfo->Index = DTR_PAL_INDEX;
  395. TrInfo->PageSize = PalPageShift;
  396. TrInfo->VirtualAddress = HAL_PAL_VIRTUAL_ADDRESS;
  397. TrInfo->PhysicalAddress = PalCode.PhysicalAddress;
  398. return STATUS_SUCCESS;
  399. }
  400. NTSTATUS
  401. HalpDoInitializationForPalCalls(
  402. PLOADER_PARAMETER_BLOCK LoaderBlock
  403. )
  404. /*++
  405. Routine Description:
  406. This function virtually maps the PAL code area.
  407. PAL requires a TR mapping, and is mapped using an architected TR, using the
  408. smallest page size to map the entire PAL code region.
  409. Arguments:
  410. LoaderBlock - Supplies a pointer to the Loader parameter block, containing the
  411. physical address of the PAL code.
  412. Return Value:
  413. STATUS_SUCCESS is returned if the mapping was successful, and PAL calls can
  414. be made. Otherwise, STATUS_UNSUCCESSFUL is returned if it cannot virtually map
  415. the areas or if PAL requires a page larger than 16MB.
  416. --*/
  417. {
  418. ULONGLONG PalPteUlong;
  419. HalpSalPalData.Status = STATUS_SUCCESS;
  420. //
  421. // Initialize the HAL private spinlocks
  422. //
  423. // - HalpSalSpinLock, HalpSalStateInfoSpinLock are used for MP synchronization of the
  424. // SAL calls that are not MP-safe.
  425. // - HalpMcaSpinLock is used for defining an MCA monarch and MP synchrnonization of shared
  426. // HAL MCA resources during OS_MCA calls.
  427. //
  428. KeInitializeSpinLock(&HalpSalSpinLock);
  429. KeInitializeSpinLock(&HalpSalStateInfoSpinLock);
  430. KeInitializeSpinLock(&HalpMcaSpinLock);
  431. KeInitializeSpinLock(&HalpInitSpinLock);
  432. KeInitializeSpinLock(&HalpCmcSpinLock);
  433. KeInitializeSpinLock(&HalpCpeSpinLock);
  434. //
  435. // Get the wakeup vector. This is passed in the loader block
  436. // it is retrieved in the loader by reading the sal system table.
  437. //
  438. HalpOsBootRendezVector = LoaderBlock->u.Ia64.WakeupVector;
  439. if ((HalpOsBootRendezVector < 0x100 ) && (HalpOsBootRendezVector > 0xF)) {
  440. HalDebugPrint(( HAL_INFO, "SAL_PAL: Found Valid WakeupVector: 0x%x\n",
  441. HalpOsBootRendezVector ));
  442. } else {
  443. HalDebugPrint(( HAL_INFO, "SAL_PAL: Invalid WakeupVector.Using Default: 0x%x\n",
  444. DEFAULT_OS_RENDEZ_VECTOR ));
  445. HalpOsBootRendezVector = DEFAULT_OS_RENDEZ_VECTOR;
  446. }
  447. //
  448. // If PAL requires a page size of larger than 16MB, fail.
  449. //
  450. if (PalTrMask < MASK_16MB) {
  451. HalDebugPrint(( HAL_ERROR, "SAL_PAL: More than 16MB was required to map PAL" ));
  452. HalpSalPalData.Status = STATUS_UNSUCCESSFUL;
  453. return STATUS_UNSUCCESSFUL;
  454. }
  455. HalDebugPrint(( HAL_INFO,
  456. "SAL_PAL: For the PAL code located at phys 0x%I64x - length 0x%I64x, the TrMask is 0x%I64x and TrSize is %d Kbytes\n",
  457. PalCode.PhysicalAddress,
  458. PalCode.Length,
  459. PalTrMask,
  460. HalpSalPalData.PalTrSize/1024 ));
  461. //
  462. // Map the PAL code at a architected address reserved for SAL/PAL
  463. //
  464. // PAL is known to have an alignment of 256KB.
  465. //
  466. PalCode.VirtualAddress = HAL_PAL_VIRTUAL_ADDRESS + (PalCode.PhysicalAddress & ~PalTrMask);
  467. ASSERT( PalCode.VirtualAddress == LoaderBlock->u.Ia64.Pal.VirtualAddress);
  468. //
  469. // Setup the ITR to map PAL
  470. //
  471. PalPteUlong = HalpSalPalData.PalTrBase | VALID_KERNEL_EXECUTE_PTE;
  472. KeFillFixedEntryTb((PHARDWARE_PTE)&PalPteUlong,
  473. (PVOID)HAL_PAL_VIRTUAL_ADDRESS,
  474. LoaderBlock->u.Ia64.ItrInfo[ITR_PAL_INDEX].PageSize,
  475. INST_TB_PAL_INDEX);
  476. LoaderBlock->u.Ia64.ItrInfo[ITR_PAL_INDEX].Valid = TRUE;
  477. HalpSalPalData.Status = STATUS_SUCCESS;
  478. HalpVirtPalProcPointer = PalCode.VirtualAddress +
  479. (LoaderBlock->u.Ia64.Pal.PhysicalAddress - PalCode.PhysicalAddress);
  480. return(STATUS_SUCCESS);
  481. }
  482. NTSTATUS
  483. HalpInitSalPal(
  484. PLOADER_PARAMETER_BLOCK LoaderBlock
  485. )
  486. /*++
  487. Routine Description:
  488. This function virtually maps the SAL code and SAL data areas. If SAL data
  489. or SAL code areas can be mapped in the same page as the PAL TR, it uses the
  490. same translation. Otherwise, it uses MmMapIoSpace.
  491. Arguments:
  492. LoaderBlock - Supplies a pointer to the Loader parameter block.
  493. Return Value:
  494. STATUS_SUCCESS is returned if the mappings were successful, and SAL/PAL calls can
  495. be made. Otherwise, STATUS_UNSUCCESSFUL is returned if it cannot virtually map
  496. the areas.
  497. Assumptions: The EfiSysTableVirtualPtr is initialized prior by EfiInitialization.
  498. --*/
  499. {
  500. //
  501. // Local declarations
  502. //
  503. ULONG index,i,SstLength;
  504. SAL_PAL_RETURN_VALUES RetVals;
  505. PHYSICAL_ADDRESS physicalAddr;
  506. SAL_STATUS SALstatus;
  507. BOOLEAN MmMappedSalCode, MmMappedSalData;
  508. ULONGLONG physicalSAL, physicalSALGP;
  509. ULONGLONG PhysicalConfigPtr;
  510. ULONGLONG SalOffset;
  511. //SST_MEMORY_LIST SalCode,SalData;
  512. PAL_VERSION_STRUCT minimumPalVersion;
  513. ULONGLONG palStatus;
  514. HalDebugPrint(( HAL_INFO, "SAL_PAL: Entering HalpInitSalPal\n" ));
  515. //
  516. // initialize the system for making PAL calls
  517. //
  518. HalpDoInitializationForPalCalls(LoaderBlock);
  519. //
  520. // Get the PAL version.
  521. //
  522. palStatus = HalCallPal(PAL_VERSION,
  523. 0,
  524. 0,
  525. 0,
  526. NULL,
  527. &minimumPalVersion.ReturnValue,
  528. &HalpSalPalData.PalVersion.ReturnValue,
  529. NULL);
  530. if (palStatus != SAL_STATUS_SUCCESS) {
  531. HalDebugPrint(( HAL_ERROR, "SAL_PAL: Get PAL version number failed. Status = %I64d\n", palStatus ));
  532. }
  533. //
  534. // Retrieve SmBiosVersion and save the pointer into HalpSalPalData. Note:
  535. // HalpGetSmBiosVersion will allocate a buffer for SmBiosVersion.
  536. //
  537. HalpSalPalData.SmBiosVersion = HalpGetSmBiosVersion(LoaderBlock);
  538. //
  539. // Determine and Initialize HAL private SAL/PAL WorkArounds if any.
  540. //
  541. HalpInitSalPalWorkArounds();
  542. // We completed initialization
  543. HalDebugPrint(( HAL_INFO, "SAL_PAL: Exiting HalpSalPalInitialization with SUCCESS\n" ));
  544. return HalpSalPalData.Status;
  545. } // HalpInitSalPal()
  546. PUCHAR
  547. HalpGetSmBiosVersion (
  548. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  549. )
  550. /*++
  551. Routine Description:
  552. This function retrieves the SmBiosVersion string from the BIOS structure
  553. table, allocates memory for the buffer, copies the string to the buffer,
  554. and returns a pointer to this buffer. If unsuccessful, this function
  555. returns a NULL.
  556. Arguments:
  557. LoaderBlock - Pointer to the loader parameter block.
  558. Return Value:
  559. Pointer to a buffer that contains SmBiosVersion string.
  560. --*/
  561. {
  562. PSMBIOS_EPS_HEADER SMBiosEPSHeader;
  563. PDMIBIOS_EPS_HEADER DMIBiosEPSHeader;
  564. USHORT SMBiosTableLength;
  565. USHORT SMBiosTableNumberStructures;
  566. PUCHAR SmBiosVersion;
  567. PHYSICAL_ADDRESS SMBiosTablePhysicalAddress;
  568. PUCHAR SMBiosDataVirtualAddress;
  569. UCHAR Type;
  570. UCHAR Length;
  571. UCHAR BiosVersionStringNumber;
  572. UCHAR chr;
  573. USHORT i;
  574. PUCHAR pBuffer;
  575. BOOLEAN Found;
  576. if (LoaderBlock->Extension->Size < sizeof(LOADER_PARAMETER_EXTENSION)) {
  577. HalDebugPrint((HAL_ERROR, "HalpGetSmBiosVersion: Invalid LoaderBlock extension size\n"));
  578. return NULL;
  579. }
  580. SMBiosEPSHeader = (PSMBIOS_EPS_HEADER)LoaderBlock->Extension->SMBiosEPSHeader;
  581. //
  582. // Verify SM Bios Header signature
  583. //
  584. if ((SMBiosEPSHeader == NULL) || (strncmp((PUCHAR)SMBiosEPSHeader, "_SM_", 4) != 0)) {
  585. HalDebugPrint((HAL_ERROR, "HalpGetSmBiosVersion: Invalid SMBiosEPSHeader\n"));
  586. return NULL;
  587. }
  588. DMIBiosEPSHeader = (PDMIBIOS_EPS_HEADER)&SMBiosEPSHeader->Signature2[0];
  589. //
  590. // Verify DMI Bios Header signature
  591. //
  592. if ((DMIBiosEPSHeader == NULL) || (strncmp((PUCHAR)DMIBiosEPSHeader, "_DMI_", 5) != 0)) {
  593. HalDebugPrint((HAL_ERROR, "HalpGetSmBiosVersion: Invalid DMIBiosEPSHeader\n"));
  594. return NULL;
  595. }
  596. SMBiosTablePhysicalAddress.HighPart = 0;
  597. SMBiosTablePhysicalAddress.LowPart = DMIBiosEPSHeader->StructureTableAddress;
  598. SMBiosTableLength = DMIBiosEPSHeader->StructureTableLength;
  599. SMBiosTableNumberStructures = DMIBiosEPSHeader->NumberStructures;
  600. //
  601. // Map SMBiosTable to virtual address
  602. //
  603. SMBiosDataVirtualAddress = MmMapIoSpace(SMBiosTablePhysicalAddress,
  604. SMBiosTableLength,
  605. MmCached
  606. );
  607. if (!SMBiosDataVirtualAddress) {
  608. HalDebugPrint((HAL_ERROR, "HalpGetSmBiosVersion: Failed to map SMBiosTablePhysicalAddress\n"));
  609. return NULL;
  610. }
  611. //
  612. // The Spec doesn't say that SmBios Type 0 structure has to be the first
  613. // structure at this entry point... so we have to traverse through memory
  614. // to find the right one.
  615. //
  616. i = 0;
  617. Found = FALSE;
  618. while (i < SMBiosTableNumberStructures && !Found) {
  619. i++;
  620. Type = (UCHAR)SMBiosDataVirtualAddress[SMBIOS_STRUCT_HEADER_TYPE_FIELD];
  621. if (Type == 0) {
  622. Found = TRUE;
  623. }
  624. else {
  625. //
  626. // Advance to the next structure
  627. //
  628. SMBiosDataVirtualAddress += SMBiosDataVirtualAddress[SMBIOS_STRUCT_HEADER_LENGTH_FIELD];
  629. // Get pass trailing string-list by looking for a double-null
  630. while (*(USHORT UNALIGNED *)SMBiosDataVirtualAddress != 0) {
  631. SMBiosDataVirtualAddress++;
  632. }
  633. SMBiosDataVirtualAddress += 2;
  634. }
  635. }
  636. if (!Found) {
  637. HalDebugPrint((HAL_ERROR, "HalpGetSmBiosVersion: Could not find Type 0 structure\n"));
  638. return NULL;
  639. }
  640. //
  641. // Extract BIOS Version string from the SmBios Type 0 Structure
  642. //
  643. Length = SMBiosDataVirtualAddress[SMBIOS_STRUCT_HEADER_LENGTH_FIELD];
  644. BiosVersionStringNumber = SMBiosDataVirtualAddress[SMBIOS_TYPE0_STRUCT_BIOSVER_FIELD];
  645. //
  646. // Text strings begin right after the formatted portion of the structure.
  647. //
  648. pBuffer = (PUCHAR)&SMBiosDataVirtualAddress[Length];
  649. //
  650. // Get to the beginning of SmBiosVersion string
  651. //
  652. for (i = 0; i < BiosVersionStringNumber - 1; i++) {
  653. do {
  654. chr = *pBuffer;
  655. pBuffer++;
  656. } while (chr != '\0');
  657. }
  658. //
  659. // Allocate memory for SmBiosVersion string and copy content of
  660. // pBuffer to SmBiosVersion.
  661. //
  662. SmBiosVersion = ExAllocatePool(NonPagedPool, strlen(pBuffer)+1);
  663. if (!SmBiosVersion) {
  664. HalDebugPrint((HAL_ERROR, "HalpGetSmBiosVersion: Failed to allocate memory for SmBiosVersion\n"));
  665. return NULL;
  666. }
  667. strcpy(SmBiosVersion, pBuffer);
  668. MmUnmapIoSpace(SMBiosDataVirtualAddress,
  669. SMBiosTableLength
  670. );
  671. return SmBiosVersion;
  672. }
  673. BOOLEAN
  674. HalpInitSalPalNonBsp(
  675. VOID
  676. )
  677. /*++
  678. Routine Description:
  679. This function is called for the non-BSP processors to simply set up the same
  680. TR registers that HalpInitSalPal does for the BSP processor.
  681. Arguments:
  682. None
  683. Return Value:
  684. None
  685. --*/
  686. {
  687. ULONG PalPageShift;
  688. ULONGLONG PalPteUlong;
  689. ULONGLONG PalTrSize;
  690. // If we successfully initialized in HalpSalPalInitialization, then set-up the TR
  691. if (!NT_SUCCESS(HalpSalPalData.Status)) {
  692. return FALSE;
  693. }
  694. PalTrSize = HalpSalPalData.PalTrSize;
  695. PalPageShift = 14;
  696. while (PalTrSize > ((ULONGLONG)1 << PalPageShift)) {
  697. PalPageShift += 2;
  698. }
  699. PalPteUlong = HalpSalPalData.PalTrBase | VALID_KERNEL_EXECUTE_PTE;
  700. KeFillFixedEntryTb((PHARDWARE_PTE)&PalPteUlong,
  701. (PVOID)HAL_PAL_VIRTUAL_ADDRESS,
  702. PalPageShift,
  703. INST_TB_PAL_INDEX);
  704. //
  705. // Allocate the stacks needed to allow physical mode firmware calls
  706. // on this processor.
  707. //
  708. return HalpAllocateProcessorPhysicalCallStacks();
  709. } // HalpInitSalPalNonBsp()
  710. VOID
  711. PrintEfiMemoryDescriptor(
  712. IN EFI_MEMORY_DESCRIPTOR * descriptor
  713. )
  714. {
  715. char * typeStr = "<unknown>";
  716. switch (descriptor->Type) {
  717. case EfiReservedMemoryType: typeStr = "EfiReservedMemoryType"; break;
  718. case EfiLoaderCode: typeStr = "EfiLoaderCode"; break;
  719. case EfiLoaderData: typeStr = "EfiLoaderData"; break;
  720. case EfiBootServicesCode: typeStr = "EfiBootServicesCode"; break;
  721. case EfiBootServicesData: typeStr = "EfiBootServicesData"; break;
  722. case EfiRuntimeServicesCode: typeStr = "EfiRuntimeServicesCode"; break;
  723. case EfiRuntimeServicesData: typeStr = "EfiRuntimeServicesData"; break;
  724. case EfiConventionalMemory: typeStr = "EfiConventionalMemory"; break;
  725. case EfiUnusableMemory: typeStr = "EfiUnusableMemory"; break;
  726. case EfiACPIReclaimMemory: typeStr = "EfiACPIReclaimMemory"; break;
  727. case EfiACPIMemoryNVS: typeStr = "EfiACPIMemoryNVS"; break;
  728. case EfiMemoryMappedIO: typeStr = "EfiMemoryMappedIO"; break;
  729. case EfiMemoryMappedIOPortSpace: typeStr = "EfiMemoryMappedIOPortSpace"; break;
  730. case EfiPalCode: typeStr = "EfiPalCode"; break;
  731. case EfiMaxMemoryType: typeStr = "EfiMaxMemoryType"; break;
  732. }
  733. DbgPrint(" Type=%s(0x%x)\n PhysicalStart=0x%I64x\n VirtualStart=0x%I64x\n NumberOfPages=0x%I64x\n Attribute=0x%I64x\n",
  734. typeStr,
  735. descriptor->Type,
  736. descriptor->PhysicalStart,
  737. descriptor->VirtualStart,
  738. descriptor->NumberOfPages,
  739. descriptor->Attribute);
  740. }
  741. VOID
  742. PrintEfiMemoryMap(
  743. IN EFI_MEMORY_DESCRIPTOR * memoryMapPtr,
  744. IN ULONGLONG numMapEntries
  745. )
  746. {
  747. ULONGLONG index;
  748. DbgPrint("Printing 0x%x EFI memory descriptors\n", numMapEntries);
  749. for (index = 0; index < numMapEntries; ++index) {
  750. PrintEfiMemoryDescriptor(memoryMapPtr);
  751. DbgPrint("\n");
  752. memoryMapPtr = NextMemoryDescriptor(memoryMapPtr, EfiDescriptorSize);
  753. }
  754. }
  755. BOOLEAN
  756. HalpDescriptorContainsAddress(
  757. EFI_MEMORY_DESCRIPTOR *EfiMd,
  758. ULONGLONG PhysicalAddress
  759. )
  760. {
  761. ULONGLONG MdPhysicalStart, MdPhysicalEnd;
  762. MdPhysicalStart = (ULONGLONG)EfiMd->PhysicalStart;
  763. MdPhysicalEnd = MdPhysicalStart + (ULONGLONG)(EfiMd->NumberOfPages << EFI_PAGE_SHIFT);
  764. if ((PhysicalAddress >= MdPhysicalStart) &&
  765. (PhysicalAddress < MdPhysicalEnd)) {
  766. return(TRUE);
  767. }
  768. return(FALSE);
  769. }
  770. NTSTATUS
  771. HalpEfiInitialization(
  772. PLOADER_PARAMETER_BLOCK LoaderBlock
  773. )
  774. /*++
  775. Routine Description:
  776. This function
  777. Arguments:
  778. LoaderBlock - Supplies a pointer to the Loader parameter block, containing the
  779. physical address of the EFI system table.
  780. Return Value:
  781. STATUS_SUCCESS is returned if the mappings were successful, and EFI calls can
  782. be made. Otherwise, STATUS_UNSUCCESSFUL is returned.
  783. --*/
  784. {
  785. //
  786. // Local declarations
  787. //
  788. EFI_MEMORY_DESCRIPTOR *efiMapEntryPtr, *efiVirtualMemoryMapPtr;
  789. EFI_STATUS status;
  790. ULONGLONG index, mapEntries;
  791. ULONGLONG physicalEfiST, physicalEfiMemoryMapPtr, physicalRunTimeServicesPtr;
  792. ULONGLONG physicalEfiGetVariable, physicalEfiGetNextVariableName, physicalEfiSetVariable;
  793. ULONGLONG physicalEfiGetTime, physicalEfiSetTime;
  794. ULONGLONG physicalEfiSetVirtualAddressMap, physicalEfiResetSystem;
  795. PHYSICAL_ADDRESS physicalAddr;
  796. ULONGLONG physicalPlabel_Fpswa;
  797. FPSWA_INTERFACE *interfacePtr;
  798. PVOID tmpPtr;
  799. SST_MEMORY_LIST SalCode, SalData, SalDataGPOffset;
  800. ULONGLONG SalOffset = 0, SalDataOffset = 0;
  801. MEMORY_CACHING_TYPE cacheType;
  802. RtlZeroMemory(&SalCode, sizeof(SST_MEMORY_LIST));
  803. RtlZeroMemory(&SalData, sizeof(SST_MEMORY_LIST));
  804. RtlZeroMemory(&SalDataGPOffset, sizeof(SST_MEMORY_LIST));
  805. //
  806. // get the sal code, and data filled in with data from the loader block.
  807. //
  808. SalCode.PhysicalAddress = LoaderBlock->u.Ia64.Sal.PhysicalAddress;
  809. SalData.PhysicalAddress = LoaderBlock->u.Ia64.SalGP.PhysicalAddress;
  810. SalDataGPOffset.PhysicalAddress = SalData.PhysicalAddress - (2 * 0x100000);
  811. //
  812. // First, get the physical address of the fpswa entry point PLABEL.
  813. //
  814. if (LoaderBlock->u.Ia64.FpswaInterface != (ULONG_PTR) NULL) {
  815. physicalAddr.QuadPart = LoaderBlock->u.Ia64.FpswaInterface;
  816. interfacePtr = MmMapIoSpace(physicalAddr,
  817. sizeof(FPSWA_INTERFACE),
  818. MmCached
  819. );
  820. if (interfacePtr == NULL) {
  821. HalDebugPrint(( HAL_FATAL_ERROR, "FpswaInterfacePtr is Null. Efi handle not available\n"));
  822. KeBugCheckEx(FP_EMULATION_ERROR, 0, 0, 0, 0);
  823. return STATUS_UNSUCCESSFUL;
  824. }
  825. physicalPlabel_Fpswa = (ULONGLONG)(interfacePtr->Fpswa);
  826. }
  827. else {
  828. HalDebugPrint(( HAL_FATAL_ERROR, "HAL: EFI FpswaInterface is not available\n"));
  829. KeBugCheckEx(FP_EMULATION_ERROR, 0, 0, 0, 0);
  830. return STATUS_UNSUCCESSFUL;
  831. }
  832. physicalEfiST = LoaderBlock->u.Ia64.EfiSystemTable;
  833. physicalAddr.QuadPart = physicalEfiST;
  834. EfiSysTableVirtualPtr = MmMapIoSpace( physicalAddr, sizeof(EFI_SYSTEM_TABLE), MmCached);
  835. if (EfiSysTableVirtualPtr == NULL) {
  836. HalDebugPrint(( HAL_ERROR, "HAL: EfiSystem Table Virtual Addr is NULL\n" ));
  837. EfiInitStatus = STATUS_UNSUCCESSFUL;
  838. return STATUS_UNSUCCESSFUL;
  839. }
  840. EfiSysTableVirtualPtrCpy = EfiSysTableVirtualPtr;
  841. physicalRunTimeServicesPtr = (ULONGLONG) EfiSysTableVirtualPtr->RuntimeServices;
  842. physicalAddr.QuadPart = physicalRunTimeServicesPtr;
  843. EfiRSVirtualPtr = MmMapIoSpace(physicalAddr, sizeof(EFI_RUNTIME_SERVICES),MmCached);
  844. if (EfiRSVirtualPtr == NULL) {
  845. HalDebugPrint(( HAL_ERROR, "HAL: Run Time Table Virtual Addr is NULL\n" ));
  846. EfiInitStatus = STATUS_UNSUCCESSFUL;
  847. return STATUS_UNSUCCESSFUL;
  848. }
  849. EfiMemoryMapSize = LoaderBlock->u.Ia64.EfiMemMapParam.MemoryMapSize;
  850. EfiDescriptorSize = LoaderBlock->u.Ia64.EfiMemMapParam.DescriptorSize;
  851. EfiDescriptorVersion = LoaderBlock->u.Ia64.EfiMemMapParam.DescriptorVersion;
  852. physicalEfiMemoryMapPtr = (ULONGLONG)LoaderBlock->u.Ia64.EfiMemMapParam.MemoryMap;
  853. physicalAddr.QuadPart = physicalEfiMemoryMapPtr;
  854. efiVirtualMemoryMapPtr = MmMapIoSpace (physicalAddr, EfiMemoryMapSize, MmCached);
  855. if (efiVirtualMemoryMapPtr == NULL) {
  856. HalDebugPrint(( HAL_ERROR, "HAL: Virtual Set Memory Map Virtual Addr is NULL\n" ));
  857. EfiInitStatus = STATUS_UNSUCCESSFUL;
  858. return STATUS_UNSUCCESSFUL;
  859. }
  860. //
  861. // #define VENDOR_SPECIFIC_GUID \
  862. // { 0xa3c72e56, 0x4c35, 0x11d3, 0x8a, 0x03, 0x0, 0xa0, 0xc9, 0x06, 0xad, 0xec }
  863. //
  864. VendorGuid.Data1 = 0x8be4df61;
  865. VendorGuid.Data2 = 0x93ca;
  866. VendorGuid.Data3 = 0x11d2;
  867. VendorGuid.Data4[0] = 0xaa;
  868. VendorGuid.Data4[1] = 0x0d;
  869. VendorGuid.Data4[2] = 0x00;
  870. VendorGuid.Data4[3] = 0xe0;
  871. VendorGuid.Data4[4] = 0x98;
  872. VendorGuid.Data4[5] = 0x03;
  873. VendorGuid.Data4[6] = 0x2b;
  874. VendorGuid.Data4[7] = 0x8c;
  875. HalDebugPrint(( HAL_INFO,
  876. "HAL: EFI SystemTable VA = 0x%I64x, PA = 0x%I64x\n"
  877. "HAL: EFI RunTimeServices VA = 0x%I64x, PA = 0x%I64x\n"
  878. "HAL: EFI MemoryMapPtr VA = 0x%I64x, PA = 0x%I64x\n"
  879. "HAL: EFI MemoryMap Size = 0x%I64x\n"
  880. "HAL: EFI Descriptor Size = 0x%I64x\n",
  881. EfiSysTableVirtualPtr,
  882. physicalEfiST,
  883. EfiRSVirtualPtr,
  884. physicalRunTimeServicesPtr,
  885. efiVirtualMemoryMapPtr,
  886. physicalEfiMemoryMapPtr,
  887. EfiMemoryMapSize,
  888. EfiDescriptorSize
  889. ));
  890. // GetVariable
  891. physicalEfiGetVariable = (ULONGLONG) (EfiRSVirtualPtr -> GetVariable);
  892. physicalAddr.QuadPart = physicalEfiGetVariable;
  893. EfiVirtualGetVariablePtr = MmMapIoSpace (physicalAddr, sizeof(PLABEL_DESCRIPTOR), MmCached);
  894. if (EfiVirtualGetVariablePtr == NULL) {
  895. HalDebugPrint(( HAL_ERROR, "HAL: EfiGetVariable Virtual Addr is NULL\n" ));
  896. EfiInitStatus = STATUS_UNSUCCESSFUL;
  897. return STATUS_UNSUCCESSFUL;
  898. }
  899. HalDebugPrint(( HAL_INFO, "HAL: EFI GetVariable VA = 0x%I64x, PA = 0x%I64x\n",
  900. EfiVirtualGetVariablePtr, physicalEfiGetVariable ));
  901. // GetNextVariableName
  902. physicalEfiGetNextVariableName = (ULONGLONG) (EfiRSVirtualPtr -> GetNextVariableName);
  903. physicalAddr.QuadPart = physicalEfiGetNextVariableName;
  904. EfiVirtualGetNextVariableNamePtr = MmMapIoSpace (physicalAddr,sizeof(PLABEL_DESCRIPTOR),MmCached);
  905. if (EfiVirtualGetNextVariableNamePtr == NULL) {
  906. HalDebugPrint(( HAL_ERROR, "HAL: EfiVirtual Get Next Variable Name Ptr Addr is NULL\n" ));
  907. EfiInitStatus = STATUS_UNSUCCESSFUL;
  908. return STATUS_UNSUCCESSFUL;
  909. }
  910. //SetVariable
  911. physicalEfiSetVariable = (ULONGLONG) (EfiRSVirtualPtr -> SetVariable);
  912. physicalAddr.QuadPart = physicalEfiSetVariable;
  913. EfiVirtualSetVariablePtr = MmMapIoSpace (physicalAddr, sizeof(PLABEL_DESCRIPTOR), MmCached);
  914. if (EfiVirtualSetVariablePtr == NULL) {
  915. HalDebugPrint(( HAL_ERROR, "HAL: EfiVariableSetVariable Pointer dr is NULL\n" ));
  916. EfiInitStatus = STATUS_UNSUCCESSFUL;
  917. return STATUS_UNSUCCESSFUL;
  918. }
  919. HalDebugPrint(( HAL_INFO, "HAL: EFI Set Variable VA = 0x%I64x, PA = 0x%I64x\n",
  920. EfiVirtualSetVariablePtr, physicalEfiSetVariable ));
  921. //GetTime
  922. physicalEfiGetTime = (ULONGLONG) (EfiRSVirtualPtr -> GetTime);
  923. physicalAddr.QuadPart = physicalEfiGetTime;
  924. EfiVirtualGetTimePtr = MmMapIoSpace (physicalAddr, sizeof(PLABEL_DESCRIPTOR), MmCached);
  925. if (EfiVirtualGetTimePtr == NULL) {
  926. HalDebugPrint(( HAL_ERROR, "HAL: EfiGetTime Virtual Addr is NULL\n" ));
  927. EfiInitStatus = STATUS_UNSUCCESSFUL;
  928. return STATUS_UNSUCCESSFUL;
  929. }
  930. HalDebugPrint(( HAL_INFO, "HAL: EFI GetTime VA = 0x%I64x, PA = 0x%I64x\n",
  931. EfiVirtualGetTimePtr, physicalEfiGetTime ));
  932. //SetTime
  933. physicalEfiSetTime = (ULONGLONG) (EfiRSVirtualPtr -> SetTime);
  934. physicalAddr.QuadPart = physicalEfiSetTime;
  935. EfiVirtualSetTimePtr = MmMapIoSpace (physicalAddr, sizeof(PLABEL_DESCRIPTOR), MmCached);
  936. if (EfiVirtualSetTimePtr == NULL) {
  937. HalDebugPrint(( HAL_ERROR, "HAL: EfiSetTime Virtual Addr is NULL\n" ));
  938. EfiInitStatus = STATUS_UNSUCCESSFUL;
  939. return STATUS_UNSUCCESSFUL;
  940. }
  941. HalDebugPrint(( HAL_INFO, "HAL: EFI SetTime VA = 0x%I64x, PA = 0x%I64x\n",
  942. EfiVirtualSetTimePtr, physicalEfiSetTime ));
  943. //SetVirtualAddressMap
  944. physicalEfiSetVirtualAddressMap = (ULONGLONG) (EfiRSVirtualPtr -> SetVirtualAddressMap);
  945. physicalAddr.QuadPart = physicalEfiSetVirtualAddressMap;
  946. EfiSetVirtualAddressMapPtr = MmMapIoSpace (physicalAddr, sizeof(PLABEL_DESCRIPTOR), MmCached);
  947. if (EfiSetVirtualAddressMapPtr == NULL) {
  948. HalDebugPrint(( HAL_ERROR, "HAL: Efi Set VirtualMapPointer Virtual Addr is NULL\n" ));
  949. EfiInitStatus = STATUS_UNSUCCESSFUL;
  950. return STATUS_UNSUCCESSFUL;
  951. }
  952. HalDebugPrint(( HAL_INFO, "HAL: EFI SetVirtualAddressMap VA = 0x%I64x, PA = 0x%I64x\n",
  953. EfiSetVirtualAddressMapPtr, physicalEfiSetVirtualAddressMap ));
  954. //ResetSystem
  955. physicalEfiResetSystem = (ULONGLONG) (EfiRSVirtualPtr -> ResetSystem);
  956. physicalAddr.QuadPart = physicalEfiResetSystem;
  957. EfiResetSystemPtr = MmMapIoSpace (physicalAddr, sizeof(PLABEL_DESCRIPTOR), MmCached);
  958. if (EfiResetSystemPtr == NULL) {
  959. HalDebugPrint(( HAL_ERROR,"HAL: Efi Reset System Virtual Addr is NULL\n" ));
  960. EfiInitStatus = STATUS_UNSUCCESSFUL;
  961. return STATUS_UNSUCCESSFUL;
  962. }
  963. HalDebugPrint(( HAL_INFO, "HAL: EFI ResetSystem VA = 0x%I64x, PA = 0x%I64x\n",
  964. EfiResetSystemPtr, physicalEfiResetSystem ));
  965. //
  966. // The round to pages should not be needed below, but this change was made late so I made it
  967. // page aligned size since the old one was just page size.
  968. //
  969. HalpVirtualCommonDataPointer = (PUCHAR)(ExAllocatePool (NonPagedPool, ROUND_TO_PAGES( EfiMemoryMapSize + MemoryMapOffset)));
  970. if (HalpVirtualCommonDataPointer == NULL) {
  971. HalDebugPrint(( HAL_ERROR, "HAL: Common data allocation failed\n" ));
  972. EfiInitStatus = STATUS_UNSUCCESSFUL;
  973. return STATUS_UNSUCCESSFUL;
  974. }
  975. HalpVariableNameVirtualPtr = HalpVirtualCommonDataPointer + VariableNameOffset;
  976. HalpVendorGuidVirtualPtr = HalpVirtualCommonDataPointer + VendorGuidOffset;
  977. HalpVariableAttributesVirtualPtr = HalpVirtualCommonDataPointer + AttributeOffset;
  978. HalpDataSizeVirtualPtr = HalpVirtualCommonDataPointer + DataSizeOffset;
  979. HalpDataVirtualPtr = HalpVirtualCommonDataPointer + DataBufferOffset;
  980. HalpCommonDataEndPtr = HalpVirtualCommonDataPointer + EndOfCommonDataOffset;
  981. HalpMemoryMapSizeVirtualPtr = HalpVirtualCommonDataPointer + MemoryMapSizeOffset;
  982. HalpMemoryMapVirtualPtr = (PUCHAR)(HalpVirtualCommonDataPointer + MemoryMapOffset);
  983. HalpDescriptorSizeVirtualPtr = HalpVirtualCommonDataPointer + DescriptorSizeOffset;
  984. HalpDescriptorVersionVirtualPtr = HalpVirtualCommonDataPointer + DescriptorVersionOffset;
  985. HalpPhysCommonDataPointer = (PUCHAR)((MmGetPhysicalAddress(HalpVirtualCommonDataPointer)).QuadPart);
  986. HalpVariableNamePhysPtr = HalpPhysCommonDataPointer + VariableNameOffset;
  987. HalpVendorGuidPhysPtr = HalpPhysCommonDataPointer + VendorGuidOffset;
  988. HalpVariableAttributesPhysPtr = HalpPhysCommonDataPointer + AttributeOffset;
  989. HalpDataSizePhysPtr = HalpPhysCommonDataPointer + DataSizeOffset;
  990. HalpDataPhysPtr = HalpPhysCommonDataPointer + DataBufferOffset;
  991. HalpMemoryMapSizePhysPtr = HalpPhysCommonDataPointer + MemoryMapSizeOffset;
  992. HalpMemoryMapPhysPtr = HalpPhysCommonDataPointer + MemoryMapOffset;
  993. HalpDescriptorSizePhysPtr = HalpPhysCommonDataPointer + DescriptorSizeOffset;
  994. HalpDescriptorVersionPhysPtr = HalpPhysCommonDataPointer + DescriptorVersionOffset;
  995. AttributePtr = &EfiAttribute;
  996. DataSizePtr = &EfiDataSize;
  997. RtlCopyMemory ((PULONGLONG)HalpMemoryMapVirtualPtr,
  998. efiVirtualMemoryMapPtr,
  999. (ULONG)(EfiMemoryMapSize)
  1000. );
  1001. //
  1002. // Now, extract SAL, PAL information from the loader parameter block and
  1003. // initializes HAL SAL, PAL definitions.
  1004. //
  1005. // N.B 10/2000:
  1006. // We do not check the return status of HalpInitSalPal(). We should. FIXFIX.
  1007. // In case of failure, we currently flag HalpSalPalData.Status as unsuccessful.
  1008. //
  1009. HalpInitSalPal(LoaderBlock);
  1010. //
  1011. // Initialize Spin Lock
  1012. //
  1013. KeInitializeSpinLock(&EFIMPLock);
  1014. ASSERT (EfiDescriptorVersion == EFI_MEMORY_DESCRIPTOR_VERSION);
  1015. // if (EfiDescriptorVersion != EFI_MEMORY_DESCRIPTION_VERSION) {
  1016. // HalDebugPrint(HAL_ERROR,("Efi Memory Map Pointer VAddr is NULL\n"));
  1017. // EfiInitStatus = STATUS_UNSUCCESSFUL;
  1018. // return STATUS_UNSUCCESSFUL;
  1019. // }
  1020. HalDebugPrint(( HAL_INFO, "HAL: Creating EFI virtual address mapping\n" ));
  1021. efiMapEntryPtr = efiVirtualMemoryMapPtr;
  1022. if (efiMapEntryPtr == NULL) {
  1023. HalDebugPrint(( HAL_ERROR, "HAL: Efi Memory Map Pointer VAddr is NULL\n" ));
  1024. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1025. return STATUS_UNSUCCESSFUL;
  1026. }
  1027. mapEntries = EfiMemoryMapSize/EfiDescriptorSize;
  1028. HalDebugPrint(( HAL_INFO,
  1029. "HAL: Sal: 0x%I64x (offset 0x%I64x) SalGP: 0x%I64x (offset 0x%I64x) SalDataGPOffset: 0x%I64x\n",
  1030. SalCode.PhysicalAddress,
  1031. SalOffset,
  1032. SalData.PhysicalAddress,
  1033. SalDataOffset,
  1034. SalDataGPOffset.PhysicalAddress
  1035. ));
  1036. HalDebugPrint(( HAL_INFO, "HAL: EfiMemoryMapSize: 0x%I64x & EfiDescriptorSize: 0x%I64x & #of entries: 0x%I64x\n",
  1037. EfiMemoryMapSize,
  1038. EfiDescriptorSize,
  1039. mapEntries ));
  1040. HalDebugPrint(( HAL_INFO, "HAL: Efi RunTime Attribute will be printed as 1\n" ));
  1041. for (index = 0; index < mapEntries; index= index + 1) {
  1042. BOOLEAN attribute = 0;
  1043. ULONGLONG physicalStart = efiMapEntryPtr->PhysicalStart;
  1044. ULONGLONG physicalEnd = physicalStart + (efiMapEntryPtr->NumberOfPages << EFI_PAGE_SHIFT);
  1045. physicalAddr.QuadPart = efiMapEntryPtr -> PhysicalStart;
  1046. //
  1047. // To handle video bios mapping issues, HALIA64 maps every EFI MD
  1048. // regardless of the EFI_MEMORY_RUNTIME flag.
  1049. //
  1050. // Implementation Note: ia64ldr ignored 1rst MB range and did not pass
  1051. // this memory to MM. MM considers this range as
  1052. // IO space.
  1053. //
  1054. if ( (efiMapEntryPtr->NumberOfPages > 0) && (physicalStart < OptionROMAddress) ) {
  1055. ULONGLONG numberOfPages = efiMapEntryPtr->NumberOfPages;
  1056. cacheType = (efiMapEntryPtr->Attribute & EFI_MEMORY_UC) ? MmNonCached : MmCached;
  1057. efiMapEntryPtr->VirtualStart = (ULONGLONG) (MmMapIoSpace (physicalAddr,
  1058. (EFI_PAGE_SIZE) * numberOfPages,
  1059. cacheType
  1060. ));
  1061. if ((efiMapEntryPtr->VirtualStart) == 0) {
  1062. HalDebugPrint(( HAL_ERROR,
  1063. "HAL: Efi Video Bios area PA 0x%I64x, VAddr is NULL\n", physicalStart
  1064. ));
  1065. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1066. return STATUS_UNSUCCESSFUL;
  1067. }
  1068. HalDebugPrint(( HAL_INFO,
  1069. "HAL: Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x & mapped to VA 0x%I64x\n",
  1070. attribute,
  1071. efiMapEntryPtr->Type,
  1072. efiMapEntryPtr->NumberOfPages,
  1073. efiMapEntryPtr->PhysicalStart,
  1074. efiMapEntryPtr->VirtualStart));
  1075. //
  1076. // Initialize known HAL video bios pointers. These pointer must be zero based
  1077. //
  1078. if (physicalStart == 0x00000) {
  1079. HalpLowMemoryBase = (PVOID) efiMapEntryPtr->VirtualStart;
  1080. }
  1081. if ( physicalStart <= 0xA0000 && physicalEnd > 0xA0000) {
  1082. HalpFrameBufferBase = (PVOID)(efiMapEntryPtr->VirtualStart - physicalStart);
  1083. }
  1084. if ( physicalStart <= 0xC0000 && physicalEnd > 0xC0000 ) {
  1085. HalpIoMemoryBase = (PVOID)(efiMapEntryPtr->VirtualStart - physicalStart);
  1086. }
  1087. }
  1088. else if ((efiMapEntryPtr->Attribute) & EFI_MEMORY_RUNTIME)
  1089. {
  1090. attribute = 1;
  1091. switch (efiMapEntryPtr->Type) {
  1092. case EfiRuntimeServicesData:
  1093. case EfiReservedMemoryType:
  1094. case EfiACPIMemoryNVS:
  1095. if(efiMapEntryPtr->Type == EfiACPIMemoryNVS) {
  1096. //
  1097. // note: we allow ACPI NVS to be mapped per the
  1098. // firmware's specification instead of forcing it to
  1099. // be non-cached. We are relying on the first mapping
  1100. // of this range to have the "correct" caching flag, as
  1101. // that is the cachability attribute that all
  1102. // subsequent mappings of this range (ie., mapping of
  1103. // additional data in the same page from ACPI driver
  1104. // for a memory operation region, etc.). This semantic
  1105. // is enforced by the memory manager.
  1106. //
  1107. efiMapEntryPtr->VirtualStart = (ULONGLONG) (MmMapIoSpace (physicalAddr,
  1108. (SIZE_T)((EFI_PAGE_SIZE)*(efiMapEntryPtr->NumberOfPages)),
  1109. (efiMapEntryPtr->Attribute & EFI_MEMORY_UC) ? MmNonCached : MmCached
  1110. ));
  1111. } else {
  1112. efiMapEntryPtr->VirtualStart = (ULONGLONG) (MmMapIoSpace (physicalAddr,
  1113. (SIZE_T)((EFI_PAGE_SIZE)*(efiMapEntryPtr->NumberOfPages)),
  1114. (efiMapEntryPtr->Attribute & EFI_MEMORY_WB) ? MmCached : MmNonCached
  1115. ));
  1116. }
  1117. if ((efiMapEntryPtr->VirtualStart) == 0) {
  1118. HalDebugPrint(( HAL_ERROR, "HAL: Efi RunTimeSrvceData/RsrvdMemory/ACPIMemoryNVS area VAddr is NULL\n" ));
  1119. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1120. return STATUS_UNSUCCESSFUL;
  1121. }
  1122. HalDebugPrint(( HAL_INFO,
  1123. "HAL: Efi attribute %d & Type 0x%I64x with # of 4k pages 0x%I64x at PA 0x%I64x & mapped to VA 0x%I64x\n",
  1124. attribute,
  1125. efiMapEntryPtr->Type,
  1126. efiMapEntryPtr->NumberOfPages,
  1127. efiMapEntryPtr->PhysicalStart,
  1128. efiMapEntryPtr->VirtualStart ));
  1129. if (efiMapEntryPtr->Type == EfiRuntimeServicesData) {
  1130. if (HalpDescriptorContainsAddress(efiMapEntryPtr,SalData.PhysicalAddress)) {
  1131. //
  1132. // save off salgp virtual address
  1133. //
  1134. SalData.VirtualAddress = efiMapEntryPtr->VirtualStart;
  1135. SalDataOffset = SalData.PhysicalAddress - efiMapEntryPtr->PhysicalStart;
  1136. HalDebugPrint(( HAL_INFO,
  1137. "HAL: prior descriptor contains SalData.PhysicalAddress 0x%I64x\n",
  1138. SalData.PhysicalAddress ));
  1139. }
  1140. if (HalpDescriptorContainsAddress(efiMapEntryPtr,SalDataGPOffset.PhysicalAddress)) {
  1141. //
  1142. // save off salgp virtual address
  1143. //
  1144. SalDataGPOffset.VirtualAddress = efiMapEntryPtr->VirtualStart;
  1145. //
  1146. // Don't overwrite an existing SalDataOffset
  1147. // (generated using SalData.PhysicalAddress) since
  1148. // SalDataGPOffset is only needed when
  1149. // SalData.PhysicalAddress lies outside of the EFI
  1150. // memory map.
  1151. //
  1152. if (SalDataOffset == 0) {
  1153. SalDataOffset = SalDataGPOffset.PhysicalAddress - efiMapEntryPtr->PhysicalStart;
  1154. }
  1155. HalDebugPrint(( HAL_INFO,
  1156. "HAL: prior descriptor contains SalDataGPOffset.PhysicalAddress 0x%I64x\n",
  1157. SalData.PhysicalAddress ));
  1158. }
  1159. }
  1160. break;
  1161. case EfiPalCode:
  1162. efiMapEntryPtr->VirtualStart = PalCode.VirtualAddress;
  1163. HalDebugPrint(( HAL_INFO,
  1164. "HAL: Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x & mapped to VA 0x%I64x\n",
  1165. attribute,
  1166. efiMapEntryPtr->Type,
  1167. efiMapEntryPtr->NumberOfPages,
  1168. efiMapEntryPtr->PhysicalStart,
  1169. efiMapEntryPtr->VirtualStart ));
  1170. break;
  1171. case EfiRuntimeServicesCode:
  1172. //
  1173. // Skip over Option rom addresses. They are not really needed by the EFI runtime
  1174. // and most users want it mapped non-cached.
  1175. //
  1176. cacheType = (efiMapEntryPtr->Attribute & EFI_MEMORY_WB) ? MmCached : MmNonCached;
  1177. efiMapEntryPtr->VirtualStart = (ULONGLONG) (MmMapIoSpace (physicalAddr,
  1178. (EFI_PAGE_SIZE) * (efiMapEntryPtr->NumberOfPages),
  1179. cacheType
  1180. ));
  1181. if ((efiMapEntryPtr->VirtualStart) == 0) {
  1182. HalDebugPrint(( HAL_ERROR, "HAL: Efi RunTimeSrvceCode area VAddr is NULL\n" ));
  1183. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1184. return STATUS_UNSUCCESSFUL;
  1185. }
  1186. HalDebugPrint(( HAL_INFO,
  1187. "HAL: Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x & mapped to VA 0x%I64x\n",
  1188. attribute,
  1189. efiMapEntryPtr->Type,
  1190. efiMapEntryPtr->NumberOfPages,
  1191. efiMapEntryPtr->PhysicalStart,
  1192. efiMapEntryPtr->VirtualStart));
  1193. if (HalpDescriptorContainsAddress(efiMapEntryPtr,SalData.PhysicalAddress)) {
  1194. //
  1195. // save off salgp virtual address
  1196. //
  1197. SalData.VirtualAddress = efiMapEntryPtr->VirtualStart;
  1198. SalDataOffset = SalData.PhysicalAddress - efiMapEntryPtr->PhysicalStart;
  1199. }
  1200. if (HalpDescriptorContainsAddress(efiMapEntryPtr,SalDataGPOffset.PhysicalAddress)) {
  1201. //
  1202. // save off salgp virtual address
  1203. //
  1204. SalDataGPOffset.VirtualAddress = efiMapEntryPtr->VirtualStart;
  1205. //
  1206. // Don't overwrite an existing SalDataOffset
  1207. // (generated using SalData.PhysicalAddress) since
  1208. // SalDataGPOffset is only needed when
  1209. // SalData.PhysicalAddress lies outside of the EFI
  1210. // memory map.
  1211. //
  1212. if (SalDataOffset == 0) {
  1213. SalDataOffset = SalDataGPOffset.PhysicalAddress - efiMapEntryPtr->PhysicalStart;
  1214. }
  1215. HalDebugPrint(( HAL_INFO,
  1216. "HAL: prior descriptor contains SalDataGPOffset.PhysicalAddress 0x%I64x\n",
  1217. SalData.PhysicalAddress ));
  1218. }
  1219. if (HalpDescriptorContainsAddress(efiMapEntryPtr,SalCode.PhysicalAddress)) {
  1220. //
  1221. // save off sal code virtual address
  1222. //
  1223. SalCode.VirtualAddress = efiMapEntryPtr->VirtualStart;
  1224. SalOffset = SalCode.PhysicalAddress - efiMapEntryPtr->PhysicalStart;
  1225. }
  1226. break;
  1227. case EfiMemoryMappedIO:
  1228. efiMapEntryPtr->VirtualStart = (ULONGLONG) (MmMapIoSpace (physicalAddr,
  1229. (EFI_PAGE_SIZE) * (efiMapEntryPtr->NumberOfPages),
  1230. MmNonCached
  1231. ));
  1232. if ((efiMapEntryPtr->VirtualStart) == 0) {
  1233. HalDebugPrint(( HAL_ERROR, "HAL: Efi MemoryMappedIO VAddr is NULL\n" ));
  1234. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1235. return STATUS_UNSUCCESSFUL;
  1236. }
  1237. HalDebugPrint(( HAL_INFO,
  1238. "HAL: Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x & mapped to VA 0x%I64x\n",
  1239. attribute,
  1240. efiMapEntryPtr->Type,
  1241. efiMapEntryPtr->NumberOfPages,
  1242. efiMapEntryPtr->PhysicalStart,
  1243. efiMapEntryPtr->VirtualStart ));
  1244. break;
  1245. case EfiMemoryMappedIOPortSpace:
  1246. efiMapEntryPtr->VirtualStart = VIRTUAL_IO_BASE;
  1247. HalDebugPrint(( HAL_INFO,
  1248. "HAL: Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x ALREADY mapped to VA 0x%I64x\n",
  1249. attribute,
  1250. efiMapEntryPtr->Type,
  1251. efiMapEntryPtr->NumberOfPages,
  1252. efiMapEntryPtr->PhysicalStart,
  1253. efiMapEntryPtr->VirtualStart ));
  1254. break;
  1255. case EfiACPIReclaimMemory:
  1256. //
  1257. // note: we allow ACPI reclaim memory to be mapped per the
  1258. // firmware's specification instead of forcing it to
  1259. // be non-cached. We are relying on the first mapping
  1260. // of this range to have the "correct" caching flag, as
  1261. // that is the cachability attribute that all
  1262. // subsequent mappings of this range (ie., mapping of
  1263. // additional data in the same page from ACPI driver
  1264. // for a memory operation region, etc.). This semantic
  1265. // is enforced by the memory manager.
  1266. //
  1267. efiMapEntryPtr->VirtualStart = (ULONGLONG) (MmMapIoSpace(
  1268. physicalAddr,
  1269. (SIZE_T)((EFI_PAGE_SIZE)*(efiMapEntryPtr->NumberOfPages)),
  1270. (efiMapEntryPtr->Attribute & EFI_MEMORY_UC) ? MmNonCached : MmCached));
  1271. if ((efiMapEntryPtr->VirtualStart) == 0) {
  1272. HalDebugPrint(( HAL_ERROR, "HAL: Efi ACPI Reclaim VAddr is NULL\n" ));
  1273. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1274. return STATUS_UNSUCCESSFUL;
  1275. }
  1276. HalDebugPrint(( HAL_INFO,
  1277. "HAL: Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x & mapped to VA 0x%I64x\n",
  1278. attribute,
  1279. efiMapEntryPtr->Type,
  1280. efiMapEntryPtr->NumberOfPages,
  1281. efiMapEntryPtr->PhysicalStart,
  1282. efiMapEntryPtr->VirtualStart ));
  1283. break;
  1284. default:
  1285. HalDebugPrint(( HAL_INFO, "HAL: Efi CONTROL SHOULD NOT COME HERE\n" ));
  1286. HalDebugPrint(( HAL_INFO,
  1287. "HAL: NON-SUPPORTED Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x\n",
  1288. attribute,
  1289. efiMapEntryPtr->Type,
  1290. efiMapEntryPtr->NumberOfPages,
  1291. efiMapEntryPtr->PhysicalStart ));
  1292. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1293. return STATUS_UNSUCCESSFUL;
  1294. break;
  1295. }
  1296. } else {
  1297. HalDebugPrint(( HAL_INFO,
  1298. "HAL: Efi attribute %d & Type 0x%I64x with # of 4K pages 0x%I64x at PA 0x%I64x ALREADY mapped to VA 0x%I64x\n",
  1299. attribute,
  1300. efiMapEntryPtr->Type,
  1301. efiMapEntryPtr->NumberOfPages,
  1302. efiMapEntryPtr->PhysicalStart,
  1303. efiMapEntryPtr->VirtualStart ));
  1304. }
  1305. efiMapEntryPtr = NextMemoryDescriptor(efiMapEntryPtr,EfiDescriptorSize);
  1306. }
  1307. status = HalpCallEfi(EFI_SET_VIRTUAL_ADDRESS_MAP_INDEX,
  1308. (ULONGLONG)EfiMemoryMapSize,
  1309. (ULONGLONG)EfiDescriptorSize,
  1310. (ULONGLONG)EfiDescriptorVersion,
  1311. (ULONGLONG)efiVirtualMemoryMapPtr,
  1312. 0,
  1313. 0,
  1314. 0,
  1315. 0
  1316. );
  1317. HalDebugPrint(( HAL_INFO, "HAL: Returned from SetVirtualAddressMap: 0x%Ix\n", status ));
  1318. if (EFI_ERROR( status )) {
  1319. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1320. return STATUS_UNSUCCESSFUL;
  1321. }
  1322. HalDebugPrint(( HAL_INFO, "HAL: EFI Virtual Address mapping done...\n" ));
  1323. //
  1324. // setup sal global pointers.
  1325. //
  1326. if (!SalCode.VirtualAddress) {
  1327. HalDebugPrint(( HAL_FATAL_ERROR, "HAL: no virtual address for sal code\n" ));
  1328. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1329. return (EfiInitStatus);
  1330. }
  1331. //
  1332. // The SAL GP is supposed to point somewhere within the SAL's short data
  1333. // segment (.sdata), meaning that we should be able to use it to find
  1334. // the SAL data area. Unfortunately most SALs are built using linkers
  1335. // that locate GP well outside of .sdata. As a consequence the SAL GP
  1336. // lies off of the memory map (not covered by any memory descriptor) on
  1337. // some systems. In this case we have no way of finding the descriptor
  1338. // that contains the SAL data while needing to relocate the SAL GP based
  1339. // upon the virtual address of this unknown descriptor (the data and GP
  1340. // need to remain fixed in relationship to one another). We try to detect
  1341. // and work around this problem here.
  1342. //
  1343. if (!SalData.VirtualAddress) {
  1344. //
  1345. // If we get here we'll need to do some tricks in order to
  1346. // generate a virtual address for the SAL data area (basically
  1347. // the SAL GP).
  1348. //
  1349. HalDebugPrint(( HAL_INFO,
  1350. "HAL: no virtual address for SalGP found, checking SalDataGPOffset 0x%I64x\n",
  1351. SalDataGPOffset.VirtualAddress ));
  1352. //
  1353. // Check if we found an EFI descriptor 2MB below the physical SAL GP
  1354. // address. If we did, add 2MB back to the newly constructed virtual
  1355. // address of that descriptor and call it the GP. This method will
  1356. // occasionally work because the current linkers typically put the
  1357. // GP 2MB outside of .sdata.
  1358. //
  1359. if (SalDataGPOffset.VirtualAddress) {
  1360. HalDebugPrint(( HAL_INFO, "HAL: using SalDataGPOffset.VirtualAddress\n" ));
  1361. SalData.VirtualAddress = SalDataGPOffset.VirtualAddress + (2 * 0x100000);
  1362. } else {
  1363. //
  1364. // As a last resort assume that the physical SAL GP address
  1365. // is relative to the SAL code memory descriptor. This will
  1366. // work as long as SAL code and data share the same EFI memory
  1367. // descriptor (otherwise the SAL GP is relative to a SAL data
  1368. // memory descriptor that we weren't able to detect). Currently
  1369. // there isn't any way to detect the case where SAL data is in
  1370. // a different memory descriptor that doesn't contain the SAL GP.
  1371. //
  1372. HalDebugPrint(( HAL_FATAL_ERROR, "HAL: no virtual address for sal data. Some systems don't seem to care so we're faking this.\n" ));
  1373. //
  1374. // SalCode.PhysicalAddress is the address of SAL_PROC. Load
  1375. // up the virtual address of SAL_PROC and the distance the
  1376. // virtual SAL GP should lie away from this point.
  1377. //
  1378. SalData.VirtualAddress = SalCode.VirtualAddress + SalOffset;
  1379. SalDataOffset = SalData.PhysicalAddress - SalCode.PhysicalAddress;
  1380. }
  1381. }
  1382. HalpSalProcPointer = (ULONGLONG) (SalCode.VirtualAddress + SalOffset);
  1383. HalpSalProcGlobalPointer = (ULONGLONG) (SalData.VirtualAddress + SalDataOffset);
  1384. HalDebugPrint(( HAL_INFO,
  1385. "HAL: SalProc: 0x%I64x SalGP: 0x%I64x \n",
  1386. HalpSalProcPointer,
  1387. HalpSalProcGlobalPointer
  1388. ));
  1389. EfiInitStatus = STATUS_SUCCESS;
  1390. //
  1391. // Execute some validity checks on the floating point software assist.
  1392. //
  1393. if (LoaderBlock->u.Ia64.FpswaInterface != (ULONG_PTR) NULL) {
  1394. PPLABEL_DESCRIPTOR plabelPointer;
  1395. HalpFpEmulate = interfacePtr->Fpswa;
  1396. if (HalpFpEmulate == NULL ) {
  1397. HalDebugPrint(( HAL_FATAL_ERROR, "HAL: EfiFpswa Virtual Addr is NULL\n" ));
  1398. KeBugCheckEx(FP_EMULATION_ERROR, 0, 0, 0, 0);
  1399. EfiInitStatus = STATUS_UNSUCCESSFUL;
  1400. return STATUS_UNSUCCESSFUL;
  1401. }
  1402. plabelPointer = (PPLABEL_DESCRIPTOR) HalpFpEmulate;
  1403. if ((plabelPointer->EntryPoint & 0xe000000000000000) == 0) {
  1404. HalDebugPrint(( HAL_FATAL_ERROR, "HAL: EfiFpswa Instruction Addr is bougus\n" ));
  1405. KeBugCheckEx(FP_EMULATION_ERROR, 0, 0, 0, 0);
  1406. }
  1407. }
  1408. return STATUS_SUCCESS;
  1409. } // HalpEfiInitialization()
  1410. EFI_STATUS
  1411. HalpCallEfiPhysical(
  1412. IN ULONGLONG Arg1,
  1413. IN ULONGLONG Arg2,
  1414. IN ULONGLONG Arg3,
  1415. IN ULONGLONG Arg4,
  1416. IN ULONGLONG Arg5,
  1417. IN ULONGLONG Arg6,
  1418. IN ULONGLONG EP,
  1419. IN ULONGLONG GP
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. This function is a wrapper for making a physical mode EFI call. This
  1424. function's only job is to provide the stack and backing store pointers
  1425. needed by HalpCallEfiPhysicalEx.
  1426. Arguments:
  1427. Arg1 through Arg6 - The arguments to be passed to EFI.
  1428. EP - The entry point of the EFI runtime service we want to call.
  1429. GP - The global pointer associated with the entry point.
  1430. Return Value:
  1431. The EFI_STATUS value returned by HalpCallEfiPhysicalEx.
  1432. --*/
  1433. {
  1434. ULONGLONG StackPointer;
  1435. ULONGLONG BackingStorePointer;
  1436. ULONGLONG StackBase;
  1437. //
  1438. // Load the addresses of the stack and backing store reserved for
  1439. // physical mode EFI calls on this processor.
  1440. //
  1441. StackBase = PCR->HalReserved[PROCESSOR_PHYSICAL_FW_STACK_INDEX];
  1442. StackPointer = GET_FW_STACK_POINTER(StackBase);
  1443. BackingStorePointer = GET_FW_BACKING_STORE_POINTER(StackBase);
  1444. //
  1445. // Branch to the assembly routine that makes the actual EFI call.
  1446. //
  1447. return HalpCallEfiPhysicalEx(
  1448. Arg1,
  1449. Arg2,
  1450. Arg3,
  1451. Arg4,
  1452. Arg5,
  1453. Arg6,
  1454. EP,
  1455. GP,
  1456. StackPointer,
  1457. BackingStorePointer
  1458. );
  1459. }
  1460. EFI_STATUS
  1461. HalpCallEfi(
  1462. IN ULONGLONG FunctionId,
  1463. IN ULONGLONG Arg1,
  1464. IN ULONGLONG Arg2,
  1465. IN ULONGLONG Arg3,
  1466. IN ULONGLONG Arg4,
  1467. IN ULONGLONG Arg5,
  1468. IN ULONGLONG Arg6,
  1469. IN ULONGLONG Arg7,
  1470. IN ULONGLONG Arg8
  1471. )
  1472. /*++
  1473. Routine Description:
  1474. :9
  1475. This function is a wrapper function for making a EFI call. Callers within the
  1476. HAL must use this function to call the EFI.
  1477. Arguments:
  1478. FunctionId - The EFI function
  1479. Arg1-Arg7 - EFI defined arguments for each call
  1480. ReturnValues - A pointer to an array of 4 64-bit return values
  1481. Return Value:
  1482. SAL's return status, return value 0, is returned in addition to the ReturnValues structure
  1483. being filled
  1484. --*/
  1485. {
  1486. ULONGLONG EP, GP;
  1487. EFI_STATUS efiStatus;
  1488. HALP_EFI_CALL EfiCall;
  1489. //
  1490. // Storage for old level
  1491. //
  1492. KIRQL OldLevel;
  1493. //
  1494. // Set EfiCall to the physical or virtual mode EFI call dispatcher
  1495. // depending upon whether we've made a successful call to SetVirtual
  1496. // AddressMap.
  1497. //
  1498. if (HalpSetVirtualAddressMapCount == 0) {
  1499. EfiCall = HalpCallEfiPhysical;
  1500. } else {
  1501. EfiCall = HalpCallEfiVirtual;
  1502. }
  1503. //
  1504. // Acquire MP Lock
  1505. //
  1506. KeAcquireSpinLock(&EFIMPLock, &OldLevel);
  1507. switch (FunctionId) {
  1508. case EFI_GET_VARIABLE_INDEX:
  1509. //
  1510. // Dereference the pointer to get the function arguements
  1511. //
  1512. EP = ((PPLABEL_DESCRIPTOR)EfiVirtualGetVariablePtr) -> EntryPoint;
  1513. GP = ((PPLABEL_DESCRIPTOR)EfiVirtualGetVariablePtr) -> GlobalPointer;
  1514. efiStatus = (EfiCall( (ULONGLONG)Arg1, // VariableNamePtr
  1515. (ULONGLONG)Arg2, // VendorGuidPtr
  1516. (ULONGLONG)Arg3, // VariableAttributesPtr,
  1517. (ULONGLONG)Arg4, // DataSizePtr,
  1518. (ULONGLONG)Arg5, // DataPtr,
  1519. Arg6,
  1520. EP,
  1521. GP
  1522. ));
  1523. break;
  1524. case EFI_SET_VARIABLE_INDEX:
  1525. //
  1526. // Dereference the pointer to get the function arguements
  1527. //
  1528. EP = ((PPLABEL_DESCRIPTOR)EfiVirtualSetVariablePtr) -> EntryPoint;
  1529. GP = ((PPLABEL_DESCRIPTOR)EfiVirtualSetVariablePtr) -> GlobalPointer;
  1530. efiStatus = (EfiCall( Arg1,
  1531. Arg2,
  1532. Arg3,
  1533. Arg4,
  1534. Arg5,
  1535. Arg6,
  1536. EP,
  1537. GP
  1538. ));
  1539. break;
  1540. case EFI_GET_NEXT_VARIABLE_NAME_INDEX:
  1541. //
  1542. // Dereference the pointer to get the function arguements
  1543. //
  1544. EP = ((PPLABEL_DESCRIPTOR)EfiVirtualGetNextVariableNamePtr) -> EntryPoint;
  1545. GP = ((PPLABEL_DESCRIPTOR)EfiVirtualGetNextVariableNamePtr) -> GlobalPointer;
  1546. efiStatus = (EfiCall( Arg1,
  1547. Arg2,
  1548. Arg3,
  1549. Arg4,
  1550. Arg5,
  1551. Arg6,
  1552. EP,
  1553. GP
  1554. ));
  1555. break;
  1556. case EFI_GET_TIME_INDEX:
  1557. //
  1558. // Dereference the pointer to get the function arguements
  1559. //
  1560. EP = ((PPLABEL_DESCRIPTOR)EfiVirtualGetTimePtr) -> EntryPoint;
  1561. GP = ((PPLABEL_DESCRIPTOR)EfiVirtualGetTimePtr) -> GlobalPointer;
  1562. efiStatus = (EfiCall ((ULONGLONG)Arg1, //EFI_TIME
  1563. (ULONGLONG)Arg2, //EFI_TIME Capabilities
  1564. Arg3,
  1565. Arg4,
  1566. Arg5,
  1567. Arg6,
  1568. EP,
  1569. GP
  1570. ));
  1571. break;
  1572. case EFI_SET_TIME_INDEX:
  1573. //
  1574. // Dereference the pointer to get the function arguements
  1575. //
  1576. EP = ((PPLABEL_DESCRIPTOR)EfiVirtualSetTimePtr) -> EntryPoint;
  1577. GP = ((PPLABEL_DESCRIPTOR)EfiVirtualSetTimePtr) -> GlobalPointer;
  1578. efiStatus = (EfiCall ((ULONGLONG)Arg1, //EFI_TIME
  1579. Arg2,
  1580. Arg3,
  1581. Arg4,
  1582. Arg5,
  1583. Arg6,
  1584. EP,
  1585. GP
  1586. ));
  1587. break;
  1588. case EFI_SET_VIRTUAL_ADDRESS_MAP_INDEX:
  1589. //
  1590. // Dereference the pointer to get the function arguements
  1591. //
  1592. EP = ((PPLABEL_DESCRIPTOR)EfiSetVirtualAddressMapPtr) -> EntryPoint;
  1593. GP = ((PPLABEL_DESCRIPTOR)EfiSetVirtualAddressMapPtr) -> GlobalPointer;
  1594. //
  1595. // Arg 1 and 5 are virtual mode pointers. We need to convert to physical
  1596. //
  1597. RtlCopyMemory (HalpMemoryMapVirtualPtr,
  1598. (PULONGLONG)Arg4,
  1599. (ULONG)EfiMemoryMapSize
  1600. );
  1601. efiStatus = (EfiCall ((ULONGLONG)EfiMemoryMapSize,
  1602. (ULONGLONG)EfiDescriptorSize,
  1603. (ULONGLONG)EfiDescriptorVersion,
  1604. (ULONGLONG)HalpMemoryMapPhysPtr,
  1605. Arg5,
  1606. Arg6,
  1607. EP,
  1608. GP
  1609. ));
  1610. //
  1611. // If the call was successful make a note in HalpSetVirtualAddressMap
  1612. // Count that EFI is now running in virtual mode.
  1613. //
  1614. if (efiStatus == EFI_SUCCESS) {
  1615. HalpSetVirtualAddressMapCount++;
  1616. }
  1617. break;
  1618. case EFI_RESET_SYSTEM_INDEX:
  1619. //
  1620. // Dereference the pointer to get the function arguements
  1621. //
  1622. EP = ((PPLABEL_DESCRIPTOR)EfiResetSystemPtr) -> EntryPoint;
  1623. GP = ((PPLABEL_DESCRIPTOR)EfiResetSystemPtr) -> GlobalPointer;
  1624. efiStatus = ((EfiCall ( Arg1,
  1625. Arg2,
  1626. Arg3,
  1627. Arg4,
  1628. Arg5,
  1629. Arg6,
  1630. EP,
  1631. GP
  1632. )));
  1633. break;
  1634. default:
  1635. //
  1636. // DebugPrint("EFI: Not supported now\n");
  1637. //
  1638. efiStatus = EFI_UNSUPPORTED;
  1639. break;
  1640. }
  1641. //
  1642. // Release the MP Lock
  1643. //
  1644. KeReleaseSpinLock (&EFIMPLock, OldLevel);
  1645. return efiStatus;
  1646. } // HalpCallEfi()
  1647. HalpFpErrorPrint (PAL_RETURN pal_ret)
  1648. {
  1649. ULONGLONG err_nr;
  1650. unsigned int qp;
  1651. ULONGLONG OpCode;
  1652. unsigned int rc;
  1653. unsigned int significand_size;
  1654. unsigned int ISRlow;
  1655. unsigned int f1;
  1656. unsigned int sign;
  1657. unsigned int exponent;
  1658. ULONGLONG significand;
  1659. unsigned int new_trap_type;
  1660. err_nr = pal_ret.err1 >> 56;
  1661. switch (err_nr) {
  1662. case 1:
  1663. // err_nr = 1 in err1, bits 63-56
  1664. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: template FXX is invalid\n"));
  1665. break;
  1666. case 2:
  1667. // err_nr = 2 in err1, bits 63-56
  1668. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: instruction slot 3 is not valid \n"));
  1669. break;
  1670. case 3:
  1671. // err_nr = 3 in err1, bits 63-56
  1672. // qp in err1, bits 31-0
  1673. qp = (unsigned int) pal_ret.err1 & 0xffffffff;
  1674. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: qualifying predicate PR[%ud] = 0 \n",qp));
  1675. break;
  1676. case 4:
  1677. // err_nr = 4 in err1, bits 63-56
  1678. // OpCode in err2, bits 63-0
  1679. OpCode = pal_ret.err2;
  1680. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: instruction opcode %8x%8x not recognized \n",
  1681. (unsigned int)((OpCode >> 32) & 0xffffffff),(unsigned int)(OpCode & 0xffffffff)));
  1682. break;
  1683. case 5:
  1684. // err_nr = 5 in err1, bits 63-56
  1685. // rc in err1, bits 31-0 (1-0)
  1686. rc = (unsigned int) pal_ret.err1 & 0xffffffff;
  1687. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: invalid rc = %ud\n", rc));
  1688. break;
  1689. case 6:
  1690. // err_nr = 6 in err1, bits 63-56
  1691. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: cannot determine the computation model \n"));
  1692. break;
  1693. case 7:
  1694. // err_nr = 7 in err1, bits 63-56
  1695. // significand_size in err1, bits 55-32
  1696. // ISRlow in err1, bits 31-0
  1697. // f1 in err2, bits 63-32
  1698. // tmp_fp.sign in err2, bit 17
  1699. // tmp_fp.exponent in err2, bits 16-0
  1700. // tmp_fp.significand in err3
  1701. significand_size = (unsigned int)((pal_ret.err1 >> 32) & 0xffffff);
  1702. ISRlow = (unsigned int) (pal_ret.err1 & 0xffffffff);
  1703. f1 = (unsigned int) ((pal_ret.err2 >> 32) & 0xffffffff);
  1704. sign = (unsigned int) ((pal_ret.err2 >> 17) & 0x01);
  1705. exponent = (unsigned int) (pal_ret.err2 & 0x1ffff);
  1706. significand = pal_ret.err3;
  1707. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: incorrect significand \
  1708. size %ud for ISRlow = %4.4x and FR[%ud] = %1.1x %5.5x %8x%8x\n",
  1709. significand_size, ISRlow, f1, sign, exponent,
  1710. (unsigned int)((significand >> 32) & 0xffffffff),
  1711. (unsigned int)(significand & 0xffffffff)));
  1712. break;
  1713. case 8:
  1714. // err_nr = 8 in err1, bits 63-56
  1715. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: non-tiny result\n"));
  1716. break;
  1717. case 9:
  1718. // err_nr = 9 in err1, bits 63-56
  1719. // significand_size in err1, bits 31-0
  1720. significand_size = (unsigned int) pal_ret.err1 & 0xffffffff;
  1721. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: incorrect significand \
  1722. size %ud\n", significand_size));
  1723. break;
  1724. case 10:
  1725. // err_nr = 10 in err1, bits 63-56
  1726. // rc in err1, bits 31-0
  1727. rc = (unsigned int) (pal_ret.err1 & 0xffffffff);
  1728. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: invalid rc = %ud for \
  1729. non-SIMD F1 instruction\n", rc));
  1730. break;
  1731. case 11:
  1732. // err_nr = 11 in err1, bits 63-56
  1733. // ISRlow & 0x0ffff in err1, bits 31-0
  1734. ISRlow = (unsigned int) (pal_ret.err1 & 0xffffffff);
  1735. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: SWA trap code invoked \
  1736. with F1 instruction, w/o O or U set in ISR.code = %x\n", ISRlow));
  1737. break;
  1738. case 12:
  1739. // err_nr = 12 in err1, bits 63-56
  1740. // ISRlow & 0x0ffff in err1, bits 31-0
  1741. ISRlow = (unsigned int) (pal_ret.err1 & 0xffffffff);
  1742. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: SWA trap code invoked \
  1743. with SIMD F1 instruction, w/o O or U set in ISR.code = %x\n", ISRlow));
  1744. break;
  1745. case 13:
  1746. // err_nr = 13 in err1, bits 63-56
  1747. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: non-tiny result low\n"));
  1748. break;
  1749. case 14:
  1750. // err_nr = 14 in err1, bits 63-56
  1751. // rc in err1, bits 31-0
  1752. rc = (unsigned int) (pal_ret.err1 & 0xffffffff);
  1753. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: invalid rc = %ud for \
  1754. SIMD F1 instruction\n", rc));
  1755. break;
  1756. case 15:
  1757. // err_nr = 15 in err1, bits 63-56
  1758. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: non-tiny result high\n"));
  1759. break;
  1760. case 16:
  1761. // err_nr = 16 in err1, bits 63-56
  1762. // OpCode in err2, bits 63-0
  1763. OpCode = pal_ret.err2;
  1764. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: instruction opcode %8x%8x \
  1765. not valid for SWA trap\n", (unsigned int)((OpCode >> 32) & 0xffffffff),
  1766. (unsigned int)(OpCode & 0xffffffff)));
  1767. break;
  1768. case 17:
  1769. // err_nr = 17 in err1, bits 63-56
  1770. // OpCode in err2, bits 63-0
  1771. // ISRlow in err3, bits 31-0
  1772. OpCode = pal_ret.err2;
  1773. ISRlow = (unsigned int) (pal_ret.err3 & 0xffffffff);
  1774. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: fp_emulate () called w/o \
  1775. trap_type FPFLT or FPTRAP, OpCode = %8x%8x, and ISR code = %x\n",
  1776. (unsigned int)((OpCode >> 32) & 0xffffffff),
  1777. (unsigned int)(OpCode & 0xffffffff), ISRlow));
  1778. break;
  1779. case 18:
  1780. // err_nr = 18 in err1, bits 63-56
  1781. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: SWA fault repeated\n"));
  1782. break;
  1783. case 19:
  1784. // err_nr = 19 in err1, bits 63-56
  1785. // new_trap_type in err1, bits 31-0
  1786. new_trap_type = (unsigned int) (pal_ret.err1 & 0xffffffff);
  1787. HalDebugPrint(( HAL_ERROR, "fp_emulate () Internal Error: new_trap_type = %x\n",
  1788. new_trap_type));
  1789. break;
  1790. default:
  1791. // error
  1792. HalDebugPrint(( HAL_ERROR, "Incorrect err_nr = %8x%8x from fp_emulate ()\n",
  1793. (unsigned int)((err_nr >> 32) & 0xffffffff),
  1794. (unsigned int)(err_nr & 0xffffffff)));
  1795. }
  1796. }
  1797. LONG
  1798. HalFpEmulate (
  1799. ULONG trap_type,
  1800. BUNDLE *pbundle,
  1801. ULONGLONG *pipsr,
  1802. ULONGLONG *pfpsr,
  1803. ULONGLONG *pisr,
  1804. ULONGLONG *ppreds,
  1805. ULONGLONG *pifs,
  1806. FP_STATE *fp_state
  1807. )
  1808. /*++
  1809. Routine Description:
  1810. This function is a wrapper function to make fp_emulate() call
  1811. to EFI FPSWA driver.
  1812. Arguments:
  1813. trap_type - indicating which FP trap it is.
  1814. pbundle - bundle where this trap occurred
  1815. pipsr - IPSR value
  1816. pfpsr - FPSR value
  1817. pisr - ISR value
  1818. ppreds - value of predicate registers
  1819. pifs - IFS value
  1820. fp_state - floating point registers
  1821. Return Value:
  1822. return IEEE result of the floating point operation
  1823. --*/
  1824. {
  1825. PAL_RETURN ret;
  1826. ret = (*HalpFpEmulate) (
  1827. trap_type,
  1828. pbundle,
  1829. pipsr,
  1830. pfpsr,
  1831. pisr,
  1832. ppreds,
  1833. pifs,
  1834. fp_state
  1835. );
  1836. if (ret.retval == FP_EMUL_ERROR) {
  1837. HalpFpErrorPrint (ret);
  1838. }
  1839. return ((LONG) (ret.retval));
  1840. }