OvmfPkg/LoongArchVirt: Support PEI phase

Platfrom PEI module for LoongArch platfrom initialization.

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Dongyan Qian <qiandongyan@loongson.cn>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
This commit is contained in:
Chao Li 2024-06-14 17:10:15 +08:00 committed by mergify[bot]
parent 9912434785
commit e5e2cf48a9
5 changed files with 789 additions and 0 deletions

View File

@ -0,0 +1,36 @@
/** @file
Build FV related hobs for platform.
Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
/**
Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
and DXE know about them.
@retval EFI_SUCCESS Platform PEI FVs were initialized successfully.
**/
EFI_STATUS
PeiFvInitialization (
VOID
)
{
DEBUG ((DEBUG_INFO, "Platform PEI Firmware Volume Initialization\n"));
//
// Create a memory allocation HOB for the PEI FV.
//
BuildMemoryAllocationHob (
FixedPcdGet64 (PcdOvmfSecPeiTempRamBase),
FixedPcdGet32 (PcdOvmfSecPeiTempRamSize),
EfiBootServicesData
);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,237 @@
/** @file
Memory Detection for Virtual Machines.
Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
//
// The package level header files this module uses
//
#include <PiPei.h>
//
// The Library classes this module consumes
//
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/ResourcePublicationLib.h>
#include <Register/LoongArch64/Csr.h>
#include <Uefi/UefiSpec.h>
#include "Platform.h"
#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
#define LOONGARCH_FW_RAM_TOP BASE_256MB
/**
Publish PEI core memory
@return EFI_SUCCESS The PEIM initialized successfully.
**/
EFI_STATUS
PublishPeiMemory (
VOID
)
{
EFI_STATUS Status;
UINT64 Base;
UINT64 Size;
UINT64 RamTop;
FIRMWARE_CONFIG_ITEM FwCfgItem;
UINTN FwCfgSize;
UINTN Processed;
MEMMAP_ENTRY MemoryMapEntry;
//
// Determine the range of memory to use during PEI
//
Base = FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize);
RamTop = 0;
Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
if (EFI_ERROR (Status)) {
return Status;
}
if (FwCfgSize % sizeof MemoryMapEntry != 0) {
return EFI_PROTOCOL_ERROR;
}
QemuFwCfgSelectItem (FwCfgItem);
for (Processed = 0; Processed < FwCfgSize; Processed += sizeof MemoryMapEntry) {
QemuFwCfgReadBytes (sizeof MemoryMapEntry, &MemoryMapEntry);
if (MemoryMapEntry.Type != EfiAcpiAddressRangeMemory) {
continue;
}
//
// Find memory map entry where PEI temp stack is located
//
if ((MemoryMapEntry.BaseAddr <= Base) &&
(Base < (MemoryMapEntry.BaseAddr + MemoryMapEntry.Length)))
{
RamTop = MemoryMapEntry.BaseAddr + MemoryMapEntry.Length;
break;
}
}
if (RamTop == 0) {
DEBUG ((DEBUG_ERROR, "ERROR: No memory map entry contains temp stack \n"));
ASSERT (FALSE);
}
Size = RamTop - Base;
//
// Publish this memory to the PEI Core
//
Status = PublishSystemMemory (Base, Size);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "Publish Memory Initialize done.\n"));
return Status;
}
/**
Peform Memory Detection
Publish system RAM and reserve memory regions
**/
VOID
InitializeRamRegions (
VOID
)
{
EFI_STATUS Status;
FIRMWARE_CONFIG_ITEM FwCfgItem;
UINTN FwCfgSize;
MEMMAP_ENTRY MemoryMapEntry;
MEMMAP_ENTRY *StartEntry;
MEMMAP_ENTRY *pEntry;
UINTN Processed;
Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status));
return;
}
if (FwCfgSize % sizeof MemoryMapEntry != 0) {
DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));
return;
}
QemuFwCfgSelectItem (FwCfgItem);
StartEntry = AllocatePages (EFI_SIZE_TO_PAGES (FwCfgSize));
QemuFwCfgReadBytes (FwCfgSize, StartEntry);
for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) {
pEntry = StartEntry + Processed;
if (pEntry->Length == 0) {
continue;
}
DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type));
if (pEntry->Type != EfiAcpiAddressRangeMemory) {
continue;
}
AddMemoryRangeHob (pEntry->BaseAddr, pEntry->BaseAddr + pEntry->Length);
}
//
// When 0 address protection is enabled,
// 0-4k memory needs to be preallocated to prevent UEFI applications from allocating use,
// such as grub
//
if (PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) {
BuildMemoryAllocationHob (
0,
EFI_PAGE_SIZE,
EfiBootServicesData
);
}
}
/**
Gets the Virtual Memory Map of corresponding platforms.
This Virtual Memory Map is used by initialize the MMU on corresponding
platforms.
@param[out] MemoryTable Array of EFI_MEMORY_DESCRIPTOR
describing a Physical-to-Virtual Memory
mapping. This array must be ended by a
zero-filled entry. The allocated memory
will not be freed.
**/
VOID
EFIAPI
GetMemoryMapPolicy (
OUT EFI_MEMORY_DESCRIPTOR **MemoryTable
)
{
EFI_STATUS Status;
FIRMWARE_CONFIG_ITEM FwCfgItem;
UINTN FwCfgSize;
MEMMAP_ENTRY MemoryMapEntry;
MEMMAP_ENTRY *StartEntry;
MEMMAP_ENTRY *pEntry;
UINTN Processed;
EFI_MEMORY_DESCRIPTOR *VirtualMemoryTable;
UINTN Index = 0;
ASSERT (MemoryTable != NULL);
VirtualMemoryTable = AllocatePool (
sizeof (EFI_MEMORY_DESCRIPTOR) *
MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
);
//
// Add the 0x10000000-0x20000000. In the virtual machine, this area use for CPU UART, flash, PIC etc.
//
VirtualMemoryTable[Index].PhysicalStart = BASE_256MB;
VirtualMemoryTable[Index].VirtualStart = VirtualMemoryTable[Index].PhysicalStart;
VirtualMemoryTable[Index].NumberOfPages = EFI_SIZE_TO_PAGES (SIZE_256MB);
VirtualMemoryTable[Index].Attribute = EFI_MEMORY_UC;
++Index;
Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status));
ZeroMem (&VirtualMemoryTable[Index], sizeof (EFI_MEMORY_DESCRIPTOR));
*MemoryTable = VirtualMemoryTable;
return;
}
if (FwCfgSize % sizeof MemoryMapEntry != 0) {
DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));
}
QemuFwCfgSelectItem (FwCfgItem);
StartEntry = AllocatePages (EFI_SIZE_TO_PAGES (FwCfgSize));
QemuFwCfgReadBytes (FwCfgSize, StartEntry);
for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) {
pEntry = StartEntry + Processed;
if (pEntry->Length == 0) {
continue;
}
DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type));
VirtualMemoryTable[Index].PhysicalStart = pEntry->BaseAddr;
VirtualMemoryTable[Index].VirtualStart = VirtualMemoryTable[Index].PhysicalStart;
VirtualMemoryTable[Index].NumberOfPages = EFI_SIZE_TO_PAGES (pEntry->Length);
VirtualMemoryTable[Index].Attribute = EFI_MEMORY_WB;
++Index;
}
FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));
// End of Table
ZeroMem (&VirtualMemoryTable[Index], sizeof (EFI_MEMORY_DESCRIPTOR));
*MemoryTable = VirtualMemoryTable;
}

View File

@ -0,0 +1,364 @@
/** @file
Platform PEI driver
Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Glossary:
- Mem - Memory
**/
//
// The package level header files this module uses
//
#include <PiPei.h>
//
// The Library classes this module consumes
//
#include <Guid/MemoryTypeInformation.h>
#include <Guid/FdtHob.h>
#include <Library/BaseMemoryLib.h>
#include <Library/CpuMmuInitLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/MpInitLib.h>
#include <Library/PcdLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
#include <Library/PlatformHookLib.h>
#include <Library/QemuFwCfgLib.h>
#include <libfdt.h>
#include <Ppi/MasterBootMode.h>
#include <Register/LoongArch64/Cpucfg.h>
#include <Register/LoongArch64/Csr.h>
#include <Uefi/UefiSpec.h>
#include "Platform.h"
STATIC EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
{ EfiReservedMemoryType, 0x004 },
{ EfiRuntimeServicesData, 0x024 },
{ EfiRuntimeServicesCode, 0x030 },
{ EfiBootServicesCode, 0x180 },
{ EfiBootServicesData, 0xF00 },
{ EfiMaxMemoryType, 0x000 }
};
//
// Module globals
//
CONST EFI_PEI_PPI_DESCRIPTOR mPpiListBootMode = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiMasterBootModePpiGuid,
NULL
};
STATIC EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
/**
Create system type memory range hand off block.
@param MemoryBase memory base address.
@param MemoryLimit memory length.
@return VOID
**/
STATIC
VOID
AddMemoryBaseSizeHob (
EFI_PHYSICAL_ADDRESS MemoryBase,
UINT64 MemorySize
)
{
BuildResourceDescriptorHob (
EFI_RESOURCE_SYSTEM_MEMORY,
EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
EFI_RESOURCE_ATTRIBUTE_TESTED,
MemoryBase,
MemorySize
);
}
/**
Create memory range hand off block.
@param MemoryBase memory base address.
@param MemoryLimit memory length.
@return VOID
**/
VOID
AddMemoryRangeHob (
EFI_PHYSICAL_ADDRESS MemoryBase,
EFI_PHYSICAL_ADDRESS MemoryLimit
)
{
AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
}
STATIC
VOID
SaveRtcRegisterAddressHob (
UINT64 RtcRegisterBase
)
{
UINT64 Data64;
//
// Build location of RTC register base address buffer in HOB
//
Data64 = (UINT64)(UINTN)RtcRegisterBase;
BuildGuidDataHob (
&gRtcRegisterBaseAddressHobGuid,
(VOID *)&Data64,
sizeof (UINT64)
);
}
/**
Create memory type information hand off block.
@param VOID
@return VOID
**/
STATIC
VOID
MemMapInitialization (
VOID
)
{
DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
//
// Create Memory Type Information HOB
//
BuildGuidDataHob (
&gEfiMemoryTypeInformationGuid,
mDefaultMemoryTypeInformation,
sizeof (mDefaultMemoryTypeInformation)
);
}
/** Get the Rtc base address from the DT.
This function fetches the node referenced in the "loongson,ls7a-rtc"
property of the "reg" node and returns the base address of
the RTC.
@param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
@param [out] RtcBaseAddress If success, contains the base address
of the Rtc.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND RTC info not found in DT.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
STATIC
EFI_STATUS
EFIAPI
GetRtcAddress (
IN CONST VOID *Fdt,
OUT UINT64 *RtcBaseAddress
)
{
INT32 Node;
INT32 Prev;
CONST CHAR8 *Type;
INT32 Len;
CONST UINT64 *RegProp;
EFI_STATUS Status;
if ((Fdt == NULL) || (fdt_check_header (Fdt) != 0)) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_NOT_FOUND;
for (Prev = 0; ; Prev = Node) {
Node = fdt_next_node (Fdt, Prev, NULL);
if (Node < 0) {
break;
}
//
// Check for memory node
//
Type = fdt_getprop (Fdt, Node, "compatible", &Len);
if ((Type) && (AsciiStrnCmp (Type, "loongson,ls7a-rtc", Len) == 0)) {
//
// Get the 'reg' property of this node. For now, we will assume
// two 8 byte quantities for base and size, respectively.
//
RegProp = fdt_getprop (Fdt, Node, "reg", &Len);
if ((RegProp != 0) && (Len == (2 * sizeof (UINT64)))) {
*RtcBaseAddress = SwapBytes64 (RegProp[0]);
Status = RETURN_SUCCESS;
DEBUG ((DEBUG_INFO, "%a Len %d RtcBase %llx\n", __func__, Len, *RtcBaseAddress));
break;
} else {
DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT rtc node\n", __func__));
break;
}
}
}
return Status;
}
/**
Misc Initialization.
@param VOID
@return VOID
**/
STATIC
VOID
MiscInitialization (
VOID
)
{
CPUCFG_REG1_INFO_DATA CpucfgReg1Data;
UINT8 CpuPhysMemAddressWidth;
DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
//
// Get the the CPU physical memory address width.
//
AsmCpucfg (CPUCFG_REG1_INFO, &CpucfgReg1Data.Uint32);
CpuPhysMemAddressWidth = (UINT8)(CpucfgReg1Data.Bits.PALEN + 1);
//
// Creat CPU HOBs.
//
BuildCpuHob (CpuPhysMemAddressWidth, FixedPcdGet8 (PcdPrePiCpuIoSize));
}
/**
add fdt hand off block.
@param VOID
@return VOID
**/
STATIC
VOID
AddFdtHob (
VOID
)
{
VOID *Base;
VOID *NewBase;
UINTN FdtSize;
UINTN FdtPages;
UINT64 *FdtHobData;
UINT64 RtcBaseAddress;
RETURN_STATUS Status;
Base = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
ASSERT (Base != NULL);
Status = GetRtcAddress (Base, &RtcBaseAddress);
if (RETURN_ERROR (Status)) {
return;
}
SaveRtcRegisterAddressHob (RtcBaseAddress);
FdtSize = fdt_totalsize (Base) + PcdGet32 (PcdDeviceTreeAllocationPadding);
FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
NewBase = AllocatePages (FdtPages);
ASSERT (NewBase != NULL);
fdt_open_into (Base, NewBase, EFI_PAGES_TO_SIZE (FdtPages));
FdtHobData = BuildGuidHob (&gFdtHobGuid, sizeof *FdtHobData);
ASSERT (FdtHobData != NULL);
*FdtHobData = (UINTN)NewBase;
}
/**
Fetch the size of system memory from QEMU.
@param VOID
@return VOID
**/
STATIC
VOID
ReportSystemMemorySize (
VOID
)
{
UINT64 RamSize;
QemuFwCfgSelectItem (QemuFwCfgItemRamSize);
RamSize = QemuFwCfgRead64 ();
DEBUG ((
DEBUG_INFO,
"%a: QEMU reports %dM system memory\n",
__func__,
RamSize/1024/1024
));
}
/**
Perform Platform PEI initialization.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@return EFI_SUCCESS The PEIM initialized successfully.
**/
EFI_STATUS
EFIAPI
InitializePlatform (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
EFI_MEMORY_DESCRIPTOR *MemoryTable;
DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
Status = PeiServicesSetBootMode (mBootMode);
ASSERT_EFI_ERROR (Status);
Status = PeiServicesInstallPpi (&mPpiListBootMode);
ASSERT_EFI_ERROR (Status);
ReportSystemMemorySize ();
PublishPeiMemory ();
PeiFvInitialization ();
InitializeRamRegions ();
MemMapInitialization ();
Status = PlatformHookSerialPortInitialize ();
ASSERT_EFI_ERROR (Status);
MiscInitialization ();
AddFdtHob ();
//
// Initialization MMU
//
GetMemoryMapPolicy (&MemoryTable);
Status = ConfigureMemoryManagementUnit (MemoryTable);
ASSERT_EFI_ERROR (Status);
MpInitLibInitialize ();
return EFI_SUCCESS;
}

View File

@ -0,0 +1,85 @@
/** @file
Platform PEI module include file.
Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef PLATFORM_H_
#define PLATFORM_H_
#include <IndustryStandard/E820.h>
typedef struct {
UINT64 BaseAddr;
UINT64 Length;
UINT32 Type;
UINT32 Reserved;
} MEMMAP_ENTRY;
/**
Create memory range hand off block.
@param MemoryBase memory base address.
@param MemoryLimit memory length.
@return VOID
**/
VOID
AddMemoryRangeHob (
EFI_PHYSICAL_ADDRESS MemoryBase,
EFI_PHYSICAL_ADDRESS MemoryLimit
);
/**
Publish PEI core memory
@return EFI_SUCCESS The PEIM initialized successfully.
**/
EFI_STATUS
PublishPeiMemory (
VOID
);
/**
Publish system RAM and reserve memory regions
@return VOID
**/
VOID
InitializeRamRegions (
VOID
);
/**
Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
and DXE know about them.
@retval EFI_SUCCESS Platform PEI FVs were initialized successfully.
**/
EFI_STATUS
PeiFvInitialization (
VOID
);
/**
Gets the Virtual Memory Map of corresponding platforms.
This Virtual Memory Map is used by initialize the MMU on corresponding
platforms.
@param[out] MemoryTable Array of EFI_MEMORY_DESCRIPTOR
describing a Physical-to-Virtual Memory
mapping. This array must be ended by a
zero-filled entry. The allocated memory
will not be freed.
**/
VOID
EFIAPI
GetMemoryMapPolicy (
OUT EFI_MEMORY_DESCRIPTOR **MemoryTable
);
#endif // PLATFORM_H_

View File

@ -0,0 +1,67 @@
## @file
# Platform PEI driver
#
# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 1.29
BASE_NAME = PlatformPei
FILE_GUID = 4c0e81e5-e8e3-4eef-b24b-19b686e9ab53
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = InitializePlatform
#
# VALID_ARCHITECTURES = LOONGARCH64
#
[Sources]
Fv.c
MemDetect.c
Platform.c
[Packages]
EmbeddedPkg/EmbeddedPkg.dec
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
OvmfPkg/OvmfPkg.dec
UefiCpuPkg/UefiCpuPkg.dec
[Ppis]
gEfiPeiMasterBootModePpiGuid
[Guids]
gEfiMemoryTypeInformationGuid
gFdtHobGuid
gRtcRegisterBaseAddressHobGuid
[LibraryClasses]
BaseMemoryLib
CpuMmuInitLib
DebugLib
HobLib
MemoryAllocationLib
MpInitLib
PcdLib
PeimEntryPoint
PeiServicesLib
PlatformHookLib
PeiResourcePublicationLib
QemuFwCfgLib
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeAllocationPadding
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
[FixedPcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize
[Depex]
TRUE