1 /** @file
2   ACPI Sdt Protocol Driver
3 
4   Copyright (c) 2010 - 2015, 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 
20 GLOBAL_REMOVE_IF_UNREFERENCED
21 EFI_ACPI_SDT_PROTOCOL  mAcpiSdtProtocolTemplate = {
22   EFI_ACPI_TABLE_VERSION_NONE | EFI_ACPI_TABLE_VERSION_1_0B | ACPI_TABLE_VERSION_GTE_2_0,
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 **/
39 EFI_ACPI_TABLE_INSTANCE *
SdtGetAcpiTableInstance(VOID)40 SdtGetAcpiTableInstance (
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 **/
54 EFI_ACPI_TABLE_LIST *
FindTableByBuffer(IN VOID * Buffer)55 FindTableByBuffer (
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 **/
100 EFI_STATUS
SdtUpdateAmlChecksum(IN VOID * Buffer)101 SdtUpdateAmlChecksum (
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 **/
130 EFI_STATUS
SdtGetMaxAmlBufferSize(IN VOID * Buffer,OUT UINTN * MaxSize)131 SdtGetMaxAmlBufferSize (
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 **/
154 VOID
SdtNotifyAcpiList(IN EFI_ACPI_TABLE_INSTANCE * AcpiTableInstance,IN EFI_ACPI_TABLE_VERSION Version,IN UINTN Handle)155 SdtNotifyAcpiList (
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 **/
222 EFI_STATUS
223 EFIAPI
GetAcpiTable2(IN UINTN Index,OUT EFI_ACPI_SDT_HEADER ** Table,OUT EFI_ACPI_TABLE_VERSION * Version,OUT UINTN * TableKey)224 GetAcpiTable2 (
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 **/
286 VOID
SdtRegisterNotify(IN EFI_ACPI_NOTIFICATION_FN Notification)287 SdtRegisterNotify (
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 **/
329 EFI_STATUS
SdtUnregisterNotify(IN EFI_ACPI_NOTIFICATION_FN Notification)330 SdtUnregisterNotify (
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 **/
386 EFI_STATUS
387 EFIAPI
RegisterNotify(IN BOOLEAN Register,IN EFI_ACPI_NOTIFICATION_FN Notification)388 RegisterNotify (
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 **/
423 EFI_STATUS
SdtOpenSdtTable(IN UINTN TableKey,OUT EFI_ACPI_HANDLE * Handle)424 SdtOpenSdtTable (
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 **/
476 EFI_STATUS
477 EFIAPI
OpenSdt(IN UINTN TableKey,OUT EFI_ACPI_HANDLE * Handle)478 OpenSdt (
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 **/
502 EFI_STATUS
SdtOpenEx(IN VOID * Buffer,IN UINTN BufferSize,OUT EFI_ACPI_HANDLE * Handle)503 SdtOpenEx (
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 **/
557 EFI_STATUS
558 EFIAPI
Open(IN VOID * Buffer,OUT EFI_ACPI_HANDLE * Handle)559 Open (
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 **/
592 EFI_STATUS
593 EFIAPI
Close(IN EFI_ACPI_HANDLE Handle)594 Close (
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 **/
643 EFI_STATUS
644 EFIAPI
GetOption(IN EFI_ACPI_HANDLE Handle,IN UINTN Index,OUT EFI_ACPI_DATA_TYPE * DataType,OUT CONST VOID ** Data,OUT UINTN * DataSize)645 GetOption (
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 **/
708 EFI_STATUS
709 EFIAPI
SetOption(IN EFI_ACPI_HANDLE Handle,IN UINTN Index,IN CONST VOID * Data,IN UINTN DataSize)710 SetOption (
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 **/
781 EFI_STATUS
782 EFIAPI
GetChild(IN EFI_ACPI_HANDLE ParentHandle,IN OUT EFI_ACPI_HANDLE * Handle)783 GetChild (
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 **/
846 EFI_STATUS
SdtFindPathFromNonRoot(IN EFI_ACPI_HANDLE HandleIn,IN UINT8 * AmlPath,OUT EFI_ACPI_HANDLE * HandleOut)847 SdtFindPathFromNonRoot (
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 **/
881 EFI_AML_HANDLE *
SdtDuplicateHandle(IN EFI_AML_HANDLE * AmlHandle)882 SdtDuplicateHandle (
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 **/
906 EFI_STATUS
SdtFindPathFromRoot(IN EFI_ACPI_HANDLE HandleIn,IN UINT8 * AmlPath,OUT EFI_ACPI_HANDLE * HandleOut)907 SdtFindPathFromRoot (
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 **/
989 EFI_STATUS
990 EFIAPI
FindPath(IN EFI_ACPI_HANDLE HandleIn,IN VOID * AcpiPath,OUT EFI_ACPI_HANDLE * HandleOut)991 FindPath (
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   ExitPmAuth Protocol notification event handler.
1045 
1046   @param[in] Event    Event whose notification function is being invoked.
1047   @param[in] Context  Pointer to the notification function's context.
1048 **/
1049 VOID
1050 EFIAPI
ExitPmAuthNotification(IN EFI_EVENT Event,IN VOID * Context)1051 ExitPmAuthNotification (
1052   IN EFI_EVENT  Event,
1053   IN VOID       *Context
1054   )
1055 {
1056   EFI_STATUS Status;
1057   VOID       *DxeSmmReadyToLock;
1058 
1059   //
1060   // Add more check to locate protocol after got event, because
1061   // the library will signal this event immediately once it is register
1062   // just in case it is already installed.
1063   //
1064   Status = gBS->LocateProtocol (
1065                   &gEfiDxeSmmReadyToLockProtocolGuid,
1066                   NULL,
1067                   &DxeSmmReadyToLock
1068                   );
1069   if (EFI_ERROR (Status)) {
1070     return ;
1071   }
1072 
1073   //
1074   // Uninstall ACPI SDT protocol, so that we can make sure no one update ACPI table from API level.
1075   //
1076   Status = gBS->UninstallProtocolInterface (
1077                   mHandle,
1078                   &gEfiAcpiSdtProtocolGuid,
1079                   &mPrivateData->AcpiSdtProtocol
1080                   );
1081   ASSERT_EFI_ERROR (Status);
1082 
1083   //
1084   // Close event, so it will not be invoked again.
1085   //
1086   gBS->CloseEvent (Event);
1087 
1088   return ;
1089 }
1090 
1091 /**
1092   This function initializes AcpiSdt protocol in ACPI table instance.
1093 
1094   @param[in]  AcpiTableInstance       Instance to construct
1095 **/
1096 VOID
SdtAcpiTableAcpiSdtConstructor(IN EFI_ACPI_TABLE_INSTANCE * AcpiTableInstance)1097 SdtAcpiTableAcpiSdtConstructor (
1098   IN EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance
1099   )
1100 {
1101   VOID *Registration;
1102 
1103   InitializeListHead (&AcpiTableInstance->NotifyList);
1104   CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate));
1105 
1106   //
1107   // Register event for ExitPmAuth, so that we can uninstall ACPI SDT protocol after ExitPmAuth.
1108   //
1109   EfiCreateProtocolNotifyEvent (
1110     &gEfiDxeSmmReadyToLockProtocolGuid,
1111     TPL_CALLBACK,
1112     ExitPmAuthNotification,
1113     NULL,
1114     &Registration
1115     );
1116 
1117   return ;
1118 }
1119