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