1 /** @file
2   Populate the BIOS_TABLES_TEST structure.
3 
4   Copyright (C) 2019, Red Hat, Inc.
5 
6   This program and the accompanying materials are licensed and made available
7   under the terms and conditions of the BSD License that accompanies this
8   distribution. The full text of the license may be found at
9   <http://opensource.org/licenses/bsd-license.php>.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 **/
14 
15 #include <Guid/Acpi.h>
16 #include <Guid/BiosTablesTest.h>
17 #include <Guid/SmBios.h>
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 
24 /**
25   Wait for a keypress with a message that the application is about to exit.
26 **/
27 STATIC
28 VOID
29 WaitForExitKeyPress (
30   VOID
31   )
32 {
33   EFI_STATUS    Status;
34   UINTN         Idx;
35   EFI_INPUT_KEY Key;
36 
37   if (gST->ConIn == NULL) {
38     return;
39   }
40   AsciiPrint ("%a: press any key to exit\n", gEfiCallerBaseName);
41   Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Idx);
42   if (EFI_ERROR (Status)) {
43     return;
44   }
45   gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
46 }
47 
48 EFI_STATUS
49 EFIAPI
50 BiosTablesTestMain (
51   IN EFI_HANDLE       ImageHandle,
52   IN EFI_SYSTEM_TABLE *SystemTable
53   )
54 {
55   VOID                          *Pages;
56   volatile BIOS_TABLES_TEST     *BiosTablesTest;
57   CONST VOID                    *Rsdp10;
58   CONST VOID                    *Rsdp20;
59   CONST VOID                    *Smbios21;
60   CONST VOID                    *Smbios30;
61   CONST EFI_CONFIGURATION_TABLE *ConfigTable;
62   CONST EFI_CONFIGURATION_TABLE *ConfigTablesEnd;
63   volatile EFI_GUID             *InverseSignature;
64   UINTN                         Idx;
65 
66   Pages = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof *BiosTablesTest),
67             SIZE_1MB);
68   if (Pages == NULL) {
69     AsciiErrorPrint ("%a: AllocateAlignedPages() failed\n",
70       gEfiCallerBaseName);
71     //
72     // Assuming the application was launched by the boot manager as a boot
73     // loader, exiting with error will cause the boot manager to proceed with
74     // the remaining boot options. If there are no other boot options, the boot
75     // manager menu will be pulled up. Give the user a chance to read the error
76     // message.
77     //
78     WaitForExitKeyPress ();
79     return EFI_OUT_OF_RESOURCES;
80   }
81 
82   //
83   // Locate all the gEfiAcpi10TableGuid, gEfiAcpi20TableGuid,
84   // gEfiSmbiosTableGuid, gEfiSmbios3TableGuid config tables in one go.
85   //
86   Rsdp10 = NULL;
87   Rsdp20 = NULL;
88   Smbios21 = NULL;
89   Smbios30 = NULL;
90   ConfigTable = gST->ConfigurationTable;
91   ConfigTablesEnd = gST->ConfigurationTable + gST->NumberOfTableEntries;
92   while ((Rsdp10 == NULL || Rsdp20 == NULL ||
93           Smbios21 == NULL || Smbios30 == NULL) &&
94          ConfigTable < ConfigTablesEnd) {
95     if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi10TableGuid)) {
96       Rsdp10 = ConfigTable->VendorTable;
97     } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi20TableGuid)) {
98       Rsdp20 = ConfigTable->VendorTable;
99     } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiSmbiosTableGuid)) {
100       Smbios21 = ConfigTable->VendorTable;
101     } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiSmbios3TableGuid)) {
102       Smbios30 = ConfigTable->VendorTable;
103     }
104     ++ConfigTable;
105   }
106 
107   AsciiPrint ("%a: BiosTablesTest=%p Rsdp10=%p Rsdp20=%p\n",
108     gEfiCallerBaseName, Pages, Rsdp10, Rsdp20);
109   AsciiPrint ("%a: Smbios21=%p Smbios30=%p\n", gEfiCallerBaseName, Smbios21,
110     Smbios30);
111 
112   //
113   // Store the config table addresses first, then the signature second.
114   //
115   BiosTablesTest = Pages;
116   BiosTablesTest->Rsdp10 = (UINTN)Rsdp10;
117   BiosTablesTest->Rsdp20 = (UINTN)Rsdp20;
118   BiosTablesTest->Smbios21 = (UINTN)Smbios21;
119   BiosTablesTest->Smbios30 = (UINTN)Smbios30;
120 
121   MemoryFence();
122 
123   InverseSignature = &BiosTablesTest->InverseSignatureGuid;
124   InverseSignature->Data1  = gBiosTablesTestGuid.Data1;
125   InverseSignature->Data1 ^= MAX_UINT32;
126   InverseSignature->Data2  = gBiosTablesTestGuid.Data2;
127   InverseSignature->Data2 ^= MAX_UINT16;
128   InverseSignature->Data3  = gBiosTablesTestGuid.Data3;
129   InverseSignature->Data3 ^= MAX_UINT16;
130   for (Idx = 0; Idx < sizeof InverseSignature->Data4; ++Idx) {
131     InverseSignature->Data4[Idx]  = gBiosTablesTestGuid.Data4[Idx];
132     InverseSignature->Data4[Idx] ^= MAX_UINT8;
133   }
134 
135   //
136   // The wait below has dual purpose. First, it blocks the application without
137   // wasting VCPU cycles while the hypervisor is scanning guest RAM. Second,
138   // assuming the application was launched by the boot manager as a boot
139   // loader, exiting the app with success causes the boot manager to pull up
140   // the boot manager menu at once (regardless of other boot options); the wait
141   // gives the user a chance to read the info printed above.
142   //
143   WaitForExitKeyPress ();
144   return EFI_SUCCESS;
145 }
146