1 /** @file
2 ACPI Sdt Protocol Driver
3
4 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved. <BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 //
16 // Includes
17 //
18 #include "AcpiTable.h"
19
20 GLOBAL_REMOVE_IF_UNREFERENCED
21 EFI_ACPI_SDT_PROTOCOL mAcpiSdtProtocolTemplate = {
22 EFI_ACPI_TABLE_VERSION_NONE,
23 GetAcpiTable2,
24 RegisterNotify,
25 Open,
26 OpenSdt,
27 Close,
28 GetChild,
29 GetOption,
30 SetOption,
31 FindPath
32 };
33
34 /**
35 This function returns ACPI Table instance.
36
37 @return AcpiTableInstance
38 **/
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 This function initializes AcpiSdt protocol in ACPI table instance.
1045
1046 @param[in] AcpiTableInstance Instance to construct
1047 **/
1048 VOID
SdtAcpiTableAcpiSdtConstructor(IN EFI_ACPI_TABLE_INSTANCE * AcpiTableInstance)1049 SdtAcpiTableAcpiSdtConstructor (
1050 IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
1051 )
1052 {
1053
1054 InitializeListHead (&AcpiTableInstance->NotifyList);
1055 CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate));
1056 AcpiTableInstance->AcpiSdtProtocol.AcpiVersion = (EFI_ACPI_TABLE_VERSION)PcdGet32 (PcdAcpiExposedTableVersions);
1057
1058 return ;
1059 }
1060