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