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