109a274d8SLaszlo Ersek /** @file
209a274d8SLaszlo Ersek   Populate the BIOS_TABLES_TEST structure.
309a274d8SLaszlo Ersek 
409a274d8SLaszlo Ersek   Copyright (C) 2019, Red Hat, Inc.
509a274d8SLaszlo Ersek 
609a274d8SLaszlo Ersek   This program and the accompanying materials are licensed and made available
709a274d8SLaszlo Ersek   under the terms and conditions of the BSD License that accompanies this
809a274d8SLaszlo Ersek   distribution. The full text of the license may be found at
909a274d8SLaszlo Ersek   <http://opensource.org/licenses/bsd-license.php>.
1009a274d8SLaszlo Ersek 
1109a274d8SLaszlo Ersek   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
1209a274d8SLaszlo Ersek   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
1309a274d8SLaszlo Ersek **/
1409a274d8SLaszlo Ersek 
1509a274d8SLaszlo Ersek #include <Guid/Acpi.h>
1609a274d8SLaszlo Ersek #include <Guid/BiosTablesTest.h>
17*b097ba37SLaszlo Ersek #include <Guid/SmBios.h>
1809a274d8SLaszlo Ersek #include <Library/BaseLib.h>
1909a274d8SLaszlo Ersek #include <Library/BaseMemoryLib.h>
2009a274d8SLaszlo Ersek #include <Library/MemoryAllocationLib.h>
2109a274d8SLaszlo Ersek #include <Library/UefiBootServicesTableLib.h>
2209a274d8SLaszlo Ersek #include <Library/UefiLib.h>
2309a274d8SLaszlo Ersek 
2409a274d8SLaszlo Ersek /**
2509a274d8SLaszlo Ersek   Wait for a keypress with a message that the application is about to exit.
2609a274d8SLaszlo Ersek **/
2709a274d8SLaszlo Ersek STATIC
2809a274d8SLaszlo Ersek VOID
WaitForExitKeyPress(VOID)2909a274d8SLaszlo Ersek WaitForExitKeyPress (
3009a274d8SLaszlo Ersek   VOID
3109a274d8SLaszlo Ersek   )
3209a274d8SLaszlo Ersek {
3309a274d8SLaszlo Ersek   EFI_STATUS    Status;
3409a274d8SLaszlo Ersek   UINTN         Idx;
3509a274d8SLaszlo Ersek   EFI_INPUT_KEY Key;
3609a274d8SLaszlo Ersek 
3709a274d8SLaszlo Ersek   if (gST->ConIn == NULL) {
3809a274d8SLaszlo Ersek     return;
3909a274d8SLaszlo Ersek   }
4009a274d8SLaszlo Ersek   AsciiPrint ("%a: press any key to exit\n", gEfiCallerBaseName);
4109a274d8SLaszlo Ersek   Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Idx);
4209a274d8SLaszlo Ersek   if (EFI_ERROR (Status)) {
4309a274d8SLaszlo Ersek     return;
4409a274d8SLaszlo Ersek   }
4509a274d8SLaszlo Ersek   gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
4609a274d8SLaszlo Ersek }
4709a274d8SLaszlo Ersek 
4809a274d8SLaszlo Ersek EFI_STATUS
4909a274d8SLaszlo Ersek EFIAPI
BiosTablesTestMain(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)5009a274d8SLaszlo Ersek BiosTablesTestMain (
5109a274d8SLaszlo Ersek   IN EFI_HANDLE       ImageHandle,
5209a274d8SLaszlo Ersek   IN EFI_SYSTEM_TABLE *SystemTable
5309a274d8SLaszlo Ersek   )
5409a274d8SLaszlo Ersek {
5509a274d8SLaszlo Ersek   VOID                          *Pages;
5609a274d8SLaszlo Ersek   volatile BIOS_TABLES_TEST     *BiosTablesTest;
5709a274d8SLaszlo Ersek   CONST VOID                    *Rsdp10;
5809a274d8SLaszlo Ersek   CONST VOID                    *Rsdp20;
59*b097ba37SLaszlo Ersek   CONST VOID                    *Smbios21;
60*b097ba37SLaszlo Ersek   CONST VOID                    *Smbios30;
6109a274d8SLaszlo Ersek   CONST EFI_CONFIGURATION_TABLE *ConfigTable;
6209a274d8SLaszlo Ersek   CONST EFI_CONFIGURATION_TABLE *ConfigTablesEnd;
6309a274d8SLaszlo Ersek   volatile EFI_GUID             *InverseSignature;
6409a274d8SLaszlo Ersek   UINTN                         Idx;
6509a274d8SLaszlo Ersek 
6609a274d8SLaszlo Ersek   Pages = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof *BiosTablesTest),
6709a274d8SLaszlo Ersek             SIZE_1MB);
6809a274d8SLaszlo Ersek   if (Pages == NULL) {
6909a274d8SLaszlo Ersek     AsciiErrorPrint ("%a: AllocateAlignedPages() failed\n",
7009a274d8SLaszlo Ersek       gEfiCallerBaseName);
7109a274d8SLaszlo Ersek     //
7209a274d8SLaszlo Ersek     // Assuming the application was launched by the boot manager as a boot
7309a274d8SLaszlo Ersek     // loader, exiting with error will cause the boot manager to proceed with
7409a274d8SLaszlo Ersek     // the remaining boot options. If there are no other boot options, the boot
7509a274d8SLaszlo Ersek     // manager menu will be pulled up. Give the user a chance to read the error
7609a274d8SLaszlo Ersek     // message.
7709a274d8SLaszlo Ersek     //
7809a274d8SLaszlo Ersek     WaitForExitKeyPress ();
7909a274d8SLaszlo Ersek     return EFI_OUT_OF_RESOURCES;
8009a274d8SLaszlo Ersek   }
8109a274d8SLaszlo Ersek 
8209a274d8SLaszlo Ersek   //
83*b097ba37SLaszlo Ersek   // Locate all the gEfiAcpi10TableGuid, gEfiAcpi20TableGuid,
84*b097ba37SLaszlo Ersek   // gEfiSmbiosTableGuid, gEfiSmbios3TableGuid config tables in one go.
8509a274d8SLaszlo Ersek   //
8609a274d8SLaszlo Ersek   Rsdp10 = NULL;
8709a274d8SLaszlo Ersek   Rsdp20 = NULL;
88*b097ba37SLaszlo Ersek   Smbios21 = NULL;
89*b097ba37SLaszlo Ersek   Smbios30 = NULL;
9009a274d8SLaszlo Ersek   ConfigTable = gST->ConfigurationTable;
9109a274d8SLaszlo Ersek   ConfigTablesEnd = gST->ConfigurationTable + gST->NumberOfTableEntries;
92*b097ba37SLaszlo Ersek   while ((Rsdp10 == NULL || Rsdp20 == NULL ||
93*b097ba37SLaszlo Ersek           Smbios21 == NULL || Smbios30 == NULL) &&
94*b097ba37SLaszlo Ersek          ConfigTable < ConfigTablesEnd) {
9509a274d8SLaszlo Ersek     if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi10TableGuid)) {
9609a274d8SLaszlo Ersek       Rsdp10 = ConfigTable->VendorTable;
9709a274d8SLaszlo Ersek     } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi20TableGuid)) {
9809a274d8SLaszlo Ersek       Rsdp20 = ConfigTable->VendorTable;
99*b097ba37SLaszlo Ersek     } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiSmbiosTableGuid)) {
100*b097ba37SLaszlo Ersek       Smbios21 = ConfigTable->VendorTable;
101*b097ba37SLaszlo Ersek     } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiSmbios3TableGuid)) {
102*b097ba37SLaszlo Ersek       Smbios30 = ConfigTable->VendorTable;
10309a274d8SLaszlo Ersek     }
10409a274d8SLaszlo Ersek     ++ConfigTable;
10509a274d8SLaszlo Ersek   }
10609a274d8SLaszlo Ersek 
10709a274d8SLaszlo Ersek   AsciiPrint ("%a: BiosTablesTest=%p Rsdp10=%p Rsdp20=%p\n",
10809a274d8SLaszlo Ersek     gEfiCallerBaseName, Pages, Rsdp10, Rsdp20);
109*b097ba37SLaszlo Ersek   AsciiPrint ("%a: Smbios21=%p Smbios30=%p\n", gEfiCallerBaseName, Smbios21,
110*b097ba37SLaszlo Ersek     Smbios30);
11109a274d8SLaszlo Ersek 
11209a274d8SLaszlo Ersek   //
113*b097ba37SLaszlo Ersek   // Store the config table addresses first, then the signature second.
11409a274d8SLaszlo Ersek   //
11509a274d8SLaszlo Ersek   BiosTablesTest = Pages;
11609a274d8SLaszlo Ersek   BiosTablesTest->Rsdp10 = (UINTN)Rsdp10;
11709a274d8SLaszlo Ersek   BiosTablesTest->Rsdp20 = (UINTN)Rsdp20;
118*b097ba37SLaszlo Ersek   BiosTablesTest->Smbios21 = (UINTN)Smbios21;
119*b097ba37SLaszlo Ersek   BiosTablesTest->Smbios30 = (UINTN)Smbios30;
12009a274d8SLaszlo Ersek 
12109a274d8SLaszlo Ersek   MemoryFence();
12209a274d8SLaszlo Ersek 
12309a274d8SLaszlo Ersek   InverseSignature = &BiosTablesTest->InverseSignatureGuid;
12409a274d8SLaszlo Ersek   InverseSignature->Data1  = gBiosTablesTestGuid.Data1;
12509a274d8SLaszlo Ersek   InverseSignature->Data1 ^= MAX_UINT32;
12609a274d8SLaszlo Ersek   InverseSignature->Data2  = gBiosTablesTestGuid.Data2;
12709a274d8SLaszlo Ersek   InverseSignature->Data2 ^= MAX_UINT16;
12809a274d8SLaszlo Ersek   InverseSignature->Data3  = gBiosTablesTestGuid.Data3;
12909a274d8SLaszlo Ersek   InverseSignature->Data3 ^= MAX_UINT16;
13009a274d8SLaszlo Ersek   for (Idx = 0; Idx < sizeof InverseSignature->Data4; ++Idx) {
13109a274d8SLaszlo Ersek     InverseSignature->Data4[Idx]  = gBiosTablesTestGuid.Data4[Idx];
13209a274d8SLaszlo Ersek     InverseSignature->Data4[Idx] ^= MAX_UINT8;
13309a274d8SLaszlo Ersek   }
13409a274d8SLaszlo Ersek 
13509a274d8SLaszlo Ersek   //
13609a274d8SLaszlo Ersek   // The wait below has dual purpose. First, it blocks the application without
13709a274d8SLaszlo Ersek   // wasting VCPU cycles while the hypervisor is scanning guest RAM. Second,
13809a274d8SLaszlo Ersek   // assuming the application was launched by the boot manager as a boot
13909a274d8SLaszlo Ersek   // loader, exiting the app with success causes the boot manager to pull up
14009a274d8SLaszlo Ersek   // the boot manager menu at once (regardless of other boot options); the wait
14109a274d8SLaszlo Ersek   // gives the user a chance to read the info printed above.
14209a274d8SLaszlo Ersek   //
14309a274d8SLaszlo Ersek   WaitForExitKeyPress ();
14409a274d8SLaszlo Ersek   return EFI_SUCCESS;
14509a274d8SLaszlo Ersek }
146