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