From f340a4a4b804b410f1c2e9a9d6b22b78fa950e9a Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Tue, 23 Jun 2015 13:14:59 +0200
Subject: [PATCH] OvmfPkg: PlatformPei: set SMBIOS entry point version
 dynamically

Message-id: <1435058099-6393-2-git-send-email-lersek@redhat.com>
Patchwork-id: 66364
O-Subject:  [RHEL-7.2 OVMF PATCH 1/1] OvmfPkg: PlatformPei: set SMBIOS entry
	point version dynamically
Bugzilla: 1232876
Acked-by: Don Dutile <ddutile@redhat.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Andrew Jones <drjones@redhat.com>

Git commit 54753b60 (SVN r16870), "MdeModulePkg: Update SMBIOS revision to
3.0." changed PcdSmbiosVersion from 0x0208 to 0x0300. This controls the
version number of the SMBIOS entry point table (and other things) that
"MdeModulePkg/Universal/SmbiosDxe" installs.

Alas, this change breaks older Linux guests, like RHEL-6 (up to RHEL-6.7);
those are limited to 2.x (both in the guest kernel firmware driver, and in
the dmidecode utility). The SMBIOS 3.0 entry point has a different GUID --
defined in UEFI 2.5 -- pointing to it in the UEFI Configuration Table, and
guest kernels that lack upstream kernel commit e1ccbbc9d5 don't recognize
it.

The v2.1.0+ machine types of QEMU generate SMBIOS payload for the firmware
to install. The payload includes the entry point table ("anchor" table).
OvmfPkg/SmbiosPlatformDxe cannot install the anchor table (because that is
the jurisdiction of the generic "MdeModulePkg/Universal/SmbiosDxe"
driver); however, we can parse the entry point version from QEMU's anchor
table, and instruct "MdeModulePkg/Universal/SmbiosDxe" to adhere to that
version.

On machine types older than v2.1.0, the feature is not available, but
then, should anything in OVMF install SMBIOS tables, version 2.8 is simply
safer / more widely supported than 3.0 -- hence the default 2.8 value for
the dynamic PCD.

We set the PCD in PlatformPei (when not on the S3 resume path), because
that's an easy and certain way to set the PCD before a DXE driver reads
it. This follows the example of PcdEmuVariableNvStoreReserved (which is
read by EmuVariableFvbRuntimeDxe).

RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1232876
Cc: Gabriel Somlo <somlo@cmu.edu>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Acked-by: Gabriel Somlo <somlo@cmu.edu>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17676 6f19259b-4bc3-4df7-8a09-765794883524
(cherry picked from commit 37baf06b44ba78214aca8806b8516575d3b20db6)

RHEL-7 notes:

- This patch does not affect AAVMF.

- When run on RHEL machine types that lack the full SMBIOS generator,
  downstream OVMF still utilizes the legacy SMBIOS fw_cfg interface, and
  then this patch amounts to a static 3.0 -> 2.8 SMBIOS entry point
  downgrade (which matches our intent). In other words, downstream OVMF
  running on said machine types matches the paragraph "should anything in
  OVMF install SMBIOS tables [...]" above.

- The SMBIOS entry point exported by the full SMBIOS generator (whenever
  the latter is available) has actually version 2.8, so the dynamism in
  this patch makes no difference in practice ATM; it's only effective as
  "future proofing".

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/OvmfPkgIa32.dsc             |  2 ++
 OvmfPkg/OvmfPkgIa32X64.dsc          |  2 ++
 OvmfPkg/OvmfPkgX64.dsc              |  2 ++
 OvmfPkg/PlatformPei/Platform.c      | 39 +++++++++++++++++++++++++++++++++++++
 OvmfPkg/PlatformPei/PlatformPei.inf |  2 ++
 5 files changed, 47 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index a5b339f..baa3f73 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -357,6 +357,8 @@
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|640
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution|480
 
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0208
+
 ################################################################################
 #
 # Components Section - list of all EDK II Modules needed by this Platform.
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index a48c4b7..39401ad 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -363,6 +363,8 @@
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|640
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution|480
 
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0208
+
 ################################################################################
 #
 # Components Section - list of all EDK II Modules needed by this Platform.
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 78eecfc..827df78 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -362,6 +362,8 @@
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|640
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution|480
 
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0208
+
 ################################################################################
 #
 # Components Section - list of all EDK II Modules needed by this Platform.
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 5ce0a90..653ccfe 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -32,9 +32,11 @@
 #include <Library/PeiServicesLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/ResourcePublicationLib.h>
+#include <Library/BaseMemoryLib.h>
 #include <Guid/MemoryTypeInformation.h>
 #include <Ppi/MasterBootMode.h>
 #include <IndustryStandard/Pci22.h>
+#include <IndustryStandard/SmBios.h>
 #include <OvmfPlatforms.h>
 
 #include "Platform.h"
@@ -363,6 +365,41 @@ DebugDumpCmos (
 
 
 /**
+  Set the SMBIOS entry point version for the generic SmbiosDxe driver.
+**/
+STATIC
+VOID
+SmbiosVersionInitialization (
+  VOID
+  )
+{
+  FIRMWARE_CONFIG_ITEM     Anchor;
+  UINTN                    AnchorSize;
+  SMBIOS_TABLE_ENTRY_POINT QemuAnchor;
+  UINT16                   SmbiosVersion;
+
+  if (RETURN_ERROR (QemuFwCfgFindFile ("etc/smbios/smbios-anchor", &Anchor,
+                      &AnchorSize)) ||
+      AnchorSize != sizeof QemuAnchor) {
+    return;
+  }
+
+  QemuFwCfgSelectItem (Anchor);
+  QemuFwCfgReadBytes (AnchorSize, &QemuAnchor);
+  if (CompareMem (QemuAnchor.AnchorString, "_SM_", 4) != 0 ||
+      CompareMem (QemuAnchor.IntermediateAnchorString, "_DMI_", 5) != 0) {
+    return;
+  }
+
+  SmbiosVersion = (UINT16)(QemuAnchor.MajorVersion << 8 |
+                           QemuAnchor.MinorVersion);
+  DEBUG ((EFI_D_INFO, "%a: SMBIOS version from QEMU: 0x%04x\n", __FUNCTION__,
+    SmbiosVersion));
+  PcdSet16 (PcdSmbiosVersion, SmbiosVersion);
+}
+
+
+/**
   Perform Platform PEI initialization.
 
   @param  FileHandle      Handle of the file being invoked.
@@ -406,6 +443,8 @@ InitializePlatform (
     PeiFvInitialization ();
 
     MemMapInitialization ();
+
+    SmbiosVersionInitialization ();
   }
 
   MiscInitialization ();
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 0307bca..721495b 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -58,6 +58,7 @@
   QemuFwCfgLib
   MtrrLib
   PcdLib
+  BaseMemoryLib
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
@@ -81,6 +82,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
   gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved
   gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion
   gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
 
 [Ppis]
-- 
1.8.3.1

