1 /** @file
2   Sample ACPI Platform Driver
3 
4   Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <PiDxe.h>
10 
11 #include <Protocol/AcpiTable.h>
12 #include <Protocol/FirmwareVolume2.h>
13 
14 #include <Library/BaseLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/PcdLib.h>
18 
19 #include <IndustryStandard/Acpi.h>
20 
21 /**
22   Locate the first instance of a protocol.  If the protocol requested is an
23   FV protocol, then it will return the first FV that contains the ACPI table
24   storage file.
25 
26   @param  Instance      Return pointer to the first instance of the protocol
27 
28   @return EFI_SUCCESS           The function completed successfully.
29   @return EFI_NOT_FOUND         The protocol could not be located.
30   @return EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.
31 
32 **/
33 EFI_STATUS
LocateFvInstanceWithTables(OUT EFI_FIRMWARE_VOLUME2_PROTOCOL ** Instance)34 LocateFvInstanceWithTables (
35   OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance
36   )
37 {
38   EFI_STATUS                    Status;
39   EFI_HANDLE                    *HandleBuffer;
40   UINTN                         NumberOfHandles;
41   EFI_FV_FILETYPE               FileType;
42   UINT32                        FvStatus;
43   EFI_FV_FILE_ATTRIBUTES        Attributes;
44   UINTN                         Size;
45   UINTN                         Index;
46   EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
47 
48   FvStatus = 0;
49 
50   //
51   // Locate protocol.
52   //
53   Status = gBS->LocateHandleBuffer (
54                    ByProtocol,
55                    &gEfiFirmwareVolume2ProtocolGuid,
56                    NULL,
57                    &NumberOfHandles,
58                    &HandleBuffer
59                    );
60   if (EFI_ERROR (Status)) {
61     //
62     // Defined errors at this time are not found and out of resources.
63     //
64     return Status;
65   }
66 
67 
68 
69   //
70   // Looking for FV with ACPI storage file
71   //
72 
73   for (Index = 0; Index < NumberOfHandles; Index++) {
74     //
75     // Get the protocol on this handle
76     // This should not fail because of LocateHandleBuffer
77     //
78     Status = gBS->HandleProtocol (
79                      HandleBuffer[Index],
80                      &gEfiFirmwareVolume2ProtocolGuid,
81                      (VOID**) &FvInstance
82                      );
83     ASSERT_EFI_ERROR (Status);
84 
85     //
86     // See if it has the ACPI storage file
87     //
88     Status = FvInstance->ReadFile (
89                            FvInstance,
90                            (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
91                            NULL,
92                            &Size,
93                            &FileType,
94                            &Attributes,
95                            &FvStatus
96                            );
97 
98     //
99     // If we found it, then we are done
100     //
101     if (Status == EFI_SUCCESS) {
102       *Instance = FvInstance;
103       break;
104     }
105   }
106 
107   //
108   // Our exit status is determined by the success of the previous operations
109   // If the protocol was found, Instance already points to it.
110   //
111 
112   //
113   // Free any allocated buffers
114   //
115   gBS->FreePool (HandleBuffer);
116 
117   return Status;
118 }
119 
120 
121 /**
122   This function calculates and updates an UINT8 checksum.
123 
124   @param  Buffer          Pointer to buffer to checksum
125   @param  Size            Number of bytes to checksum
126 
127 **/
128 VOID
AcpiPlatformChecksum(IN UINT8 * Buffer,IN UINTN Size)129 AcpiPlatformChecksum (
130   IN UINT8      *Buffer,
131   IN UINTN      Size
132   )
133 {
134   UINTN ChecksumOffset;
135 
136   ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
137 
138   //
139   // Set checksum to 0 first
140   //
141   Buffer[ChecksumOffset] = 0;
142 
143   //
144   // Update checksum value
145   //
146   Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size);
147 }
148 
149 
150 /**
151   Entrypoint of Acpi Platform driver.
152 
153   @param  ImageHandle
154   @param  SystemTable
155 
156   @return EFI_SUCCESS
157   @return EFI_LOAD_ERROR
158   @return EFI_OUT_OF_RESOURCES
159 
160 **/
161 EFI_STATUS
162 EFIAPI
AcpiPlatformEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)163 AcpiPlatformEntryPoint (
164   IN EFI_HANDLE         ImageHandle,
165   IN EFI_SYSTEM_TABLE   *SystemTable
166   )
167 {
168   EFI_STATUS                     Status;
169   EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
170   EFI_FIRMWARE_VOLUME2_PROTOCOL  *FwVol;
171   INTN                           Instance;
172   EFI_ACPI_COMMON_HEADER         *CurrentTable;
173   UINTN                          TableHandle;
174   UINT32                         FvStatus;
175   UINTN                          TableSize;
176   UINTN                          Size;
177 
178   Instance     = 0;
179   CurrentTable = NULL;
180   TableHandle  = 0;
181 
182   //
183   // Find the AcpiTable protocol
184   //
185   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable);
186   if (EFI_ERROR (Status)) {
187     return EFI_ABORTED;
188   }
189 
190   //
191   // Locate the firmware volume protocol
192   //
193   Status = LocateFvInstanceWithTables (&FwVol);
194   if (EFI_ERROR (Status)) {
195     return EFI_ABORTED;
196   }
197   //
198   // Read tables from the storage file.
199   //
200   while (Status == EFI_SUCCESS) {
201 
202     Status = FwVol->ReadSection (
203                       FwVol,
204                       (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
205                       EFI_SECTION_RAW,
206                       Instance,
207                       (VOID**) &CurrentTable,
208                       &Size,
209                       &FvStatus
210                       );
211     if (!EFI_ERROR(Status)) {
212       //
213       // Add the table
214       //
215       TableHandle = 0;
216 
217       TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
218       ASSERT (Size >= TableSize);
219 
220       //
221       // Checksum ACPI table
222       //
223       AcpiPlatformChecksum ((UINT8*)CurrentTable, TableSize);
224 
225       //
226       // Install ACPI table
227       //
228       Status = AcpiTable->InstallAcpiTable (
229                             AcpiTable,
230                             CurrentTable,
231                             TableSize,
232                             &TableHandle
233                             );
234 
235       //
236       // Free memory allocated by ReadSection
237       //
238       gBS->FreePool (CurrentTable);
239 
240       if (EFI_ERROR(Status)) {
241         return EFI_ABORTED;
242       }
243 
244       //
245       // Increment the instance
246       //
247       Instance++;
248       CurrentTable = NULL;
249     }
250   }
251 
252   //
253   // The driver does not require to be kept loaded.
254   //
255   return EFI_REQUEST_UNLOAD_IMAGE;
256 }
257 
258