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