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