1 /** @file
2 *
3 *  Copyright (c) 2014-2015, ARM Limited. All rights reserved.
4 *
5 *  SPDX-License-Identifier: BSD-2-Clause-Patent
6 *
7 **/
8 
9 #include <Uefi.h>
10 
11 #include <Library/AcpiLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/UefiBootServicesTableLib.h>
14 
15 #include <Protocol/AcpiTable.h>
16 #include <Protocol/FirmwareVolume2.h>
17 
18 #include <IndustryStandard/Acpi.h>
19 
20 /**
21   Locate and Install the ACPI tables from the Firmware Volume if it verifies
22   the function condition.
23 
24   @param  AcpiFile                Guid of the ACPI file into the Firmware Volume
25   @param  CheckAcpiTableFunction  Function that checks if the ACPI table should be installed
26 
27   @return EFI_SUCCESS             The function completed successfully.
28   @return EFI_NOT_FOUND           The protocol could not be located.
29   @return EFI_OUT_OF_RESOURCES    There are not enough resources to find the protocol.
30 
31 **/
32 EFI_STATUS
LocateAndInstallAcpiFromFvConditional(IN CONST EFI_GUID * AcpiFile,IN EFI_LOCATE_ACPI_CHECK CheckAcpiTableFunction)33 LocateAndInstallAcpiFromFvConditional (
34   IN CONST EFI_GUID*        AcpiFile,
35   IN EFI_LOCATE_ACPI_CHECK  CheckAcpiTableFunction
36   )
37 {
38   EFI_STATUS                    Status;
39   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol;
40   EFI_HANDLE                    *HandleBuffer;
41   UINTN                         NumberOfHandles;
42   UINT32                        FvStatus;
43   UINTN                         Index;
44   EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
45   INTN                          SectionInstance;
46   UINTN                         SectionSize;
47   EFI_ACPI_COMMON_HEADER       *AcpiTable;
48   UINTN                         AcpiTableSize;
49   UINTN                         AcpiTableKey;
50   BOOLEAN                       Valid;
51 
52   // Ensure the ACPI Table is present
53   Status = gBS->LocateProtocol (
54                   &gEfiAcpiTableProtocolGuid,
55                   NULL,
56                   (VOID**)&AcpiProtocol
57                   );
58   if (EFI_ERROR (Status)) {
59     return Status;
60   }
61 
62   FvStatus        = 0;
63   SectionInstance = 0;
64 
65   // Locate all the Firmware Volume protocols.
66   Status = gBS->LocateHandleBuffer (
67                    ByProtocol,
68                    &gEfiFirmwareVolume2ProtocolGuid,
69                    NULL,
70                    &NumberOfHandles,
71                    &HandleBuffer
72                    );
73   if (EFI_ERROR (Status)) {
74     return Status;
75   }
76 
77   // Looking for FV with ACPI storage file
78   for (Index = 0; Index < NumberOfHandles; Index++) {
79     //
80     // Get the protocol on this handle
81     // This should not fail because of LocateHandleBuffer
82     //
83     Status = gBS->HandleProtocol (
84                      HandleBuffer[Index],
85                      &gEfiFirmwareVolume2ProtocolGuid,
86                      (VOID**) &FvInstance
87                      );
88     if (EFI_ERROR (Status)) {
89       goto FREE_HANDLE_BUFFER;
90     }
91 
92     while (Status == EFI_SUCCESS) {
93       // AcpiTable must be allocated by ReadSection (ie: AcpiTable == NULL)
94       AcpiTable = NULL;
95 
96       // See if it has the ACPI storage file
97       Status = FvInstance->ReadSection (
98                         FvInstance,
99                         AcpiFile,
100                         EFI_SECTION_RAW,
101                         SectionInstance,
102                         (VOID**) &AcpiTable,
103                         &SectionSize,
104                         &FvStatus
105                         );
106       if (!EFI_ERROR (Status)) {
107         AcpiTableKey = 0;
108         AcpiTableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Length;
109         ASSERT (SectionSize >= AcpiTableSize);
110 
111         DEBUG ((EFI_D_ERROR, "- Found '%c%c%c%c' ACPI Table\n",
112             (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature & 0xFF),
113             ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 8) & 0xFF),
114             ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 16) & 0xFF),
115             ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 24) & 0xFF)));
116 
117         // Is the ACPI table valid?
118         if (CheckAcpiTableFunction) {
119           Valid = CheckAcpiTableFunction ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable);
120         } else {
121           Valid = TRUE;
122         }
123 
124         // Install the ACPI Table
125         if (Valid) {
126           Status = AcpiProtocol->InstallAcpiTable (
127                                  AcpiProtocol,
128                                  AcpiTable,
129                                  AcpiTableSize,
130                                  &AcpiTableKey
131                                  );
132         }
133 
134         // Free memory allocated by ReadSection
135         gBS->FreePool (AcpiTable);
136 
137         if (EFI_ERROR (Status)) {
138           break;
139         }
140 
141         // Increment the section instance
142         SectionInstance++;
143       }
144     }
145   }
146 
147 FREE_HANDLE_BUFFER:
148   //
149   // Free any allocated buffers
150   //
151   gBS->FreePool (HandleBuffer);
152 
153   return EFI_SUCCESS;
154 }
155 
156 /**
157   Locate and Install the ACPI tables from the Firmware Volume
158 
159   @param  AcpiFile              Guid of the ACPI file into the Firmware Volume
160 
161   @return EFI_SUCCESS           The function completed successfully.
162   @return EFI_NOT_FOUND         The protocol could not be located.
163   @return EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.
164 
165 **/
166 EFI_STATUS
LocateAndInstallAcpiFromFv(IN CONST EFI_GUID * AcpiFile)167 LocateAndInstallAcpiFromFv (
168   IN CONST EFI_GUID* AcpiFile
169   )
170 {
171   return LocateAndInstallAcpiFromFvConditional (AcpiFile, NULL);
172 }
173