| /** @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; |
| } |