]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
MdeModulePkg AcpiTableDxe: Don't uninstall Acpi Sdt Protocol at ReadyToLock
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / AcpiTableDxe / AcpiSdt.c
CommitLineData
3dc8585e
JY
1/** @file\r
2 ACPI Sdt Protocol Driver\r
3\r
f53a3134 4 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved. <BR>\r
3dc8585e
JY
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15//\r
16// Includes\r
17//\r
18#include "AcpiTable.h"\r
19\r
20GLOBAL_REMOVE_IF_UNREFERENCED\r
21EFI_ACPI_SDT_PROTOCOL mAcpiSdtProtocolTemplate = {\r
f9bbb8d9 22 EFI_ACPI_TABLE_VERSION_NONE,\r
3dc8585e
JY
23 GetAcpiTable2,\r
24 RegisterNotify,\r
25 Open,\r
26 OpenSdt,\r
27 Close,\r
28 GetChild,\r
29 GetOption,\r
30 SetOption,\r
31 FindPath\r
32};\r
33\r
34/**\r
35 This function returns ACPI Table instance.\r
36\r
37 @return AcpiTableInstance\r
38**/\r
39EFI_ACPI_TABLE_INSTANCE *\r
40SdtGetAcpiTableInstance (\r
41 VOID\r
42 )\r
43{\r
44 return mPrivateData;\r
45}\r
46\r
47/**\r
48 This function finds the table specified by the buffer.\r
49\r
50 @param[in] Buffer Table buffer to find.\r
51\r
52 @return ACPI table list.\r
53**/\r
54EFI_ACPI_TABLE_LIST *\r
55FindTableByBuffer (\r
56 IN VOID *Buffer\r
57 )\r
58{\r
59 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;\r
60 LIST_ENTRY *CurrentLink;\r
61 EFI_ACPI_TABLE_LIST *CurrentTableList;\r
62 LIST_ENTRY *StartLink;\r
63\r
64 //\r
65 // Get the instance of the ACPI Table\r
66 //\r
67 AcpiTableInstance = SdtGetAcpiTableInstance ();\r
68\r
69 //\r
70 // Find the notify\r
71 //\r
72 StartLink = &AcpiTableInstance->TableList;\r
73 CurrentLink = StartLink->ForwardLink;\r
74\r
75 while (CurrentLink != StartLink) {\r
76 CurrentTableList = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);\r
77 if (((UINTN)CurrentTableList->PageAddress <= (UINTN)Buffer) &&\r
78 ((UINTN)CurrentTableList->PageAddress + EFI_PAGES_TO_SIZE(CurrentTableList->NumberOfPages) > (UINTN)Buffer)) {\r
79 //\r
80 // Good! Found Table.\r
81 //\r
82 return CurrentTableList;\r
83 }\r
84\r
85 CurrentLink = CurrentLink->ForwardLink;\r
86 }\r
87\r
88 return NULL;\r
89}\r
90\r
91/**\r
92 This function updates AML table checksum.\r
93 It will search the ACPI table installed by ACPI_TABLE protocol.\r
94\r
95 @param[in] Buffer A piece of AML code buffer pointer.\r
96\r
97 @retval EFI_SUCCESS The table holds the AML buffer is found, and checksum is updated.\r
98 @retval EFI_NOT_FOUND The table holds the AML buffer is not found.\r
99**/\r
100EFI_STATUS\r
101SdtUpdateAmlChecksum (\r
102 IN VOID *Buffer\r
103 )\r
104{\r
105 EFI_ACPI_TABLE_LIST *CurrentTableList;\r
106\r
107 CurrentTableList = FindTableByBuffer (Buffer);\r
108 if (CurrentTableList == NULL) {\r
109 return EFI_NOT_FOUND;\r
110 }\r
111\r
112 AcpiPlatformChecksum (\r
113 (VOID *)CurrentTableList->Table,\r
114 CurrentTableList->Table->Length,\r
115 OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum)\r
116 );\r
117 return EFI_SUCCESS;\r
118}\r
119\r
120/**\r
121 This function finds MAX AML buffer size.\r
122 It will search the ACPI table installed by ACPI_TABLE protocol.\r
123\r
124 @param[in] Buffer A piece of AML code buffer pointer.\r
125 @param[out] MaxSize On return it holds the MAX size of buffer.\r
126\r
127 @retval EFI_SUCCESS The table holds the AML buffer is found, and MAX size if returned.\r
128 @retval EFI_NOT_FOUND The table holds the AML buffer is not found.\r
129**/\r
130EFI_STATUS\r
131SdtGetMaxAmlBufferSize (\r
132 IN VOID *Buffer,\r
133 OUT UINTN *MaxSize\r
134 )\r
135{\r
136 EFI_ACPI_TABLE_LIST *CurrentTableList;\r
137\r
138 CurrentTableList = FindTableByBuffer (Buffer);\r
139 if (CurrentTableList == NULL) {\r
140 return EFI_NOT_FOUND;\r
141 }\r
142\r
143 *MaxSize = (UINTN)CurrentTableList->Table + CurrentTableList->Table->Length - (UINTN)Buffer;\r
144 return EFI_SUCCESS;\r
145}\r
146\r
147/**\r
148 This function invokes ACPI notification.\r
149\r
150 @param[in] AcpiTableInstance Instance to AcpiTable\r
151 @param[in] Version Version(s) to set.\r
152 @param[in] Handle Handle of the table.\r
153**/\r
154VOID\r
155SdtNotifyAcpiList (\r
156 IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,\r
157 IN EFI_ACPI_TABLE_VERSION Version,\r
158 IN UINTN Handle\r
159 )\r
160{\r
161 EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;\r
162 LIST_ENTRY *CurrentLink;\r
163 LIST_ENTRY *StartLink;\r
164 EFI_ACPI_TABLE_LIST *Table;\r
165 EFI_STATUS Status;\r
166\r
167 //\r
168 // We should not use Table buffer, because it is user input buffer.\r
169 //\r
170 Status = FindTableByHandle (\r
171 Handle,\r
172 &AcpiTableInstance->TableList,\r
173 &Table\r
174 );\r
175 ASSERT_EFI_ERROR (Status);\r
176\r
177 //\r
178 // Find the notify\r
179 //\r
180 StartLink = &AcpiTableInstance->NotifyList;\r
181 CurrentLink = StartLink->ForwardLink;\r
182\r
183 while (CurrentLink != StartLink) {\r
184 CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);\r
185\r
186 //\r
187 // Inovke notification\r
188 //\r
189 CurrentNotifyList->Notification ((EFI_ACPI_SDT_HEADER *)Table->Table, Version, Handle);\r
190\r
191 CurrentLink = CurrentLink->ForwardLink;\r
192 }\r
193\r
194 return ;\r
195}\r
196\r
197/**\r
198 Returns a requested ACPI table.\r
199 \r
200 The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated\r
201 with the Index that was input. The following structures are not considered elements in the list of\r
202 ACPI tables:\r
203 - Root System Description Pointer (RSD_PTR)\r
204 - Root System Description Table (RSDT)\r
205 - Extended System Description Table (XSDT)\r
206 Version is updated with a bit map containing all the versions of ACPI of which the table is a\r
f0071740
SZ
207 member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,\r
208 the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.\r
3dc8585e
JY
209 \r
210 @param[in] Index The zero-based index of the table to retrieve.\r
211 @param[out] Table Pointer for returning the table buffer.\r
212 @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type\r
213 EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the\r
214 EFI_ACPI_SDT_PROTOCOL. \r
f0071740
SZ
215 @param[out] TableKey On return, points to the table key for the specified ACPI system definition table.\r
216 This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL.\r
217 The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()\r
218 to uninstall the table.\r
3dc8585e
JY
219 @retval EFI_SUCCESS The function completed successfully.\r
220 @retval EFI_NOT_FOUND The requested index is too large and a table was not found. \r
221**/ \r
222EFI_STATUS\r
223EFIAPI\r
224GetAcpiTable2 (\r
225 IN UINTN Index,\r
226 OUT EFI_ACPI_SDT_HEADER **Table,\r
227 OUT EFI_ACPI_TABLE_VERSION *Version,\r
228 OUT UINTN *TableKey\r
229 )\r
230{\r
231 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;\r
232 UINTN TableIndex;\r
233 LIST_ENTRY *CurrentLink;\r
234 LIST_ENTRY *StartLink;\r
235 EFI_ACPI_TABLE_LIST *CurrentTable;\r
236\r
237 ASSERT (Table != NULL);\r
238 ASSERT (Version != NULL);\r
239 ASSERT (TableKey != NULL);\r
240\r
241 //\r
242 // Get the instance of the ACPI Table\r
243 //\r
244 AcpiTableInstance = SdtGetAcpiTableInstance ();\r
245\r
246 //\r
247 // Find the table\r
248 //\r
249 StartLink = &AcpiTableInstance->TableList;\r
250 CurrentLink = StartLink->ForwardLink;\r
251 TableIndex = 0;\r
252\r
253 while (CurrentLink != StartLink) {\r
254 if (TableIndex == Index) {\r
255 break;\r
256 }\r
257 //\r
258 // Next one\r
259 //\r
260 CurrentLink = CurrentLink->ForwardLink;\r
261 TableIndex ++;\r
262 }\r
263\r
264 if ((TableIndex != Index) || (CurrentLink == StartLink)) {\r
265 return EFI_NOT_FOUND;\r
266 }\r
267\r
268 //\r
269 // Get handle and version\r
270 //\r
271 CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);\r
272 *TableKey = CurrentTable->Handle;\r
273 *Version = CurrentTable->Version;\r
274 *Table = (EFI_ACPI_SDT_HEADER *)CurrentTable->Table;\r
275\r
276 return EFI_SUCCESS;\r
277}\r
278\r
279/**\r
280 Register a callback when an ACPI table is installed.\r
281 \r
282 This function registers a function which will be called whenever a new ACPI table is installed.\r
283 \r
284 @param[in] Notification Points to the callback function to be registered\r
285**/\r
286VOID\r
287SdtRegisterNotify (\r
288 IN EFI_ACPI_NOTIFICATION_FN Notification\r
289 )\r
290{\r
291 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;\r
292 EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;\r
293\r
294 //\r
295 // Get the instance of the ACPI Table\r
296 //\r
297 AcpiTableInstance = SdtGetAcpiTableInstance ();\r
298\r
299 //\r
300 // Create a new list entry\r
301 //\r
302 CurrentNotifyList = AllocatePool (sizeof (EFI_ACPI_NOTIFY_LIST));\r
303 ASSERT (CurrentNotifyList != NULL);\r
304\r
305 //\r
306 // Initialize the table contents\r
307 //\r
308 CurrentNotifyList->Signature = EFI_ACPI_NOTIFY_LIST_SIGNATURE;\r
309 CurrentNotifyList->Notification = Notification;\r
310\r
311 //\r
312 // Add the table to the current list of tables\r
313 //\r
314 InsertTailList (&AcpiTableInstance->NotifyList, &CurrentNotifyList->Link);\r
315\r
316 return ;\r
317}\r
318\r
319/**\r
320 Unregister a callback when an ACPI table is installed.\r
321 \r
322 This function unregisters a function which will be called whenever a new ACPI table is installed.\r
323 \r
324 @param[in] Notification Points to the callback function to be unregistered.\r
325 \r
326 @retval EFI_SUCCESS Callback successfully unregistered.\r
327 @retval EFI_INVALID_PARAMETER Notification does not match a known registration function. \r
328**/\r
329EFI_STATUS\r
330SdtUnregisterNotify (\r
331 IN EFI_ACPI_NOTIFICATION_FN Notification\r
332 )\r
333{\r
334 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;\r
335 EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;\r
336 LIST_ENTRY *CurrentLink;\r
337 LIST_ENTRY *StartLink;\r
338\r
339 //\r
340 // Get the instance of the ACPI Table\r
341 //\r
342 AcpiTableInstance = SdtGetAcpiTableInstance ();\r
343\r
344 //\r
345 // Find the notify\r
346 //\r
347 StartLink = &AcpiTableInstance->NotifyList;\r
348 CurrentLink = StartLink->ForwardLink;\r
349\r
350 while (CurrentLink != StartLink) {\r
351 CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);\r
352 if (CurrentNotifyList->Notification == Notification) {\r
353 //\r
354 // Good! Found notification.\r
355 //\r
356 // Remove it from list and free the node.\r
357 //\r
358 RemoveEntryList (&(CurrentNotifyList->Link));\r
359 FreePool (CurrentNotifyList);\r
360 return EFI_SUCCESS;\r
361 }\r
362\r
363 CurrentLink = CurrentLink->ForwardLink;\r
364 }\r
365\r
366 //\r
367 // Not found!\r
368 //\r
369 return EFI_INVALID_PARAMETER;\r
370}\r
371\r
372/**\r
373 Register or unregister a callback when an ACPI table is installed.\r
374 \r
375 This function registers or unregisters a function which will be called whenever a new ACPI table is\r
376 installed.\r
377 \r
378 @param[in] Register If TRUE, then the specified function will be registered. If FALSE, then the specified\r
379 function will be unregistered.\r
380 @param[in] Notification Points to the callback function to be registered or unregistered.\r
381 \r
382 @retval EFI_SUCCESS Callback successfully registered or unregistered.\r
383 @retval EFI_INVALID_PARAMETER Notification is NULL\r
384 @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function. \r
385**/\r
386EFI_STATUS\r
387EFIAPI\r
388RegisterNotify (\r
389 IN BOOLEAN Register,\r
390 IN EFI_ACPI_NOTIFICATION_FN Notification\r
391 )\r
392{\r
393 //\r
394 // Check for invalid input parameters\r
395 //\r
396 if (Notification == NULL) {\r
397 return EFI_INVALID_PARAMETER;\r
398 }\r
399\r
400 if (Register) {\r
401 //\r
402 // Register a new notify\r
403 //\r
404 SdtRegisterNotify (Notification);\r
405 return EFI_SUCCESS;\r
406 } else {\r
407 //\r
408 // Unregister an old notify\r
409 //\r
410 return SdtUnregisterNotify (Notification);\r
411 }\r
412}\r
413\r
414/**\r
415 Create a handle for the first ACPI opcode in an ACPI system description table.\r
416 \r
417 @param[in] TableKey The table key for the ACPI table, as returned by GetTable().\r
418 @param[out] Handle On return, points to the newly created ACPI handle.\r
419\r
420 @retval EFI_SUCCESS Handle created successfully.\r
421 @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table. \r
422**/\r
423EFI_STATUS\r
424SdtOpenSdtTable (\r
425 IN UINTN TableKey,\r
426 OUT EFI_ACPI_HANDLE *Handle\r
427 )\r
428{\r
429 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;\r
430 EFI_STATUS Status;\r
431 EFI_ACPI_TABLE_LIST *Table;\r
432 EFI_AML_HANDLE *AmlHandle;\r
433\r
434 //\r
435 // Get the instance of the ACPI Table\r
436 //\r
437 AcpiTableInstance = SdtGetAcpiTableInstance ();\r
438\r
439 //\r
440 // Find the table\r
441 //\r
442 Status = FindTableByHandle (\r
443 TableKey,\r
444 &AcpiTableInstance->TableList,\r
445 &Table\r
446 );\r
447 if (EFI_ERROR (Status)) {\r
448 return EFI_NOT_FOUND;\r
449 }\r
450\r
451 AmlHandle = AllocatePool (sizeof(*AmlHandle));\r
452 ASSERT (AmlHandle != NULL);\r
453 AmlHandle->Signature = EFI_AML_ROOT_HANDLE_SIGNATURE;\r
454 AmlHandle->Buffer = (VOID *)((UINTN)Table->Table + sizeof(EFI_ACPI_SDT_HEADER));\r
455 AmlHandle->Size = Table->Table->Length - sizeof(EFI_ACPI_SDT_HEADER);\r
456 AmlHandle->AmlByteEncoding = NULL;\r
457 AmlHandle->Modified = FALSE;\r
458\r
459 //\r
460 // return the ACPI handle\r
461 //\r
462 *Handle = (EFI_ACPI_HANDLE)AmlHandle;\r
463\r
464 return EFI_SUCCESS;\r
465}\r
466\r
467/**\r
468 Create a handle for the first ACPI opcode in an ACPI system description table.\r
469 \r
470 @param[in] TableKey The table key for the ACPI table, as returned by GetTable().\r
471 @param[out] Handle On return, points to the newly created ACPI handle.\r
472\r
473 @retval EFI_SUCCESS Handle created successfully.\r
474 @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table. \r
475**/\r
476EFI_STATUS\r
477EFIAPI\r
478OpenSdt (\r
479 IN UINTN TableKey,\r
480 OUT EFI_ACPI_HANDLE *Handle\r
481 )\r
482{\r
483 if (Handle == NULL) {\r
484 return EFI_INVALID_PARAMETER;\r
485 }\r
486\r
487 return SdtOpenSdtTable (TableKey, Handle);\r
488}\r
489\r
490/**\r
491 Create a handle from an ACPI opcode\r
492 \r
493 @param[in] Buffer Points to the ACPI opcode.\r
494 @param[in] BufferSize Max buffer size.\r
495 @param[out] Handle Upon return, holds the handle.\r
496 \r
497 @retval EFI_SUCCESS Success\r
498 @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an\r
499 invalid opcode.\r
500 \r
501**/\r
502EFI_STATUS\r
503SdtOpenEx (\r
504 IN VOID *Buffer,\r
505 IN UINTN BufferSize,\r
506 OUT EFI_ACPI_HANDLE *Handle \r
507 )\r
508{\r
509 AML_BYTE_ENCODING *AmlByteEncoding;\r
510 EFI_AML_HANDLE *AmlHandle;\r
511\r
512 AmlByteEncoding = AmlSearchByOpByte (Buffer);\r
513 if (AmlByteEncoding == NULL) {\r
514 return EFI_INVALID_PARAMETER;\r
515 }\r
516\r
517 //\r
518 // Do not open NameString as handle\r
519 //\r
520 if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {\r
521 return EFI_INVALID_PARAMETER;\r
522 }\r
523\r
524 //\r
525 // Good, find it\r
526 //\r
527 AmlHandle = AllocatePool (sizeof(*AmlHandle));\r
528 ASSERT (AmlHandle != NULL);\r
529 \r
530 AmlHandle->Signature = EFI_AML_HANDLE_SIGNATURE;\r
531 AmlHandle->Buffer = Buffer;\r
532 AmlHandle->AmlByteEncoding = AmlByteEncoding;\r
533 AmlHandle->Modified = FALSE;\r
534\r
535 AmlHandle->Size = AmlGetObjectSize (AmlByteEncoding, Buffer, BufferSize);\r
536 if (AmlHandle->Size == 0) {\r
537 FreePool (AmlHandle);\r
538 return EFI_INVALID_PARAMETER;\r
539 }\r
540\r
541 *Handle = (EFI_ACPI_HANDLE)AmlHandle;\r
542\r
543 return EFI_SUCCESS;\r
544}\r
545\r
546/**\r
547 Create a handle from an ACPI opcode\r
548 \r
549 @param[in] Buffer Points to the ACPI opcode.\r
550 @param[out] Handle Upon return, holds the handle.\r
551 \r
552 @retval EFI_SUCCESS Success\r
553 @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an\r
554 invalid opcode.\r
555 \r
556**/\r
557EFI_STATUS\r
558EFIAPI\r
559Open (\r
560 IN VOID *Buffer,\r
561 OUT EFI_ACPI_HANDLE *Handle \r
562 )\r
563{\r
564 EFI_STATUS Status;\r
565 UINTN MaxSize;\r
566\r
a6bb62e4 567 MaxSize = 0;\r
568\r
3dc8585e
JY
569 //\r
570 // Check for invalid input parameters\r
571 //\r
572 if (Buffer == NULL || Handle == NULL) {\r
573 return EFI_INVALID_PARAMETER;\r
574 }\r
575\r
576 Status = SdtGetMaxAmlBufferSize (Buffer, &MaxSize);\r
577 if (EFI_ERROR (Status)) {\r
578 return EFI_INVALID_PARAMETER;\r
579 }\r
580\r
581 return SdtOpenEx (Buffer, MaxSize, Handle);\r
582}\r
583\r
584/**\r
585 Close an ACPI handle.\r
586 \r
587 @param[in] Handle Returns the handle.\r
588 \r
589 @retval EFI_SUCCESS Success\r
590 @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object. \r
591**/\r
592EFI_STATUS\r
593EFIAPI\r
594Close (\r
595 IN EFI_ACPI_HANDLE Handle\r
596 )\r
597{\r
598 EFI_AML_HANDLE *AmlHandle;\r
599 EFI_STATUS Status;\r
600\r
601 //\r
602 // Check for invalid input parameters\r
603 //\r
604 if (Handle == NULL) {\r
605 return EFI_INVALID_PARAMETER;\r
606 }\r
607\r
608 AmlHandle = (EFI_AML_HANDLE *)Handle;\r
609 if ((AmlHandle->Signature != EFI_AML_ROOT_HANDLE_SIGNATURE) &&\r
610 (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {\r
611 return EFI_INVALID_PARAMETER;\r
612 }\r
613\r
614 //\r
615 // Update Checksum only if modified\r
616 //\r
617 if (AmlHandle->Modified) {\r
618 Status = SdtUpdateAmlChecksum (AmlHandle->Buffer);\r
619 if (EFI_ERROR (Status)) {\r
620 return EFI_INVALID_PARAMETER;\r
621 }\r
622 }\r
623\r
624 FreePool (AmlHandle);\r
625\r
626 return EFI_SUCCESS;\r
627}\r
628\r
629/**\r
630 Retrieve information about an ACPI object.\r
631 \r
632 @param[in] Handle ACPI object handle.\r
633 @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right\r
634 in the ACPI encoding, with index 0 always being the ACPI opcode.\r
635 @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists\r
636 for the specified index.\r
637 @param[out] Data Upon return, points to the pointer to the data.\r
638 @param[out] DataSize Upon return, points to the size of Data.\r
639 \r
640 @retval EFI_SUCCESS Success.\r
641 @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.\r
642**/\r
643EFI_STATUS\r
644EFIAPI\r
645GetOption (\r
646 IN EFI_ACPI_HANDLE Handle,\r
647 IN UINTN Index,\r
648 OUT EFI_ACPI_DATA_TYPE *DataType,\r
649 OUT CONST VOID **Data,\r
650 OUT UINTN *DataSize\r
651 )\r
652{\r
653 EFI_AML_HANDLE *AmlHandle;\r
654 AML_BYTE_ENCODING *AmlByteEncoding;\r
655 EFI_STATUS Status;\r
656\r
657 ASSERT (DataType != NULL);\r
658 ASSERT (Data != NULL);\r
659 ASSERT (DataSize != NULL);\r
660\r
661 //\r
662 // Check for invalid input parameters\r
663 //\r
664 if (Handle == NULL) {\r
665 return EFI_INVALID_PARAMETER;\r
666 }\r
667\r
668 AmlHandle = (EFI_AML_HANDLE *)Handle;\r
669 //\r
670 // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle\r
671 //\r
672 if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {\r
673 return EFI_INVALID_PARAMETER;\r
674 }\r
675\r
676 AmlByteEncoding = AmlHandle->AmlByteEncoding;\r
677 if (Index > AmlByteEncoding->MaxIndex) {\r
678 *DataType = EFI_ACPI_DATA_TYPE_NONE;\r
679 return EFI_SUCCESS;\r
680 }\r
681\r
682 //\r
683 // Parse option\r
684 //\r
685 Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, DataType, (VOID **)Data, DataSize);\r
686 if (EFI_ERROR (Status)) {\r
687 return EFI_INVALID_PARAMETER;\r
688 }\r
689\r
690 return EFI_SUCCESS;\r
691}\r
692\r
693/**\r
694 Change information about an ACPI object.\r
695 \r
696 @param[in] Handle ACPI object handle.\r
697 @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right\r
698 in the ACPI encoding, with index 0 always being the ACPI opcode.\r
699 @param[in] Data Points to the data.\r
700 @param[in] DataSize The size of the Data.\r
701\r
702 @retval EFI_SUCCESS Success\r
703 @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.\r
704 @retval EFI_BAD_BUFFER_SIZE Data cannot be accommodated in the space occupied by\r
705 the option.\r
706\r
707**/\r
708EFI_STATUS\r
709EFIAPI\r
710SetOption (\r
711 IN EFI_ACPI_HANDLE Handle,\r
712 IN UINTN Index,\r
713 IN CONST VOID *Data,\r
714 IN UINTN DataSize\r
715 )\r
716{\r
717 EFI_AML_HANDLE *AmlHandle;\r
718 AML_BYTE_ENCODING *AmlByteEncoding;\r
719 EFI_STATUS Status;\r
720 EFI_ACPI_DATA_TYPE DataType;\r
721 VOID *OrgData;\r
722 UINTN OrgDataSize;\r
723\r
724 ASSERT (Data != NULL);\r
725\r
726 //\r
727 // Check for invalid input parameters\r
728 //\r
729 if (Handle == NULL) {\r
730 return EFI_INVALID_PARAMETER;\r
731 }\r
732\r
733 AmlHandle = (EFI_AML_HANDLE *)Handle;\r
734 //\r
735 // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle\r
736 //\r
737 if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {\r
738 return EFI_INVALID_PARAMETER;\r
739 }\r
740 AmlByteEncoding = AmlHandle->AmlByteEncoding;\r
741\r
742 if (Index > AmlByteEncoding->MaxIndex) {\r
743 return EFI_INVALID_PARAMETER;\r
744 }\r
745\r
746 //\r
747 // Parse option\r
748 //\r
749 Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, &DataType, &OrgData, &OrgDataSize);\r
750 if (EFI_ERROR (Status)) {\r
751 return EFI_INVALID_PARAMETER;\r
752 }\r
753 if (DataType == EFI_ACPI_DATA_TYPE_NONE) {\r
754 return EFI_INVALID_PARAMETER;\r
755 }\r
756\r
757 if (DataSize > OrgDataSize) {\r
758 return EFI_BAD_BUFFER_SIZE;\r
759 }\r
760\r
761 //\r
762 // Update\r
763 //\r
764 CopyMem (OrgData, Data, DataSize);\r
765 AmlHandle->Modified = TRUE;\r
766\r
767 return EFI_SUCCESS;\r
768}\r
769\r
770/**\r
771 Return the child ACPI objects.\r
772 \r
773 @param[in] ParentHandle Parent handle.\r
774 @param[in, out] Handle On entry, points to the previously returned handle or NULL to start with the first\r
775 handle. On return, points to the next returned ACPI handle or NULL if there are no\r
776 child objects.\r
777\r
778 @retval EFI_SUCCESS Success\r
779 @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object. \r
780**/\r
781EFI_STATUS\r
782EFIAPI\r
783GetChild (\r
784 IN EFI_ACPI_HANDLE ParentHandle,\r
785 IN OUT EFI_ACPI_HANDLE *Handle\r
786 )\r
787{\r
788 EFI_AML_HANDLE *AmlParentHandle;\r
789 EFI_AML_HANDLE *AmlHandle;\r
790 VOID *Buffer;\r
791 EFI_STATUS Status;\r
792\r
793 ASSERT (Handle != NULL);\r
794\r
795 //\r
796 // Check for invalid input parameters\r
797 //\r
798 if (ParentHandle == NULL) {\r
799 return EFI_INVALID_PARAMETER;\r
800 }\r
801\r
802 AmlHandle = *Handle;\r
803 if ((AmlHandle != NULL) && (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {\r
804 return EFI_INVALID_PARAMETER;\r
805 }\r
806\r
807 AmlParentHandle = (EFI_AML_HANDLE *)ParentHandle;\r
808 if (AmlParentHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {\r
809 //\r
810 // Root handle\r
811 //\r
812 Status = AmlGetChildFromRoot (AmlParentHandle, AmlHandle, &Buffer);\r
813 } else if (AmlParentHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {\r
814 //\r
815 // Non-root handle\r
816 //\r
817 Status = AmlGetChildFromNonRoot (AmlParentHandle, AmlHandle, &Buffer);\r
818 } else {\r
819 //\r
820 // Invalid\r
821 //\r
822 return EFI_INVALID_PARAMETER;\r
823 }\r
824\r
825 if (EFI_ERROR (Status)) {\r
826 return EFI_INVALID_PARAMETER;\r
827 }\r
828 if (Buffer == NULL) {\r
829 *Handle = NULL;\r
830 return EFI_SUCCESS;\r
831 }\r
832 return SdtOpenEx (Buffer, (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)Buffer, Handle);\r
833}\r
834\r
835/**\r
836 Returns the handle of the ACPI object representing the specified ACPI path\r
837 \r
838 @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.\r
839 @param[in] AmlPath Points to the AML path.\r
840 @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to\r
841 HandleIn.\r
842 \r
843 @retval EFI_SUCCESS Success\r
844 @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. \r
845**/\r
846EFI_STATUS\r
847SdtFindPathFromNonRoot (\r
848 IN EFI_ACPI_HANDLE HandleIn,\r
849 IN UINT8 *AmlPath,\r
850 OUT EFI_ACPI_HANDLE *HandleOut\r
851 )\r
852{\r
853 EFI_AML_HANDLE *AmlHandle;\r
854 VOID *Buffer;\r
855 EFI_STATUS Status;\r
856\r
4e1005ec 857 Buffer = NULL;\r
3dc8585e
JY
858 AmlHandle = (EFI_AML_HANDLE *)HandleIn;\r
859\r
860 //\r
861 // For non-root handle, we need search from THIS node instead of ROOT.\r
862 //\r
863 Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, FALSE);\r
864 if (EFI_ERROR (Status)) {\r
865 return EFI_INVALID_PARAMETER;\r
866 }\r
867 if (Buffer == NULL) {\r
868 *HandleOut = NULL;\r
869 return EFI_SUCCESS;\r
870 }\r
871 return SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);\r
872}\r
873\r
874/**\r
875 Duplicate AML handle.\r
876 \r
877 @param[in] AmlHandle Handle to be duplicated.\r
878 \r
879 @return Duplicated AML handle.\r
880**/\r
881EFI_AML_HANDLE *\r
882SdtDuplicateHandle (\r
883 IN EFI_AML_HANDLE *AmlHandle\r
884 )\r
885{\r
886 EFI_AML_HANDLE *DstAmlHandle;\r
887\r
888 DstAmlHandle = AllocatePool (sizeof(*DstAmlHandle));\r
889 ASSERT (DstAmlHandle != NULL);\r
890 CopyMem (DstAmlHandle, (VOID *)AmlHandle, sizeof(*DstAmlHandle));\r
891\r
892 return DstAmlHandle;\r
893}\r
894\r
895/**\r
896 Returns the handle of the ACPI object representing the specified ACPI path\r
897 \r
898 @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.\r
899 @param[in] AmlPath Points to the AML path.\r
900 @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to\r
901 HandleIn.\r
902 \r
903 @retval EFI_SUCCESS Success\r
904 @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. \r
905**/\r
906EFI_STATUS\r
907SdtFindPathFromRoot (\r
908 IN EFI_ACPI_HANDLE HandleIn,\r
909 IN UINT8 *AmlPath,\r
910 OUT EFI_ACPI_HANDLE *HandleOut\r
911 )\r
912{\r
913 EFI_ACPI_HANDLE ChildHandle;\r
914 EFI_AML_HANDLE *AmlHandle;\r
915 EFI_STATUS Status;\r
916 VOID *Buffer;\r
917\r
4e1005ec 918 Buffer = NULL;\r
3dc8585e
JY
919 AmlHandle = (EFI_AML_HANDLE *)HandleIn;\r
920\r
921 //\r
922 // Handle case that AcpiPath is Root\r
923 //\r
924 if (AmlIsRootPath (AmlPath)) {\r
925 //\r
926 // Duplicate RootHandle\r
927 //\r
928 *HandleOut = (EFI_ACPI_HANDLE)SdtDuplicateHandle (AmlHandle);\r
929 return EFI_SUCCESS;\r
930 }\r
931\r
932 //\r
933 // Let children find it.\r
934 //\r
935 ChildHandle = NULL;\r
936 while (TRUE) {\r
937 Status = GetChild (HandleIn, &ChildHandle);\r
938 if (EFI_ERROR (Status)) {\r
939 return EFI_INVALID_PARAMETER;\r
940 }\r
941\r
942 if (ChildHandle == NULL) {\r
943 //\r
944 // Not found\r
945 //\r
946 *HandleOut = NULL;\r
947 return EFI_SUCCESS;\r
948 }\r
949\r
950 //\r
951 // More child\r
952 //\r
953 AmlHandle = (EFI_AML_HANDLE *)ChildHandle;\r
954 Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, TRUE);\r
955 if (EFI_ERROR (Status)) {\r
956 return EFI_INVALID_PARAMETER;\r
957 }\r
958\r
959 if (Buffer != NULL) {\r
960 //\r
961 // Great! Find it, open\r
962 //\r
963 Status = SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);\r
964 if (!EFI_ERROR (Status)) {\r
965 return EFI_SUCCESS;\r
966 }\r
967 //\r
968 // Not success, try next one\r
969 //\r
970 }\r
971 }\r
972\r
973 //\r
974 // Should not run here\r
975 //\r
976}\r
977\r
978/**\r
979 Returns the handle of the ACPI object representing the specified ACPI path\r
980 \r
981 @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.\r
982 @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format.\r
983 @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to\r
984 HandleIn.\r
985 \r
986 @retval EFI_SUCCESS Success\r
987 @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. \r
988**/\r
989EFI_STATUS\r
990EFIAPI\r
991FindPath (\r
992 IN EFI_ACPI_HANDLE HandleIn,\r
993 IN VOID *AcpiPath,\r
994 OUT EFI_ACPI_HANDLE *HandleOut\r
995 )\r
996{\r
997 EFI_AML_HANDLE *AmlHandle;\r
998 EFI_STATUS Status;\r
999 UINT8 *AmlPath;\r
1000\r
1001 //\r
1002 // Check for invalid input parameters\r
1003 //\r
1004 if (HandleIn == NULL) {\r
1005 return EFI_INVALID_PARAMETER;\r
1006 }\r
1007\r
1008 AmlHandle = (EFI_AML_HANDLE *)HandleIn;\r
1009 \r
1010 //\r
1011 // Convert ASL path to AML path\r
1012 //\r
1013 AmlPath = AmlNameFromAslName (AcpiPath);\r
1014 if (AmlPath == NULL) {\r
1015 return EFI_INVALID_PARAMETER;\r
1016 }\r
1017\r
1018 DEBUG_CODE_BEGIN ();\r
1019 DEBUG ((EFI_D_ERROR, "AcpiSdt: FindPath - "));\r
1020 AmlPrintNameString (AmlPath);\r
1021 DEBUG ((EFI_D_ERROR, "\n"));\r
1022 DEBUG_CODE_END ();\r
1023\r
1024 if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {\r
1025 //\r
1026 // Root Handle\r
1027 //\r
1028 Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut);\r
1029 } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {\r
1030 //\r
1031 // Non-Root handle\r
1032 //\r
1033 Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut);\r
1034 } else {\r
1035 Status = EFI_INVALID_PARAMETER;\r
1036 }\r
1037\r
1038 FreePool (AmlPath);\r
1039\r
1040 return Status;\r
1041}\r
1042\r
3dc8585e
JY
1043/**\r
1044 This function initializes AcpiSdt protocol in ACPI table instance.\r
1045\r
1046 @param[in] AcpiTableInstance Instance to construct\r
1047**/\r
1048VOID\r
1049SdtAcpiTableAcpiSdtConstructor (\r
1050 IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance\r
1051 )\r
1052{\r
3dc8585e
JY
1053\r
1054 InitializeListHead (&AcpiTableInstance->NotifyList);\r
1055 CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate));\r
f9bbb8d9 1056 AcpiTableInstance->AcpiSdtProtocol.AcpiVersion = (EFI_ACPI_TABLE_VERSION)PcdGet32 (PcdAcpiExposedTableVersions);\r
3dc8585e 1057\r
3dc8585e
JY
1058 return ;\r
1059}\r