| /** @file | |
| Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Guid/MemoryTypeInformation.h> | |
| #include "UefiPayloadEntry.h" | |
| STATIC UINT32 mTopOfLowerUsableDram = 0; | |
| EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = { | |
| { EfiACPIReclaimMemory, FixedPcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory) }, | |
| { EfiACPIMemoryNVS, FixedPcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS) }, | |
| { EfiReservedMemoryType, FixedPcdGet32 (PcdMemoryTypeEfiReservedMemoryType) }, | |
| { EfiRuntimeServicesData, FixedPcdGet32 (PcdMemoryTypeEfiRuntimeServicesData) }, | |
| { EfiRuntimeServicesCode, FixedPcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode) }, | |
| { EfiMaxMemoryType, 0 } | |
| }; | |
| /** | |
| Callback function to build resource descriptor HOB | |
| This function build a HOB based on the memory map entry info. | |
| It creates only EFI_RESOURCE_MEMORY_MAPPED_IO and EFI_RESOURCE_MEMORY_RESERVED | |
| resources. | |
| @param MemoryMapEntry Memory map entry info got from bootloader. | |
| @param Params A pointer to ACPI_BOARD_INFO. | |
| @retval EFI_SUCCESS Successfully build a HOB. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter provided. | |
| **/ | |
| EFI_STATUS | |
| MemInfoCallbackMmio ( | |
| IN MEMORY_MAP_ENTRY *MemoryMapEntry, | |
| IN VOID *Params | |
| ) | |
| { | |
| EFI_PHYSICAL_ADDRESS Base; | |
| EFI_RESOURCE_TYPE Type; | |
| UINT64 Size; | |
| EFI_RESOURCE_ATTRIBUTE_TYPE Attribue; | |
| ACPI_BOARD_INFO *AcpiBoardInfo; | |
| AcpiBoardInfo = (ACPI_BOARD_INFO *)Params; | |
| if (AcpiBoardInfo == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Skip types already handled in MemInfoCallback | |
| // | |
| if ((MemoryMapEntry->Type == E820_RAM) || (MemoryMapEntry->Type == E820_ACPI)) { | |
| return EFI_SUCCESS; | |
| } | |
| if (MemoryMapEntry->Base == AcpiBoardInfo->PcieBaseAddress) { | |
| // | |
| // MMCONF is always MMIO | |
| // | |
| Type = EFI_RESOURCE_MEMORY_MAPPED_IO; | |
| } else if (MemoryMapEntry->Base < mTopOfLowerUsableDram) { | |
| // | |
| // It's in DRAM and thus must be reserved | |
| // | |
| Type = EFI_RESOURCE_MEMORY_RESERVED; | |
| } else if ((MemoryMapEntry->Base < 0x100000000ULL) && (MemoryMapEntry->Base >= mTopOfLowerUsableDram)) { | |
| // | |
| // It's not in DRAM, must be MMIO | |
| // | |
| Type = EFI_RESOURCE_MEMORY_MAPPED_IO; | |
| } else { | |
| Type = EFI_RESOURCE_MEMORY_RESERVED; | |
| } | |
| Base = MemoryMapEntry->Base; | |
| Size = MemoryMapEntry->Size; | |
| Attribue = EFI_RESOURCE_ATTRIBUTE_PRESENT | | |
| EFI_RESOURCE_ATTRIBUTE_INITIALIZED | | |
| EFI_RESOURCE_ATTRIBUTE_TESTED | | |
| EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | | |
| EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | | |
| EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | | |
| EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE; | |
| BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size); | |
| DEBUG ((DEBUG_INFO, "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type)); | |
| if ((MemoryMapEntry->Type == E820_UNUSABLE) || | |
| (MemoryMapEntry->Type == E820_DISABLED)) | |
| { | |
| BuildMemoryAllocationHob (Base, Size, EfiUnusableMemory); | |
| } else if (MemoryMapEntry->Type == E820_PMEM) { | |
| BuildMemoryAllocationHob (Base, Size, EfiPersistentMemory); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Callback function to find TOLUD (Top of Lower Usable DRAM) | |
| Estimate where TOLUD (Top of Lower Usable DRAM) resides. The exact position | |
| would require platform specific code. | |
| @param MemoryMapEntry Memory map entry info got from bootloader. | |
| @param Params Not used for now. | |
| @retval EFI_SUCCESS Successfully updated mTopOfLowerUsableDram. | |
| **/ | |
| EFI_STATUS | |
| FindToludCallback ( | |
| IN MEMORY_MAP_ENTRY *MemoryMapEntry, | |
| IN VOID *Params | |
| ) | |
| { | |
| // | |
| // This code assumes that the memory map on this x86 machine below 4GiB is continous | |
| // until TOLUD. In addition it assumes that the bootloader provided memory tables have | |
| // no "holes" and thus the first memory range not covered by e820 marks the end of | |
| // usable DRAM. In addition it's assumed that every reserved memory region touching | |
| // usable RAM is also covering DRAM, everything else that is marked reserved thus must be | |
| // MMIO not detectable by bootloader/OS | |
| // | |
| // | |
| // Skip memory types not RAM or reserved | |
| // | |
| if ((MemoryMapEntry->Type == E820_UNUSABLE) || (MemoryMapEntry->Type == E820_DISABLED) || | |
| (MemoryMapEntry->Type == E820_PMEM)) | |
| { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Skip resources above 4GiB | |
| // | |
| if ((MemoryMapEntry->Base + MemoryMapEntry->Size) > 0x100000000ULL) { | |
| return EFI_SUCCESS; | |
| } | |
| if ((MemoryMapEntry->Type == E820_RAM) || (MemoryMapEntry->Type == E820_ACPI) || | |
| (MemoryMapEntry->Type == E820_NVS)) | |
| { | |
| // | |
| // It's usable DRAM. Update TOLUD. | |
| // | |
| if (mTopOfLowerUsableDram < (MemoryMapEntry->Base + MemoryMapEntry->Size)) { | |
| mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size); | |
| } | |
| } else { | |
| // | |
| // It might be 'reserved DRAM' or 'MMIO'. | |
| // | |
| // If it touches usable DRAM at Base assume it's DRAM as well, | |
| // as it could be bootloader installed tables, TSEG, GTT, ... | |
| // | |
| if (mTopOfLowerUsableDram == MemoryMapEntry->Base) { | |
| mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size); | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Callback function to build resource descriptor HOB | |
| This function build a HOB based on the memory map entry info. | |
| Only add EFI_RESOURCE_SYSTEM_MEMORY. | |
| @param MemoryMapEntry Memory map entry info got from bootloader. | |
| @param Params Not used for now. | |
| @retval RETURN_SUCCESS Successfully build a HOB. | |
| **/ | |
| EFI_STATUS | |
| MemInfoCallback ( | |
| IN MEMORY_MAP_ENTRY *MemoryMapEntry, | |
| IN VOID *Params | |
| ) | |
| { | |
| EFI_PHYSICAL_ADDRESS Base; | |
| EFI_RESOURCE_TYPE Type; | |
| UINT64 Size; | |
| EFI_RESOURCE_ATTRIBUTE_TYPE Attribue; | |
| // | |
| // Skip everything not known to be usable DRAM. | |
| // It will be added later. | |
| // | |
| if ((MemoryMapEntry->Type != E820_RAM) && (MemoryMapEntry->Type != E820_ACPI) && | |
| (MemoryMapEntry->Type != E820_NVS)) | |
| { | |
| return RETURN_SUCCESS; | |
| } | |
| Type = EFI_RESOURCE_SYSTEM_MEMORY; | |
| Base = MemoryMapEntry->Base; | |
| Size = MemoryMapEntry->Size; | |
| Attribue = EFI_RESOURCE_ATTRIBUTE_PRESENT | | |
| EFI_RESOURCE_ATTRIBUTE_INITIALIZED | | |
| EFI_RESOURCE_ATTRIBUTE_TESTED | | |
| EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | | |
| EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | | |
| EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | | |
| EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE; | |
| BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size); | |
| DEBUG ((DEBUG_INFO, "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type)); | |
| if (MemoryMapEntry->Type == E820_ACPI) { | |
| BuildMemoryAllocationHob (Base, Size, EfiACPIReclaimMemory); | |
| } else if (MemoryMapEntry->Type == E820_NVS) { | |
| BuildMemoryAllocationHob (Base, Size, EfiACPIMemoryNVS); | |
| } | |
| return RETURN_SUCCESS; | |
| } | |
| /** | |
| It will build HOBs based on information from bootloaders. | |
| @retval EFI_SUCCESS If it completed successfully. | |
| @retval Others If it failed to build required HOBs. | |
| **/ | |
| EFI_STATUS | |
| BuildHobFromBl ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| ACPI_BOARD_INFO *AcpiBoardInfo; | |
| EFI_PEI_GRAPHICS_INFO_HOB GfxInfo; | |
| EFI_PEI_GRAPHICS_INFO_HOB *NewGfxInfo; | |
| EFI_PEI_GRAPHICS_DEVICE_INFO_HOB GfxDeviceInfo; | |
| EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *NewGfxDeviceInfo; | |
| UNIVERSAL_PAYLOAD_SMBIOS_TABLE *SmBiosTableHob; | |
| UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTableHob; | |
| // | |
| // First find TOLUD | |
| // | |
| DEBUG ((DEBUG_INFO, "Guessing Top of Lower Usable DRAM:\n")); | |
| Status = ParseMemoryInfo (FindToludCallback, NULL); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| DEBUG ((DEBUG_INFO, "Assuming TOLUD = 0x%x\n", mTopOfLowerUsableDram)); | |
| // | |
| // Parse memory info and build memory HOBs for Usable RAM | |
| // | |
| DEBUG ((DEBUG_INFO, "Building ResourceDescriptorHobs for usable memory:\n")); | |
| Status = ParseMemoryInfo (MemInfoCallback, NULL); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Create guid hob for frame buffer information | |
| // | |
| Status = ParseGfxInfo (&GfxInfo); | |
| if (!EFI_ERROR (Status)) { | |
| NewGfxInfo = BuildGuidHob (&gEfiGraphicsInfoHobGuid, sizeof (GfxInfo)); | |
| ASSERT (NewGfxInfo != NULL); | |
| CopyMem (NewGfxInfo, &GfxInfo, sizeof (GfxInfo)); | |
| DEBUG ((DEBUG_INFO, "Created graphics info hob\n")); | |
| } | |
| Status = ParseGfxDeviceInfo (&GfxDeviceInfo); | |
| if (!EFI_ERROR (Status)) { | |
| NewGfxDeviceInfo = BuildGuidHob (&gEfiGraphicsDeviceInfoHobGuid, sizeof (GfxDeviceInfo)); | |
| ASSERT (NewGfxDeviceInfo != NULL); | |
| CopyMem (NewGfxDeviceInfo, &GfxDeviceInfo, sizeof (GfxDeviceInfo)); | |
| DEBUG ((DEBUG_INFO, "Created graphics device info hob\n")); | |
| } | |
| // | |
| // Creat SmBios table Hob | |
| // | |
| SmBiosTableHob = BuildGuidHob (&gUniversalPayloadSmbiosTableGuid, sizeof (UNIVERSAL_PAYLOAD_SMBIOS_TABLE)); | |
| ASSERT (SmBiosTableHob != NULL); | |
| SmBiosTableHob->Header.Revision = UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION; | |
| SmBiosTableHob->Header.Length = sizeof (UNIVERSAL_PAYLOAD_SMBIOS_TABLE); | |
| DEBUG ((DEBUG_INFO, "Create smbios table gUniversalPayloadSmbiosTableGuid guid hob\n")); | |
| Status = ParseSmbiosTable (SmBiosTableHob); | |
| if (!EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "Detected Smbios Table at 0x%lx\n", SmBiosTableHob->SmBiosEntryPoint)); | |
| } | |
| // | |
| // Creat ACPI table Hob | |
| // | |
| AcpiTableHob = BuildGuidHob (&gUniversalPayloadAcpiTableGuid, sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE)); | |
| ASSERT (AcpiTableHob != NULL); | |
| AcpiTableHob->Header.Revision = UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION; | |
| AcpiTableHob->Header.Length = sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE); | |
| DEBUG ((DEBUG_INFO, "Create ACPI table gUniversalPayloadAcpiTableGuid guid hob\n")); | |
| Status = ParseAcpiTableInfo (AcpiTableHob); | |
| if (!EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "Detected ACPI Table at 0x%lx\n", AcpiTableHob->Rsdp)); | |
| } | |
| // | |
| // Create guid hob for acpi board information | |
| // | |
| AcpiBoardInfo = BuildHobFromAcpi (AcpiTableHob->Rsdp); | |
| ASSERT (AcpiBoardInfo != NULL); | |
| // | |
| // Parse memory info and build memory HOBs for reserved DRAM and MMIO | |
| // | |
| DEBUG ((DEBUG_INFO, "Building ResourceDescriptorHobs for reserved memory:\n")); | |
| Status = ParseMemoryInfo (MemInfoCallbackMmio, AcpiBoardInfo); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Parse the misc info provided by bootloader | |
| // | |
| Status = ParseMiscInfo (); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_WARN, "Error when parsing misc info, Status = %r\n", Status)); | |
| } | |
| // | |
| // Parse platform specific information. | |
| // | |
| Status = ParsePlatformInfo (); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Error when parsing platform info, Status = %r\n", Status)); | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function will build some generic HOBs that doesn't depend on information from bootloaders. | |
| **/ | |
| VOID | |
| BuildGenericHob ( | |
| VOID | |
| ) | |
| { | |
| UINT32 RegEax; | |
| UINT8 PhysicalAddressBits; | |
| EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute; | |
| // The UEFI payload FV | |
| BuildMemoryAllocationHob (PcdGet32 (PcdPayloadFdMemBase), PcdGet32 (PcdPayloadFdMemSize), EfiBootServicesData); | |
| // | |
| // Build CPU memory space and IO space hob | |
| // | |
| AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); | |
| if (RegEax >= 0x80000008) { | |
| AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); | |
| PhysicalAddressBits = (UINT8)RegEax; | |
| } else { | |
| PhysicalAddressBits = 36; | |
| } | |
| BuildCpuHob (PhysicalAddressBits, 16); | |
| // | |
| // Report Local APIC range, cause sbl HOB to be NULL, comment now | |
| // | |
| ResourceAttribute = ( | |
| EFI_RESOURCE_ATTRIBUTE_PRESENT | | |
| EFI_RESOURCE_ATTRIBUTE_INITIALIZED | | |
| EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | | |
| EFI_RESOURCE_ATTRIBUTE_TESTED | |
| ); | |
| BuildResourceDescriptorHob (EFI_RESOURCE_MEMORY_MAPPED_IO, ResourceAttribute, 0xFEC80000, SIZE_512KB); | |
| BuildMemoryAllocationHob (0xFEC80000, SIZE_512KB, EfiMemoryMappedIO); | |
| } | |
| /** | |
| Entry point to the C language phase of UEFI payload. | |
| @param[in] BootloaderParameter The starting address of bootloader parameter block. | |
| @retval It will not return if SUCCESS, and return error when passing bootloader parameter. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| _ModuleEntryPoint ( | |
| IN UINTN BootloaderParameter | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| PHYSICAL_ADDRESS DxeCoreEntryPoint; | |
| UINTN MemBase; | |
| UINTN HobMemBase; | |
| UINTN HobMemTop; | |
| EFI_PEI_HOB_POINTERS Hob; | |
| SERIAL_PORT_INFO SerialPortInfo; | |
| UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO *UniversalSerialPort; | |
| Status = PcdSet64S (PcdBootloaderParameter, BootloaderParameter); | |
| ASSERT_EFI_ERROR (Status); | |
| // Initialize floating point operating environment to be compliant with UEFI spec. | |
| InitializeFloatingPointUnits (); | |
| // HOB region is used for HOB and memory allocation for this module | |
| MemBase = PcdGet32 (PcdPayloadFdMemBase); | |
| HobMemBase = ALIGN_VALUE (MemBase + PcdGet32 (PcdPayloadFdMemSize), SIZE_1MB); | |
| HobMemTop = HobMemBase + FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); | |
| HobConstructor ((VOID *)MemBase, (VOID *)HobMemTop, (VOID *)HobMemBase, (VOID *)HobMemTop); | |
| // | |
| // Build serial port info | |
| // | |
| Status = ParseSerialInfo (&SerialPortInfo); | |
| if (!EFI_ERROR (Status)) { | |
| UniversalSerialPort = BuildGuidHob (&gUniversalPayloadSerialPortInfoGuid, sizeof (UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO)); | |
| ASSERT (UniversalSerialPort != NULL); | |
| UniversalSerialPort->Header.Revision = UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO_REVISION; | |
| UniversalSerialPort->Header.Length = sizeof (UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO); | |
| UniversalSerialPort->UseMmio = (SerialPortInfo.Type == 1) ? FALSE : TRUE; | |
| UniversalSerialPort->RegisterBase = SerialPortInfo.BaseAddr; | |
| UniversalSerialPort->BaudRate = SerialPortInfo.Baud; | |
| UniversalSerialPort->RegisterStride = (UINT8)SerialPortInfo.RegWidth; | |
| } | |
| // The library constructors might depend on serial port, so call it after serial port hob | |
| ProcessLibraryConstructorList (); | |
| DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN))); | |
| // Build HOB based on information from Bootloader | |
| Status = BuildHobFromBl (); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "BuildHobFromBl Status = %r\n", Status)); | |
| return Status; | |
| } | |
| // Build other HOBs required by DXE | |
| BuildGenericHob (); | |
| // | |
| // Create Memory Type Information HOB | |
| // | |
| BuildGuidDataHob ( | |
| &gEfiMemoryTypeInformationGuid, | |
| mDefaultMemoryTypeInformation, | |
| sizeof (mDefaultMemoryTypeInformation) | |
| ); | |
| // Load the DXE Core | |
| Status = LoadDxeCore (&DxeCoreEntryPoint); | |
| ASSERT_EFI_ERROR (Status); | |
| DEBUG ((DEBUG_INFO, "DxeCoreEntryPoint = 0x%lx\n", DxeCoreEntryPoint)); | |
| // | |
| // Mask off all legacy 8259 interrupt sources | |
| // | |
| IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF); | |
| IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF); | |
| Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF); | |
| HandOffToDxeCore (DxeCoreEntryPoint, Hob); | |
| // Should not get here | |
| CpuDeadLoop (); | |
| return EFI_SUCCESS; | |
| } |