public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel-01 <edk2-devel@ml01.01.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Subject: [PATCH 13/14] OvmfPkg/PlatformPei: remedy UEFI memory map fragmentation
Date: Wed, 15 Mar 2017 00:32:45 +0100	[thread overview]
Message-ID: <20170314233246.17864-14-lersek@redhat.com> (raw)
In-Reply-To: <20170314233246.17864-1-lersek@redhat.com>

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 <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 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 <Guid/MemoryTypeInformation.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Uefi/UefiMultiPhase.h>
+
+#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 <Library/QemuFwCfgLib.h>
 #include <Library/QemuFwCfgS3Lib.h>
 #include <Library/ResourcePublicationLib.h>
-#include <Guid/MemoryTypeInformation.h>
 #include <Ppi/MasterBootMode.h>
 #include <IndustryStandard/Pci22.h>
 #include <OvmfPlatforms.h>
@@ -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




  parent reply	other threads:[~2017-03-14 23:33 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-14 23:32 [PATCH 00/14] OvmfPkg: add the Variable PEIM, defragment the UEFI memmap Laszlo Ersek
2017-03-14 23:32 ` [PATCH 01/14] OvmfPkg/EmuVariableFvbRuntimeDxe: always format an auth varstore header Laszlo Ersek
2017-03-14 23:32 ` [PATCH 02/14] OvmfPkg: remove gUefiOvmfPkgTokenSpaceGuid.PcdSecureBootEnable Laszlo Ersek
2017-03-14 23:32 ` [PATCH 03/14] OvmfPkg/PlatformPei: remove unused PcdVariableStoreSize dependency Laszlo Ersek
2017-03-14 23:32 ` [PATCH 04/14] OvmfPkg/PlatformPei: don't allocate reserved mem varstore if SMM_REQUIRE Laszlo Ersek
2017-03-14 23:32 ` [PATCH 05/14] OvmfPkg: introduce PcdMemVarstoreEmuEnable feature flag Laszlo Ersek
2017-03-14 23:32 ` [PATCH 06/14] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: check PcdMemVarstoreEmuEnable Laszlo Ersek
2017-03-14 23:32 ` [PATCH 07/14] OvmfPkg: conditionally disable reserved memory varstore emulation at build Laszlo Ersek
2017-03-14 23:32 ` [PATCH 08/14] OvmfPkg: resolve PcdLib for all PEIMs individually Laszlo Ersek
2017-03-14 23:32 ` [PATCH 09/14] OvmfPkg: resolve PcdLib for PEIMs to PeiPcdLib by default Laszlo Ersek
2017-03-14 23:32 ` [PATCH 10/14] OvmfPkg: introduce FlashNvStorageAddressLib Laszlo Ersek
2017-03-14 23:32 ` [PATCH 11/14] OvmfPkg: include FaultTolerantWritePei and VariablePei Laszlo Ersek
2017-03-14 23:32 ` [PATCH 12/14] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: don't set flash PCDs if SMM or no-emu Laszlo Ersek
2017-03-14 23:32 ` Laszlo Ersek [this message]
2017-03-14 23:32 ` [PATCH 14/14] OvmfPkg/README: document MEM_VARSTORE_EMU_ENABLE and memmap defrag Laszlo Ersek
2017-03-16 18:51 ` [PATCH 00/14] OvmfPkg: add the Variable PEIM, defragment the UEFI memmap Jordan Justen
2017-03-16 21:22   ` Laszlo Ersek
2017-03-22 16:58     ` Laszlo Ersek
2017-03-24  7:38       ` Jordan Justen
2017-03-24 12:49         ` Laszlo Ersek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170314233246.17864-14-lersek@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox