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