From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 08FAD80403 for ; Tue, 14 Mar 2017 16:33:11 -0700 (PDT) Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 97D9285547; Tue, 14 Mar 2017 23:33:11 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-194.phx2.redhat.com [10.3.116.194]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v2ENWpwh006449; Tue, 14 Mar 2017 19:33:10 -0400 From: Laszlo Ersek To: edk2-devel-01 Cc: Jordan Justen Date: Wed, 15 Mar 2017 00:32:45 +0100 Message-Id: <20170314233246.17864-14-lersek@redhat.com> In-Reply-To: <20170314233246.17864-1-lersek@redhat.com> References: <20170314233246.17864-1-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 14 Mar 2017 23:33:11 +0000 (UTC) Subject: [PATCH 13/14] OvmfPkg/PlatformPei: remedy UEFI memory map fragmentation X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 14 Mar 2017 23:33:11 -0000 The Memory Type Information HOB is used for sizing the allocation bins for the various memory types. If the PEI phase does not produce the HOB, and it includes the VariablePei driver, then the DXE IPL PEIM will itself build the HOB, from the "MemoryTypeInformation" non-volatile variable. (The HOB is consumed in the DxeLoadCore() function, and it is ignored if the boot mode is BOOT_ON_S3_RESUME. Accordingly, we already don't build the HOB in InitializePlatform() during S3 resume; MemMapInitialization() isn't called.) In the BDS phase, BmSetMemoryTypeInformationVariable() reads the variable (if it exists) under all boot modes different from BOOT_WITH_DEFAULT_SETTINGS, and (re-)sets the variable if it doesn't exist, or the counts of the pages allocated during boot have changed, relative to what the variable predicted. In effect this creates a feedback loop between BDS and the next boot's PEI, making sure the memory allocation bins are sized large enough in advance. Ultimately, for BOOT_WITH_FULL_CONFIGURATION, as a special case of the above, this measures the maximum boot memory requirement per UEFI memory type, and over time decreases fragmentation in the UEFI memory map. We continue creating our (constant) Memory Type Information HOB in OvmfPkg/PlatformPei -- which prevents the above feedback loop -- except in one case: when OVMF is built with SMM_REQUIRE=TRUE or MEM_VARSTORE_EMU_ENABLE=FALSE (that is, when a flash-based varstore is guaranteed), and the "MemoryTypeInformation" variable exists (that is, when the virtual machine has been booted at least once). This lets the OS installer see a somewhat fragmented memory map at first boot, but further boots should witness defragmented maps. In practice the difference seems to be 20-24 entries in the UEFI memory map. In the longer term this should also serve as basis for S4 enablement. For now, we keep the PcdResetOnMemoryTypeInformationChange|FALSE setting in the OVMF DSC files, dating back to commit 7709cf48e432 ("DuetPkg, OvmfPkg, UnixPkg: Remove unnecessary reset during boot", 2010-12-06). Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- OvmfPkg/PlatformPei/PlatformPei.inf | 2 + OvmfPkg/PlatformPei/Platform.h | 5 + OvmfPkg/PlatformPei/MemTypeInfo.c | 151 ++++++++++++++++++++ OvmfPkg/PlatformPei/Platform.c | 23 +-- 4 files changed, 159 insertions(+), 22 deletions(-) diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf index 9c1ffa9815c1..21f3a5ea4909 100644 --- a/OvmfPkg/PlatformPei/PlatformPei.inf +++ b/OvmfPkg/PlatformPei/PlatformPei.inf @@ -33,6 +33,7 @@ [Sources] FeatureControl.c Fv.c MemDetect.c + MemTypeInfo.c Platform.c Xen.c @@ -108,6 +109,7 @@ [FeaturePcd] [Ppis] gEfiPeiMasterBootModePpiGuid gEfiPeiMpServicesPpiGuid + gEfiPeiReadOnlyVariable2PpiGuid [Depex] TRUE diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h index 18f42c3f0ea8..64a87da4a70a 100644 --- a/OvmfPkg/PlatformPei/Platform.h +++ b/OvmfPkg/PlatformPei/Platform.h @@ -74,6 +74,11 @@ PeiFvInitialization ( ); VOID +MemTypeInfoInitialization ( + VOID + ); + +VOID InstallFeatureControlCallback ( VOID ); diff --git a/OvmfPkg/PlatformPei/MemTypeInfo.c b/OvmfPkg/PlatformPei/MemTypeInfo.c new file mode 100644 index 000000000000..46ed9aaf8f31 --- /dev/null +++ b/OvmfPkg/PlatformPei/MemTypeInfo.c @@ -0,0 +1,151 @@ +/**@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. + + Copyright (C) 2017, Red Hat, Inc. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include +#include +#include +#include +#include +#include +#include + +#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 } +}; + +STATIC +VOID +BuildMemTypeInfoHob ( + VOID + ) +{ + BuildGuidDataHob ( + &gEfiMemoryTypeInformationGuid, + mDefaultMemoryTypeInformation, + sizeof mDefaultMemoryTypeInformation + ); + DEBUG (( + DEBUG_INFO, + "%a: default memory type information HOB built\n", + __FUNCTION__ + )); +} + +/** + Notification function called when EFI_PEI_READ_ONLY_VARIABLE2_PPI becomes + available. + + @param[in] PeiServices Indirect reference to the PEI Services Table. + @param[in] NotifyDescriptor Address of the notification descriptor data + structure. + @param[in] Ppi Address of the PPI that was installed. + + @return Status of the notification. The status code returned from this + function is ignored. +**/ +STATIC +EFI_STATUS +EFIAPI +OnReadOnlyVariable2Available ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_PEI_READ_ONLY_VARIABLE2_PPI *ReadOnlyVariable2; + UINTN DataSize; + EFI_STATUS Status; + + DEBUG ((DEBUG_VERBOSE, "%a: %a\n", gEfiCallerBaseName, __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 + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // The variable exists; the DXE IPL PEIM will build the HOB from it. + // + return EFI_SUCCESS; + } + // + // Install the default memory type information HOB. + // + BuildMemTypeInfoHob (); + return EFI_SUCCESS; +} + +// +// Notification object for registering the callback, for when +// EFI_PEI_READ_ONLY_VARIABLE2_PPI becomes available. +// +STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mReadOnlyVariable2Notify = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), // Flags + &gEfiPeiReadOnlyVariable2PpiGuid, // Guid + OnReadOnlyVariable2Available // Notify +}; + +VOID +MemTypeInfoInitialization ( + VOID + ) +{ + EFI_STATUS Status; + + if (!FeaturePcdGet (PcdSmmSmramRequire) && + FeaturePcdGet (PcdMemVarstoreEmuEnable)) { + // + // EFI_PEI_READ_ONLY_VARIABLE2_PPI will never be available; install + // the default memory type information HOB right away. + // + BuildMemTypeInfoHob (); + return; + } + + Status = PeiServicesNotifyPpi (&mReadOnlyVariable2Notify); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: failed to set up R/O Variable 2 callback: %r\n", + __FUNCTION__, + Status + )); + // + // Install the default HOB as a last resort. + // + BuildMemTypeInfoHob (); + } +} diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c index ec449b422eda..11a7a05fb1d7 100644 --- a/OvmfPkg/PlatformPei/Platform.c +++ b/OvmfPkg/PlatformPei/Platform.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -42,18 +41,6 @@ #include "Platform.h" #include "Cmos.h" -EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = { - { EfiACPIMemoryNVS, 0x004 }, - { EfiACPIReclaimMemory, 0x008 }, - { EfiReservedMemoryType, 0x004 }, - { EfiRuntimeServicesData, 0x024 }, - { EfiRuntimeServicesCode, 0x030 }, - { EfiBootServicesCode, 0x180 }, - { EfiBootServicesData, 0xF00 }, - { EfiMaxMemoryType, 0x000 } -}; - - EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = { { EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, @@ -166,15 +153,6 @@ MemMapInitialization ( PciIoSize = 0x4000; // - // Create Memory Type Information HOB - // - BuildGuidDataHob ( - &gEfiMemoryTypeInformationGuid, - mDefaultMemoryTypeInformation, - sizeof(mDefaultMemoryTypeInformation) - ); - - // // Video memory + Legacy BIOS region // AddIoMemoryRangeHob (0x0A0000, BASE_1MB); @@ -666,6 +644,7 @@ InitializePlatform ( ReserveEmuVariableNvStore (); } PeiFvInitialization (); + MemTypeInfoInitialization (); MemMapInitialization (); NoexecDxeInitialization (); } -- 2.9.3