X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FPlatformPei%2FMemTypeInfo.c;h=fc5ccfaf113d25f09fc7b462de006cded6f27354;hb=ac0a286f4d74;hp=c709236a457a23bbb934c6ec8c12c9811fb33f08;hpb=d42fdd6f8384bb4681d93e4a25d8f57db1e63adb;p=mirror_edk2.git diff --git a/OvmfPkg/PlatformPei/MemTypeInfo.c b/OvmfPkg/PlatformPei/MemTypeInfo.c index c709236a45..fc5ccfaf11 100644 --- a/OvmfPkg/PlatformPei/MemTypeInfo.c +++ b/OvmfPkg/PlatformPei/MemTypeInfo.c @@ -1,7 +1,5 @@ /** @file - Produce a default memory type information HOB unless we can determine, from - the existence of the "MemoryTypeInformation" variable, that the DXE IPL PEIM - will produce the HOB. + Produce the memory type information HOB. Copyright (C) 2017-2020, Red Hat, Inc. @@ -19,15 +17,16 @@ #include "Platform.h" -STATIC EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = { - { EfiACPIMemoryNVS, 0x004 }, - { EfiACPIReclaimMemory, 0x008 }, - { EfiReservedMemoryType, 0x004 }, - { EfiRuntimeServicesData, 0x024 }, - { EfiRuntimeServicesCode, 0x030 }, - { EfiBootServicesCode, 0x180 }, - { EfiBootServicesData, 0xF00 }, - { EfiMaxMemoryType, 0x000 } +#define MEMORY_TYPE_INFO_DEFAULT(Type) \ + { Type, FixedPcdGet32 (PcdMemoryType ## Type) } + +STATIC EFI_MEMORY_TYPE_INFORMATION mMemoryTypeInformation[] = { + MEMORY_TYPE_INFO_DEFAULT (EfiACPIMemoryNVS), + MEMORY_TYPE_INFO_DEFAULT (EfiACPIReclaimMemory), + MEMORY_TYPE_INFO_DEFAULT (EfiReservedMemoryType), + MEMORY_TYPE_INFO_DEFAULT (EfiRuntimeServicesCode), + MEMORY_TYPE_INFO_DEFAULT (EfiRuntimeServicesData), + { EfiMaxMemoryType, 0} }; STATIC @@ -38,11 +37,129 @@ BuildMemTypeInfoHob ( { BuildGuidDataHob ( &gEfiMemoryTypeInformationGuid, - mDefaultMemoryTypeInformation, - sizeof mDefaultMemoryTypeInformation + mMemoryTypeInformation, + sizeof mMemoryTypeInformation ); - DEBUG ((DEBUG_INFO, "%a: default memory type information HOB built\n", - __FUNCTION__)); +} + +/** + Refresh the mMemoryTypeInformation array (which we'll turn into the + MemoryTypeInformation HOB) from the MemoryTypeInformation UEFI variable. + + Normally, the DXE IPL PEIM builds the HOB from the UEFI variable. But it does + so *transparently*. Instead, we consider the UEFI variable as a list of + hints, for updating our HOB defaults: + + - Record types not covered in mMemoryTypeInformation are ignored. In + particular, this hides record types from the UEFI variable that may lead to + reboots without benefiting SMM security, such as EfiBootServicesData. + + - Records that would lower the defaults in mMemoryTypeInformation are also + ignored. + + @param[in] ReadOnlyVariable2 The EFI_PEI_READ_ONLY_VARIABLE2_PPI used for + retrieving the MemoryTypeInformation UEFI + variable. +**/ +STATIC +VOID +RefreshMemTypeInfo ( + IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *ReadOnlyVariable2 + ) +{ + UINTN DataSize; + EFI_MEMORY_TYPE_INFORMATION Entries[EfiMaxMemoryType + 1]; + EFI_STATUS Status; + UINTN NumEntries; + UINTN HobRecordIdx; + + // + // Read the MemoryTypeInformation UEFI variable from the + // gEfiMemoryTypeInformationGuid namespace. + // + DataSize = sizeof Entries; + Status = ReadOnlyVariable2->GetVariable ( + ReadOnlyVariable2, + EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, + &gEfiMemoryTypeInformationGuid, + NULL, + &DataSize, + Entries + ); + if (EFI_ERROR (Status)) { + // + // If the UEFI variable does not exist (EFI_NOT_FOUND), we can't use it for + // udpating mMemoryTypeInformation. + // + // If the UEFI variable exists but Entries is too small to hold it + // (EFI_BUFFER_TOO_SMALL), then the variable contents are arguably invalid. + // That's because Entries has room for every distinct EFI_MEMORY_TYPE, + // including the terminator record with EfiMaxMemoryType. Thus, we can't + // use the UEFI variable for updating mMemoryTypeInformation. + // + // If the UEFI variable couldn't be read for some other reason, we + // similarly can't use it for udpating mMemoryTypeInformation. + // + DEBUG ((DEBUG_ERROR, "%a: GetVariable(): %r\n", __FUNCTION__, Status)); + return; + } + + // + // Sanity-check the UEFI variable size against the record size. + // + if (DataSize % sizeof Entries[0] != 0) { + DEBUG (( + DEBUG_ERROR, + "%a: invalid UEFI variable size %Lu\n", + __FUNCTION__, + (UINT64)DataSize + )); + return; + } + + NumEntries = DataSize / sizeof Entries[0]; + + // + // For each record in mMemoryTypeInformation, except the terminator record, + // look up the first match (if any) in the UEFI variable, based on the memory + // type. + // + for (HobRecordIdx = 0; + HobRecordIdx < ARRAY_SIZE (mMemoryTypeInformation) - 1; + HobRecordIdx++) + { + EFI_MEMORY_TYPE_INFORMATION *HobRecord; + UINTN Idx; + EFI_MEMORY_TYPE_INFORMATION *VariableRecord; + + HobRecord = &mMemoryTypeInformation[HobRecordIdx]; + + for (Idx = 0; Idx < NumEntries; Idx++) { + VariableRecord = &Entries[Idx]; + + if (VariableRecord->Type == HobRecord->Type) { + break; + } + } + + // + // If there is a match, allow the UEFI variable to increase NumberOfPages. + // + if ((Idx < NumEntries) && + (HobRecord->NumberOfPages < VariableRecord->NumberOfPages)) + { + DEBUG (( + DEBUG_VERBOSE, + "%a: Type 0x%x: NumberOfPages 0x%x -> 0x%x\n", + __FUNCTION__, + HobRecord->Type, + HobRecord->NumberOfPages, + VariableRecord->NumberOfPages + )); + + HobRecord->NumberOfPages = VariableRecord->NumberOfPages; + } + } } /** @@ -66,47 +183,10 @@ OnReadOnlyVariable2Available ( IN VOID *Ppi ) { - EFI_PEI_READ_ONLY_VARIABLE2_PPI *ReadOnlyVariable2; - UINTN DataSize; - EFI_STATUS Status; - DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__)); - // - // Check if the "MemoryTypeInformation" variable exists, in the - // gEfiMemoryTypeInformationGuid namespace. - // - ReadOnlyVariable2 = Ppi; - DataSize = 0; - Status = ReadOnlyVariable2->GetVariable ( - ReadOnlyVariable2, - EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, - &gEfiMemoryTypeInformationGuid, - NULL, - &DataSize, - NULL - ); - switch (Status) { - case EFI_BUFFER_TOO_SMALL: - // - // The variable exists; the DXE IPL PEIM will build the HOB from it. - // - break; - case EFI_NOT_FOUND: - // - // The variable does not exist; install the default memory type information - // HOB. - // - BuildMemTypeInfoHob (); - break; - default: - DEBUG ((DEBUG_ERROR, "%a: unexpected: GetVariable(): %r\n", __FUNCTION__, - Status)); - ASSERT (FALSE); - CpuDeadLoop (); - break; - } - + RefreshMemTypeInfo (Ppi); + BuildMemTypeInfoHob (); return EFI_SUCCESS; } @@ -114,7 +194,7 @@ OnReadOnlyVariable2Available ( // Notification object for registering the callback, for when // EFI_PEI_READ_ONLY_VARIABLE2_PPI becomes available. // -STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mReadOnlyVariable2Notify = { +STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mReadOnlyVariable2Notify = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), // Flags &gEfiPeiReadOnlyVariable2PpiGuid, // Guid @@ -126,7 +206,7 @@ MemTypeInfoInitialization ( VOID ) { - EFI_STATUS Status; + EFI_STATUS Status; if (!FeaturePcdGet (PcdSmmSmramRequire)) { // @@ -139,8 +219,12 @@ MemTypeInfoInitialization ( Status = PeiServicesNotifyPpi (&mReadOnlyVariable2Notify); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a: failed to set up R/O Variable 2 callback: %r\n", - __FUNCTION__, Status)); + DEBUG (( + DEBUG_ERROR, + "%a: failed to set up R/O Variable 2 callback: %r\n", + __FUNCTION__, + Status + )); ASSERT (FALSE); CpuDeadLoop (); }