]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/AcpiLib/AcpiLib.c
EmbeddedPkg/AcpiLib: Add more helper functions
[mirror_edk2.git] / EmbeddedPkg / Library / AcpiLib / AcpiLib.c
CommitLineData
3356211b
OM
1/** @file\r
2*\r
da7dd714 3* Copyright (c) 2014-2015, ARM Limited. All rights reserved.\r
c63a10ec 4* Copyright (c) 2021, Ampere Computing LLC. All rights reserved.\r
3356211b 5*\r
878b807a 6* SPDX-License-Identifier: BSD-2-Clause-Patent\r
3356211b
OM
7*\r
8**/\r
9\r
10#include <Uefi.h>\r
11\r
12#include <Library/AcpiLib.h>\r
c63a10ec
NP
13#include <Library/BaseLib.h>\r
14#include <Library/BaseMemoryLib.h>\r
3356211b
OM
15#include <Library/DebugLib.h>\r
16#include <Library/UefiBootServicesTableLib.h>\r
17\r
c63a10ec 18#include <Protocol/AcpiSystemDescriptionTable.h>\r
3356211b
OM
19#include <Protocol/AcpiTable.h>\r
20#include <Protocol/FirmwareVolume2.h>\r
21\r
22#include <IndustryStandard/Acpi.h>\r
23\r
24/**\r
da7dd714
OM
25 Locate and Install the ACPI tables from the Firmware Volume if it verifies\r
26 the function condition.\r
3356211b 27\r
da7dd714
OM
28 @param AcpiFile Guid of the ACPI file into the Firmware Volume\r
29 @param CheckAcpiTableFunction Function that checks if the ACPI table should be installed\r
3356211b 30\r
da7dd714
OM
31 @return EFI_SUCCESS The function completed successfully.\r
32 @return EFI_NOT_FOUND The protocol could not be located.\r
33 @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.\r
3356211b
OM
34\r
35**/\r
36EFI_STATUS\r
da7dd714 37LocateAndInstallAcpiFromFvConditional (\r
e7108d0e 38 IN CONST EFI_GUID *AcpiFile,\r
da7dd714 39 IN EFI_LOCATE_ACPI_CHECK CheckAcpiTableFunction\r
3356211b
OM
40 )\r
41{\r
e7108d0e
MK
42 EFI_STATUS Status;\r
43 EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol;\r
44 EFI_HANDLE *HandleBuffer;\r
45 UINTN NumberOfHandles;\r
46 UINT32 FvStatus;\r
47 UINTN Index;\r
48 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;\r
49 INTN SectionInstance;\r
50 UINTN SectionSize;\r
51 EFI_ACPI_COMMON_HEADER *AcpiTable;\r
52 UINTN AcpiTableSize;\r
53 UINTN AcpiTableKey;\r
54 BOOLEAN Valid;\r
3356211b
OM
55\r
56 // Ensure the ACPI Table is present\r
57 Status = gBS->LocateProtocol (\r
58 &gEfiAcpiTableProtocolGuid,\r
59 NULL,\r
e7108d0e 60 (VOID **)&AcpiProtocol\r
3356211b
OM
61 );\r
62 if (EFI_ERROR (Status)) {\r
63 return Status;\r
64 }\r
65\r
66 FvStatus = 0;\r
67 SectionInstance = 0;\r
68\r
69 // Locate all the Firmware Volume protocols.\r
70 Status = gBS->LocateHandleBuffer (\r
e7108d0e
MK
71 ByProtocol,\r
72 &gEfiFirmwareVolume2ProtocolGuid,\r
73 NULL,\r
74 &NumberOfHandles,\r
75 &HandleBuffer\r
76 );\r
3356211b
OM
77 if (EFI_ERROR (Status)) {\r
78 return Status;\r
79 }\r
80\r
81 // Looking for FV with ACPI storage file\r
82 for (Index = 0; Index < NumberOfHandles; Index++) {\r
83 //\r
84 // Get the protocol on this handle\r
85 // This should not fail because of LocateHandleBuffer\r
86 //\r
87 Status = gBS->HandleProtocol (\r
e7108d0e
MK
88 HandleBuffer[Index],\r
89 &gEfiFirmwareVolume2ProtocolGuid,\r
90 (VOID **)&FvInstance\r
91 );\r
3356211b
OM
92 if (EFI_ERROR (Status)) {\r
93 goto FREE_HANDLE_BUFFER;\r
94 }\r
95\r
96 while (Status == EFI_SUCCESS) {\r
97 // AcpiTable must be allocated by ReadSection (ie: AcpiTable == NULL)\r
98 AcpiTable = NULL;\r
99\r
100 // See if it has the ACPI storage file\r
101 Status = FvInstance->ReadSection (\r
e7108d0e
MK
102 FvInstance,\r
103 AcpiFile,\r
104 EFI_SECTION_RAW,\r
105 SectionInstance,\r
106 (VOID **)&AcpiTable,\r
107 &SectionSize,\r
108 &FvStatus\r
109 );\r
3356211b 110 if (!EFI_ERROR (Status)) {\r
e7108d0e
MK
111 AcpiTableKey = 0;\r
112 AcpiTableSize = ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Length;\r
3356211b
OM
113 ASSERT (SectionSize >= AcpiTableSize);\r
114\r
e7108d0e
MK
115 DEBUG ((\r
116 DEBUG_ERROR,\r
117 "- Found '%c%c%c%c' ACPI Table\n",\r
118 (((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature & 0xFF),\r
119 ((((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature >> 8) & 0xFF),\r
120 ((((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature >> 16) & 0xFF),\r
121 ((((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature >> 24) & 0xFF)\r
122 ));\r
3356211b 123\r
da7dd714
OM
124 // Is the ACPI table valid?\r
125 if (CheckAcpiTableFunction) {\r
126 Valid = CheckAcpiTableFunction ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable);\r
127 } else {\r
128 Valid = TRUE;\r
129 }\r
130\r
3356211b 131 // Install the ACPI Table\r
da7dd714
OM
132 if (Valid) {\r
133 Status = AcpiProtocol->InstallAcpiTable (\r
e7108d0e
MK
134 AcpiProtocol,\r
135 AcpiTable,\r
136 AcpiTableSize,\r
137 &AcpiTableKey\r
138 );\r
da7dd714
OM
139 }\r
140\r
3356211b
OM
141 // Free memory allocated by ReadSection\r
142 gBS->FreePool (AcpiTable);\r
143\r
144 if (EFI_ERROR (Status)) {\r
145 break;\r
146 }\r
147\r
148 // Increment the section instance\r
149 SectionInstance++;\r
150 }\r
151 }\r
152 }\r
153\r
154FREE_HANDLE_BUFFER:\r
155 //\r
156 // Free any allocated buffers\r
157 //\r
158 gBS->FreePool (HandleBuffer);\r
159\r
160 return EFI_SUCCESS;\r
161}\r
da7dd714
OM
162\r
163/**\r
164 Locate and Install the ACPI tables from the Firmware Volume\r
165\r
166 @param AcpiFile Guid of the ACPI file into the Firmware Volume\r
167\r
168 @return EFI_SUCCESS The function completed successfully.\r
169 @return EFI_NOT_FOUND The protocol could not be located.\r
170 @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.\r
171\r
172**/\r
173EFI_STATUS\r
174LocateAndInstallAcpiFromFv (\r
e7108d0e 175 IN CONST EFI_GUID *AcpiFile\r
da7dd714
OM
176 )\r
177{\r
178 return LocateAndInstallAcpiFromFvConditional (AcpiFile, NULL);\r
179}\r
c63a10ec
NP
180\r
181/**\r
182 This function calculates and updates a UINT8 checksum\r
183 in an ACPI description table header.\r
184\r
185 @param Buffer Pointer to buffer to checksum\r
186 @param Size Number of bytes to checksum\r
187\r
188 @retval EFI_SUCCESS The function completed successfully.\r
189 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
190\r
191**/\r
192EFI_STATUS\r
193EFIAPI\r
194AcpiUpdateChecksum (\r
195 IN OUT UINT8 *Buffer,\r
196 IN UINTN Size\r
197 )\r
198{\r
199 UINTN ChecksumOffset;\r
200\r
201 if (Buffer == NULL || Size == 0) {\r
202 return EFI_INVALID_PARAMETER;\r
203 }\r
204\r
205 ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);\r
206\r
207 //\r
208 // Set checksum to 0 first\r
209 //\r
210 Buffer[ChecksumOffset] = 0;\r
211\r
212 //\r
213 // Update checksum value\r
214 //\r
215 Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);\r
216\r
217 return EFI_SUCCESS;\r
218}\r
219\r
220/**\r
221 This function uses the ACPI SDT protocol to search an ACPI table\r
222 with a given signature.\r
223\r
224 @param AcpiTableSdtProtocol Pointer to ACPI SDT protocol.\r
225 @param TableSignature ACPI table signature.\r
226 @param Index The zero-based index of the table where to search the table.\r
227 The index will be updated to the next instance if the table\r
228 is found with the matched TableSignature.\r
229 @param Table Pointer to the table.\r
230 @param TableKey Pointer to the table key.\r
231\r
232 @return EFI_SUCCESS The function completed successfully.\r
233 @return EFI_INVALID_PARAMETER At least one of parameters is invalid.\r
234 @retval EFI_NOT_FOUND The requested index is too large and a table was not found.\r
235\r
236**/\r
237EFI_STATUS\r
238EFIAPI\r
239AcpiLocateTableBySignature (\r
240 IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,\r
241 IN UINT32 TableSignature,\r
242 IN OUT UINTN *Index,\r
243 OUT EFI_ACPI_DESCRIPTION_HEADER **Table,\r
244 OUT UINTN *TableKey\r
245 )\r
246{\r
247 EFI_STATUS Status;\r
248 EFI_ACPI_SDT_HEADER *TempTable;\r
249 EFI_ACPI_TABLE_VERSION TableVersion;\r
250 UINTN TableIndex;\r
251\r
252 if (AcpiSdtProtocol == NULL\r
253 || Table == NULL\r
254 || TableKey == NULL) {\r
255 return EFI_INVALID_PARAMETER;\r
256 }\r
257\r
258 Status = EFI_SUCCESS;\r
259\r
260 //\r
261 // Search for ACPI Table with matching signature\r
262 //\r
263 TableVersion = 0;\r
264 TableIndex = *Index;\r
265 while (!EFI_ERROR (Status)) {\r
266 Status = AcpiSdtProtocol->GetAcpiTable (\r
267 TableIndex,\r
268 &TempTable,\r
269 &TableVersion,\r
270 TableKey\r
271 );\r
272 if (!EFI_ERROR (Status)) {\r
273 TableIndex++;\r
274\r
275 if (((EFI_ACPI_DESCRIPTION_HEADER *)TempTable)->Signature == TableSignature) {\r
276 *Table = (EFI_ACPI_DESCRIPTION_HEADER *)TempTable;\r
277 *Index = TableIndex;\r
278 break;\r
279 }\r
280 }\r
281 }\r
282\r
283 return Status;\r
284}\r
285\r
286/**\r
287 This function updates the integer value of an AML Object.\r
288\r
289 @param AcpiTableSdtProtocol Pointer to ACPI SDT protocol.\r
290 @param TableHandle Points to the table representing the starting point\r
291 for the object path search.\r
292 @param AsciiObjectPath Pointer to the ACPI path of the object being updated.\r
293 @param Value New value to write to the object.\r
294\r
295 @return EFI_SUCCESS The function completed successfully.\r
296 @return EFI_INVALID_PARAMETER At least one of parameters is invalid or the data type\r
297 of the ACPI object is not an integer value.\r
298 @retval EFI_NOT_FOUND The object is not found with the given path.\r
299\r
300**/\r
301EFI_STATUS\r
302EFIAPI\r
303AcpiAmlObjectUpdateInteger (\r
304 IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,\r
305 IN EFI_ACPI_HANDLE TableHandle,\r
306 IN CHAR8 *AsciiObjectPath,\r
307 IN UINTN Value\r
308 )\r
309{\r
310 EFI_STATUS Status;\r
311 EFI_ACPI_HANDLE ObjectHandle;\r
312 EFI_ACPI_HANDLE DataHandle;\r
313 EFI_ACPI_DATA_TYPE DataType;\r
314 UINT8 *Buffer;\r
315 UINTN BufferSize;\r
316 UINTN DataSize;\r
317\r
318 if (AcpiSdtProtocol == NULL || AsciiObjectPath == NULL) {\r
319 return EFI_INVALID_PARAMETER;\r
320 }\r
321\r
322 ObjectHandle = NULL;\r
323 DataHandle = NULL;\r
324\r
325 Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);\r
326 if (EFI_ERROR (Status)) {\r
327 return Status;\r
328 }\r
329\r
330 Status = AcpiSdtProtocol->GetOption (ObjectHandle, 0, &DataType, (VOID *)&Buffer, &BufferSize);\r
331 if (EFI_ERROR (Status)) {\r
332 Status = EFI_NOT_FOUND;\r
333 goto Exit;\r
334 }\r
335 ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);\r
336 ASSERT (Buffer != NULL);\r
337\r
338 if (Buffer[0] != AML_NAME_OP) {\r
339 Status = EFI_NOT_FOUND;\r
340 goto Exit;\r
341 }\r
342\r
343 //\r
344 // Get handle of data object\r
345 //\r
346 Status = AcpiSdtProtocol->GetChild (ObjectHandle, &DataHandle);\r
347 ASSERT_EFI_ERROR (Status);\r
348\r
349 Status = AcpiSdtProtocol->GetOption (DataHandle, 0, &DataType, (VOID *)&Buffer, &BufferSize);\r
350 ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);\r
351 ASSERT (Buffer != NULL);\r
352\r
353 if (Buffer[0] == AML_ZERO_OP || Buffer[0] == AML_ONE_OP) {\r
354 Status = AcpiSdtProtocol->SetOption (DataHandle, 0, (VOID *)&Value, sizeof (UINT8));\r
355 ASSERT_EFI_ERROR (Status);\r
356 } else {\r
357 //\r
358 // Check the size of data object\r
359 //\r
360 switch (Buffer[0]) {\r
361 case AML_BYTE_PREFIX:\r
362 DataSize = sizeof (UINT8);\r
363 break;\r
364\r
365 case AML_WORD_PREFIX:\r
366 DataSize = sizeof (UINT16);\r
367 break;\r
368\r
369 case AML_DWORD_PREFIX:\r
370 DataSize = sizeof (UINT32);\r
371 break;\r
372\r
373 case AML_QWORD_PREFIX:\r
374 DataSize = sizeof (UINT64);\r
375 break;\r
376\r
377 default:\r
378 // The data type of the ACPI object is not an integer\r
379 Status = EFI_INVALID_PARAMETER;\r
380 goto Exit;\r
381 }\r
382\r
383 Status = AcpiSdtProtocol->SetOption (DataHandle, 1, (VOID *)&Value, DataSize);\r
384 ASSERT_EFI_ERROR (Status);\r
385 }\r
386\r
387Exit:\r
388 AcpiSdtProtocol->Close (DataHandle);\r
389 AcpiSdtProtocol->Close (ObjectHandle);\r
390\r
391 return Status;\r
392}\r