1 /** @file
2   This module provides help function for finding ACPI table.
3 
4   Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "UefiLibInternal.h"
10 #include <IndustryStandard/Acpi.h>
11 #include <Guid/Acpi.h>
12 
13 /**
14   This function scans ACPI table in XSDT/RSDT.
15 
16   @param Sdt                    ACPI XSDT/RSDT.
17   @param TablePointerSize       Size of table pointer: 8(XSDT) or 4(RSDT).
18   @param Signature              ACPI table signature.
19   @param PreviousTable          Pointer to previous returned table to locate
20                                 next table, or NULL to locate first table.
21   @param PreviousTableLocated   Pointer to the indicator about whether the
22                                 previous returned table could be located, or
23                                 NULL if PreviousTable is NULL.
24 
25   If PreviousTable is NULL and PreviousTableLocated is not NULL, then ASSERT().
26   If PreviousTable is not NULL and PreviousTableLocated is NULL, then ASSERT().
27 
28   @return ACPI table or NULL if not found.
29 
30 **/
31 EFI_ACPI_COMMON_HEADER *
ScanTableInSDT(IN EFI_ACPI_DESCRIPTION_HEADER * Sdt,IN UINTN TablePointerSize,IN UINT32 Signature,IN EFI_ACPI_COMMON_HEADER * PreviousTable,OPTIONAL OUT BOOLEAN * PreviousTableLocated OPTIONAL)32 ScanTableInSDT (
33   IN  EFI_ACPI_DESCRIPTION_HEADER   *Sdt,
34   IN  UINTN                         TablePointerSize,
35   IN  UINT32                        Signature,
36   IN  EFI_ACPI_COMMON_HEADER        *PreviousTable, OPTIONAL
37   OUT BOOLEAN                       *PreviousTableLocated OPTIONAL
38   )
39 {
40   UINTN                             Index;
41   UINTN                             EntryCount;
42   UINT64                            EntryPtr;
43   UINTN                             BasePtr;
44   EFI_ACPI_COMMON_HEADER            *Table;
45 
46   if (PreviousTableLocated != NULL) {
47     ASSERT (PreviousTable != NULL);
48     *PreviousTableLocated = FALSE;
49   } else {
50     ASSERT (PreviousTable == NULL);
51   }
52 
53   if (Sdt == NULL) {
54     return NULL;
55   }
56 
57   EntryCount = (Sdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / TablePointerSize;
58 
59   BasePtr = (UINTN)(Sdt + 1);
60   for (Index = 0; Index < EntryCount; Index ++) {
61     EntryPtr = 0;
62     CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * TablePointerSize), TablePointerSize);
63     Table = (EFI_ACPI_COMMON_HEADER *)((UINTN)(EntryPtr));
64     if ((Table != NULL) && (Table->Signature == Signature)) {
65       if (PreviousTable != NULL) {
66         if (Table == PreviousTable) {
67           *PreviousTableLocated = TRUE;
68         } else if (*PreviousTableLocated) {
69           //
70           // Return next table.
71           //
72           return Table;
73         }
74       } else {
75         //
76         // Return first table.
77         //
78         return Table;
79       }
80 
81     }
82   }
83 
84   return NULL;
85 }
86 
87 /**
88   To locate FACS in FADT.
89 
90   @param Fadt   FADT table pointer.
91 
92   @return FACS table pointer or NULL if not found.
93 
94 **/
95 EFI_ACPI_COMMON_HEADER *
LocateAcpiFacsFromFadt(IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * Fadt)96 LocateAcpiFacsFromFadt (
97   IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE  *Fadt
98   )
99 {
100   EFI_ACPI_COMMON_HEADER                        *Facs;
101   UINT64                                        Data64;
102 
103   if (Fadt == NULL) {
104     return NULL;
105   }
106 
107   if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
108     Facs = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->FirmwareCtrl;
109   } else {
110     CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));
111     if (Data64 != 0) {
112       Facs = (EFI_ACPI_COMMON_HEADER *)(UINTN)Data64;
113     } else {
114       Facs = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->FirmwareCtrl;
115     }
116   }
117   return Facs;
118 }
119 
120 /**
121   To locate DSDT in FADT.
122 
123   @param Fadt   FADT table pointer.
124 
125   @return DSDT table pointer or NULL if not found.
126 
127 **/
128 EFI_ACPI_COMMON_HEADER *
LocateAcpiDsdtFromFadt(IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * Fadt)129 LocateAcpiDsdtFromFadt (
130   IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE  *Fadt
131   )
132 {
133   EFI_ACPI_COMMON_HEADER                        *Dsdt;
134   UINT64                                        Data64;
135 
136   if (Fadt == NULL) {
137     return NULL;
138   }
139 
140   if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
141     Dsdt = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->Dsdt;
142   } else {
143     CopyMem (&Data64, &Fadt->XDsdt, sizeof(UINT64));
144     if (Data64 != 0) {
145       Dsdt = (EFI_ACPI_COMMON_HEADER *)(UINTN)Data64;
146     } else {
147       Dsdt = (EFI_ACPI_COMMON_HEADER *)(UINTN)Fadt->Dsdt;
148     }
149   }
150   return Dsdt;
151 }
152 
153 /**
154   To locate ACPI table in ACPI ConfigurationTable.
155 
156   @param AcpiGuid               The GUID used to get ACPI ConfigurationTable.
157   @param Signature              ACPI table signature.
158   @param PreviousTable          Pointer to previous returned table to locate
159                                 next table, or NULL to locate first table.
160   @param PreviousTableLocated   Pointer to the indicator to return whether the
161                                 previous returned table could be located or not,
162                                 or NULL if PreviousTable is NULL.
163 
164   If PreviousTable is NULL and PreviousTableLocated is not NULL, then ASSERT().
165   If PreviousTable is not NULL and PreviousTableLocated is NULL, then ASSERT().
166   If AcpiGuid is NULL, then ASSERT().
167 
168   @return ACPI table or NULL if not found.
169 
170 **/
171 EFI_ACPI_COMMON_HEADER *
LocateAcpiTableInAcpiConfigurationTable(IN EFI_GUID * AcpiGuid,IN UINT32 Signature,IN EFI_ACPI_COMMON_HEADER * PreviousTable,OPTIONAL OUT BOOLEAN * PreviousTableLocated OPTIONAL)172 LocateAcpiTableInAcpiConfigurationTable (
173   IN  EFI_GUID                  *AcpiGuid,
174   IN  UINT32                    Signature,
175   IN  EFI_ACPI_COMMON_HEADER    *PreviousTable, OPTIONAL
176   OUT BOOLEAN                   *PreviousTableLocated OPTIONAL
177   )
178 {
179   EFI_STATUS                                    Status;
180   EFI_ACPI_COMMON_HEADER                        *Table;
181   EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;
182   EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;
183   EFI_ACPI_DESCRIPTION_HEADER                   *Xsdt;
184   EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt;
185 
186   if (PreviousTableLocated != NULL) {
187     ASSERT (PreviousTable != NULL);
188     *PreviousTableLocated = FALSE;
189   } else {
190     ASSERT (PreviousTable == NULL);
191   }
192 
193   Rsdp = NULL;
194   //
195   // Get ACPI ConfigurationTable (RSD_PTR)
196   //
197   Status = EfiGetSystemConfigurationTable(AcpiGuid, (VOID **)&Rsdp);
198   if (EFI_ERROR (Status) || (Rsdp == NULL)) {
199     return NULL;
200   }
201 
202   Table = NULL;
203 
204   //
205   // Search XSDT
206   //
207   if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
208     Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
209     if (Signature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
210       ASSERT (PreviousTable == NULL);
211       //
212       // It is to locate DSDT,
213       // need to locate FADT first.
214       //
215       Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) ScanTableInSDT (
216                Xsdt,
217                sizeof (UINT64),
218                EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
219                NULL,
220                NULL
221                );
222       Table = LocateAcpiDsdtFromFadt (Fadt);
223     } else if (Signature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) {
224       ASSERT (PreviousTable == NULL);
225       //
226       // It is to locate FACS,
227       // need to locate FADT first.
228       //
229       Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) ScanTableInSDT (
230                Xsdt,
231                sizeof (UINT64),
232                EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
233                NULL,
234                NULL
235                );
236       Table = LocateAcpiFacsFromFadt (Fadt);
237     } else {
238       Table = ScanTableInSDT (
239                 Xsdt,
240                 sizeof (UINT64),
241                 Signature,
242                 PreviousTable,
243                 PreviousTableLocated
244                 );
245     }
246   }
247 
248   if (Table != NULL) {
249     return Table;
250   } else if ((PreviousTableLocated != NULL) &&
251               *PreviousTableLocated) {
252     //
253     // PreviousTable could be located in XSDT,
254     // but next table could not be located in XSDT.
255     //
256     return NULL;
257   }
258 
259   //
260   // Search RSDT
261   //
262   Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
263   if (Signature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
264     ASSERT (PreviousTable == NULL);
265     //
266     // It is to locate DSDT,
267     // need to locate FADT first.
268     //
269     Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) ScanTableInSDT (
270              Rsdt,
271              sizeof (UINT32),
272              EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
273              NULL,
274              NULL
275              );
276     Table = LocateAcpiDsdtFromFadt (Fadt);
277   } else if (Signature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) {
278     ASSERT (PreviousTable == NULL);
279     //
280     // It is to locate FACS,
281     // need to locate FADT first.
282     //
283     Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) ScanTableInSDT (
284              Rsdt,
285              sizeof (UINT32),
286              EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
287              NULL,
288              NULL
289              );
290     Table = LocateAcpiFacsFromFadt (Fadt);
291   } else {
292     Table = ScanTableInSDT (
293               Rsdt,
294               sizeof (UINT32),
295               Signature,
296               PreviousTable,
297               PreviousTableLocated
298               );
299   }
300 
301   return Table;
302 }
303 
304 /**
305   This function locates next ACPI table in XSDT/RSDT based on Signature and
306   previous returned Table.
307 
308   If PreviousTable is NULL:
309   This function will locate the first ACPI table in XSDT/RSDT based on
310   Signature in gEfiAcpi20TableGuid system configuration table first, and then
311   gEfiAcpi10TableGuid system configuration table.
312   This function will locate in XSDT first, and then RSDT.
313   For DSDT, this function will locate XDsdt in FADT first, and then Dsdt in
314   FADT.
315   For FACS, this function will locate XFirmwareCtrl in FADT first, and then
316   FirmwareCtrl in FADT.
317 
318   If PreviousTable is not NULL:
319   1. If it could be located in XSDT in gEfiAcpi20TableGuid system configuration
320      table, then this function will just locate next table in XSDT in
321      gEfiAcpi20TableGuid system configuration table.
322   2. If it could be located in RSDT in gEfiAcpi20TableGuid system configuration
323      table, then this function will just locate next table in RSDT in
324      gEfiAcpi20TableGuid system configuration table.
325   3. If it could be located in RSDT in gEfiAcpi10TableGuid system configuration
326      table, then this function will just locate next table in RSDT in
327      gEfiAcpi10TableGuid system configuration table.
328 
329   It's not supported that PreviousTable is not NULL but PreviousTable->Signature
330   is not same with Signature, NULL will be returned.
331 
332   @param Signature          ACPI table signature.
333   @param PreviousTable      Pointer to previous returned table to locate next
334                             table, or NULL to locate first table.
335 
336   @return Next ACPI table or NULL if not found.
337 
338 **/
339 EFI_ACPI_COMMON_HEADER *
340 EFIAPI
EfiLocateNextAcpiTable(IN UINT32 Signature,IN EFI_ACPI_COMMON_HEADER * PreviousTable OPTIONAL)341 EfiLocateNextAcpiTable (
342   IN UINT32                     Signature,
343   IN EFI_ACPI_COMMON_HEADER     *PreviousTable OPTIONAL
344   )
345 {
346   EFI_ACPI_COMMON_HEADER        *Table;
347   BOOLEAN                       TempPreviousTableLocated;
348   BOOLEAN                       *PreviousTableLocated;
349 
350   if (PreviousTable != NULL) {
351     if (PreviousTable->Signature != Signature) {
352       //
353       // PreviousTable->Signature is not same with Signature.
354       //
355       return NULL;
356     } else if ((Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) ||
357                (Signature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) ||
358                (Signature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE)) {
359       //
360       // There is only one FADT/DSDT/FACS table,
361       // so don't try to locate next one.
362       //
363       return NULL;
364     }
365 
366     PreviousTableLocated = &TempPreviousTableLocated;
367     *PreviousTableLocated = FALSE;
368   } else {
369     PreviousTableLocated = NULL;
370   }
371 
372   Table = LocateAcpiTableInAcpiConfigurationTable (
373             &gEfiAcpi20TableGuid,
374             Signature,
375             PreviousTable,
376             PreviousTableLocated
377             );
378   if (Table != NULL) {
379     return Table;
380   } else if ((PreviousTableLocated != NULL) &&
381               *PreviousTableLocated) {
382     //
383     // PreviousTable could be located in gEfiAcpi20TableGuid system
384     // configuration table, but next table could not be located in
385     // gEfiAcpi20TableGuid system configuration table.
386     //
387     return NULL;
388   }
389 
390   return LocateAcpiTableInAcpiConfigurationTable (
391            &gEfiAcpi10TableGuid,
392            Signature,
393            PreviousTable,
394            PreviousTableLocated
395            );
396 }
397 
398 /**
399   This function locates first ACPI table in XSDT/RSDT based on Signature.
400 
401   This function will locate the first ACPI table in XSDT/RSDT based on
402   Signature in gEfiAcpi20TableGuid system configuration table first, and then
403   gEfiAcpi10TableGuid system configuration table.
404   This function will locate in XSDT first, and then RSDT.
405   For DSDT, this function will locate XDsdt in FADT first, and then Dsdt in
406   FADT.
407   For FACS, this function will locate XFirmwareCtrl in FADT first, and then
408   FirmwareCtrl in FADT.
409 
410   @param Signature          ACPI table signature.
411 
412   @return First ACPI table or NULL if not found.
413 
414 **/
415 EFI_ACPI_COMMON_HEADER *
416 EFIAPI
EfiLocateFirstAcpiTable(IN UINT32 Signature)417 EfiLocateFirstAcpiTable (
418   IN UINT32                     Signature
419   )
420 {
421   return EfiLocateNextAcpiTable (Signature, NULL);
422 }
423