mirror of
				https://github.com/qemu/qemu.git
				synced 2025-10-31 04:06:46 +00:00 
			
		
		
		
	 b097ba371a
			
		
	
	
		b097ba371a
		
	
	
	
	
		
			
			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;
 | |
| }
 |