On UEFI systems, the SMBIOS entry point (a.k.a. anchor) structures are found similarly to the ACPI RSD PTR table(s): by scanning the ConfigurationTable array in the EFI system table for well-known GUIDs. Locate the SMBIOS 2.1 (32-bit) and 3.0 (64-bit) anchors in the BiosTablesTest UEFI application, and report the addresses in new fields appended to the BIOS_TABLES_TEST structure. Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com> Cc: Igor Mammedov <imammedo@redhat.com> Launchpad: https://bugs.launchpad.net/qemu/+bug/1821884 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Tested-by: Igor Mammedov <imammedo@redhat.com>
		
			
				
	
	
		
			146 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Populate the BIOS_TABLES_TEST structure.
 | 
						|
 | 
						|
  Copyright (C) 2019, Red Hat, Inc.
 | 
						|
 | 
						|
  This program and the accompanying materials are licensed and made available
 | 
						|
  under the terms and conditions of the BSD License that 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/Acpi.h>
 | 
						|
#include <Guid/BiosTablesTest.h>
 | 
						|
#include <Guid/SmBios.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
 | 
						|
/**
 | 
						|
  Wait for a keypress with a message that the application is about to exit.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
WaitForExitKeyPress (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS    Status;
 | 
						|
  UINTN         Idx;
 | 
						|
  EFI_INPUT_KEY Key;
 | 
						|
 | 
						|
  if (gST->ConIn == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  AsciiPrint ("%a: press any key to exit\n", gEfiCallerBaseName);
 | 
						|
  Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Idx);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
BiosTablesTestMain (
 | 
						|
  IN EFI_HANDLE       ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID                          *Pages;
 | 
						|
  volatile BIOS_TABLES_TEST     *BiosTablesTest;
 | 
						|
  CONST VOID                    *Rsdp10;
 | 
						|
  CONST VOID                    *Rsdp20;
 | 
						|
  CONST VOID                    *Smbios21;
 | 
						|
  CONST VOID                    *Smbios30;
 | 
						|
  CONST EFI_CONFIGURATION_TABLE *ConfigTable;
 | 
						|
  CONST EFI_CONFIGURATION_TABLE *ConfigTablesEnd;
 | 
						|
  volatile EFI_GUID             *InverseSignature;
 | 
						|
  UINTN                         Idx;
 | 
						|
 | 
						|
  Pages = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof *BiosTablesTest),
 | 
						|
            SIZE_1MB);
 | 
						|
  if (Pages == NULL) {
 | 
						|
    AsciiErrorPrint ("%a: AllocateAlignedPages() failed\n",
 | 
						|
      gEfiCallerBaseName);
 | 
						|
    //
 | 
						|
    // Assuming the application was launched by the boot manager as a boot
 | 
						|
    // loader, exiting with error will cause the boot manager to proceed with
 | 
						|
    // the remaining boot options. If there are no other boot options, the boot
 | 
						|
    // manager menu will be pulled up. Give the user a chance to read the error
 | 
						|
    // message.
 | 
						|
    //
 | 
						|
    WaitForExitKeyPress ();
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Locate all the gEfiAcpi10TableGuid, gEfiAcpi20TableGuid,
 | 
						|
  // gEfiSmbiosTableGuid, gEfiSmbios3TableGuid config tables in one go.
 | 
						|
  //
 | 
						|
  Rsdp10 = NULL;
 | 
						|
  Rsdp20 = NULL;
 | 
						|
  Smbios21 = NULL;
 | 
						|
  Smbios30 = NULL;
 | 
						|
  ConfigTable = gST->ConfigurationTable;
 | 
						|
  ConfigTablesEnd = gST->ConfigurationTable + gST->NumberOfTableEntries;
 | 
						|
  while ((Rsdp10 == NULL || Rsdp20 == NULL ||
 | 
						|
          Smbios21 == NULL || Smbios30 == NULL) &&
 | 
						|
         ConfigTable < ConfigTablesEnd) {
 | 
						|
    if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi10TableGuid)) {
 | 
						|
      Rsdp10 = ConfigTable->VendorTable;
 | 
						|
    } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi20TableGuid)) {
 | 
						|
      Rsdp20 = ConfigTable->VendorTable;
 | 
						|
    } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiSmbiosTableGuid)) {
 | 
						|
      Smbios21 = ConfigTable->VendorTable;
 | 
						|
    } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiSmbios3TableGuid)) {
 | 
						|
      Smbios30 = ConfigTable->VendorTable;
 | 
						|
    }
 | 
						|
    ++ConfigTable;
 | 
						|
  }
 | 
						|
 | 
						|
  AsciiPrint ("%a: BiosTablesTest=%p Rsdp10=%p Rsdp20=%p\n",
 | 
						|
    gEfiCallerBaseName, Pages, Rsdp10, Rsdp20);
 | 
						|
  AsciiPrint ("%a: Smbios21=%p Smbios30=%p\n", gEfiCallerBaseName, Smbios21,
 | 
						|
    Smbios30);
 | 
						|
 | 
						|
  //
 | 
						|
  // Store the config table addresses first, then the signature second.
 | 
						|
  //
 | 
						|
  BiosTablesTest = Pages;
 | 
						|
  BiosTablesTest->Rsdp10 = (UINTN)Rsdp10;
 | 
						|
  BiosTablesTest->Rsdp20 = (UINTN)Rsdp20;
 | 
						|
  BiosTablesTest->Smbios21 = (UINTN)Smbios21;
 | 
						|
  BiosTablesTest->Smbios30 = (UINTN)Smbios30;
 | 
						|
 | 
						|
  MemoryFence();
 | 
						|
 | 
						|
  InverseSignature = &BiosTablesTest->InverseSignatureGuid;
 | 
						|
  InverseSignature->Data1  = gBiosTablesTestGuid.Data1;
 | 
						|
  InverseSignature->Data1 ^= MAX_UINT32;
 | 
						|
  InverseSignature->Data2  = gBiosTablesTestGuid.Data2;
 | 
						|
  InverseSignature->Data2 ^= MAX_UINT16;
 | 
						|
  InverseSignature->Data3  = gBiosTablesTestGuid.Data3;
 | 
						|
  InverseSignature->Data3 ^= MAX_UINT16;
 | 
						|
  for (Idx = 0; Idx < sizeof InverseSignature->Data4; ++Idx) {
 | 
						|
    InverseSignature->Data4[Idx]  = gBiosTablesTestGuid.Data4[Idx];
 | 
						|
    InverseSignature->Data4[Idx] ^= MAX_UINT8;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The wait below has dual purpose. First, it blocks the application without
 | 
						|
  // wasting VCPU cycles while the hypervisor is scanning guest RAM. Second,
 | 
						|
  // assuming the application was launched by the boot manager as a boot
 | 
						|
  // loader, exiting the app with success causes the boot manager to pull up
 | 
						|
  // the boot manager menu at once (regardless of other boot options); the wait
 | 
						|
  // gives the user a chance to read the info printed above.
 | 
						|
  //
 | 
						|
  WaitForExitKeyPress ();
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |