xref: /reactos/drivers/bus/acpi/acpica/tables/tbutils.c (revision 9393fc32)
1 /******************************************************************************
2  *
3  * Module Name: tbutils - ACPI Table utilities
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2021, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "actables.h"
47 
48 #define _COMPONENT          ACPI_TABLES
49         ACPI_MODULE_NAME    ("tbutils")
50 
51 
52 /* Local prototypes */
53 
54 static ACPI_PHYSICAL_ADDRESS
55 AcpiTbGetRootTableEntry (
56     UINT8                   *TableEntry,
57     UINT32                  TableEntrySize);
58 
59 
60 #if (!ACPI_REDUCED_HARDWARE)
61 /*******************************************************************************
62  *
63  * FUNCTION:    AcpiTbInitializeFacs
64  *
65  * PARAMETERS:  None
66  *
67  * RETURN:      Status
68  *
69  * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global
70  *              for accessing the Global Lock and Firmware Waking Vector
71  *
72  ******************************************************************************/
73 
74 ACPI_STATUS
75 AcpiTbInitializeFacs (
76     void)
77 {
78     ACPI_TABLE_FACS         *Facs;
79 
80 
81     /* If Hardware Reduced flag is set, there is no FACS */
82 
83     if (AcpiGbl_ReducedHardware)
84     {
85         AcpiGbl_FACS = NULL;
86         return (AE_OK);
87     }
88     else if (AcpiGbl_FADT.XFacs &&
89          (!AcpiGbl_FADT.Facs || !AcpiGbl_Use32BitFacsAddresses))
90     {
91         (void) AcpiGetTableByIndex (AcpiGbl_XFacsIndex,
92             ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Facs));
93         AcpiGbl_FACS = Facs;
94     }
95     else if (AcpiGbl_FADT.Facs)
96     {
97         (void) AcpiGetTableByIndex (AcpiGbl_FacsIndex,
98             ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Facs));
99         AcpiGbl_FACS = Facs;
100     }
101 
102     /* If there is no FACS, just continue. There was already an error msg */
103 
104     return (AE_OK);
105 }
106 #endif /* !ACPI_REDUCED_HARDWARE */
107 
108 
109 /*******************************************************************************
110  *
111  * FUNCTION:    AcpiTbCheckDsdtHeader
112  *
113  * PARAMETERS:  None
114  *
115  * RETURN:      None
116  *
117  * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect
118  *              if the DSDT has been replaced from outside the OS and/or if
119  *              the DSDT header has been corrupted.
120  *
121  ******************************************************************************/
122 
123 void
124 AcpiTbCheckDsdtHeader (
125     void)
126 {
127 
128     /* Compare original length and checksum to current values */
129 
130     if (AcpiGbl_OriginalDsdtHeader.Length != AcpiGbl_DSDT->Length ||
131         AcpiGbl_OriginalDsdtHeader.Checksum != AcpiGbl_DSDT->Checksum)
132     {
133         ACPI_BIOS_ERROR ((AE_INFO,
134             "The DSDT has been corrupted or replaced - "
135             "old, new headers below"));
136 
137         AcpiTbPrintTableHeader (0, &AcpiGbl_OriginalDsdtHeader);
138         AcpiTbPrintTableHeader (0, AcpiGbl_DSDT);
139 
140         /* Disable further error messages */
141 
142         AcpiGbl_OriginalDsdtHeader.Length = AcpiGbl_DSDT->Length;
143         AcpiGbl_OriginalDsdtHeader.Checksum = AcpiGbl_DSDT->Checksum;
144     }
145 }
146 
147 
148 /*******************************************************************************
149  *
150  * FUNCTION:    AcpiTbCopyDsdt
151  *
152  * PARAMETERS:  TableIndex          - Index of installed table to copy
153  *
154  * RETURN:      The copied DSDT
155  *
156  * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory.
157  *              Some very bad BIOSs are known to either corrupt the DSDT or
158  *              install a new, bad DSDT. This copy works around the problem.
159  *
160  ******************************************************************************/
161 
162 ACPI_TABLE_HEADER *
163 AcpiTbCopyDsdt (
164     UINT32                  TableIndex)
165 {
166     ACPI_TABLE_HEADER       *NewTable;
167     ACPI_TABLE_DESC         *TableDesc;
168 
169 
170     TableDesc = &AcpiGbl_RootTableList.Tables[TableIndex];
171 
172     NewTable = ACPI_ALLOCATE (TableDesc->Length);
173     if (!NewTable)
174     {
175         ACPI_ERROR ((AE_INFO, "Could not copy DSDT of length 0x%X",
176             TableDesc->Length));
177         return (NULL);
178     }
179 
180     memcpy (NewTable, TableDesc->Pointer, TableDesc->Length);
181     AcpiTbUninstallTable (TableDesc);
182 
183     AcpiTbInitTableDescriptor (
184         &AcpiGbl_RootTableList.Tables[AcpiGbl_DsdtIndex],
185         ACPI_PTR_TO_PHYSADDR (NewTable),
186         ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, NewTable);
187 
188     ACPI_INFO ((
189         "Forced DSDT copy: length 0x%05X copied locally, original unmapped",
190         NewTable->Length));
191 
192     return (NewTable);
193 }
194 
195 
196 /*******************************************************************************
197  *
198  * FUNCTION:    AcpiTbGetRootTableEntry
199  *
200  * PARAMETERS:  TableEntry          - Pointer to the RSDT/XSDT table entry
201  *              TableEntrySize      - sizeof 32 or 64 (RSDT or XSDT)
202  *
203  * RETURN:      Physical address extracted from the root table
204  *
205  * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
206  *              both 32-bit and 64-bit platforms
207  *
208  * NOTE:        ACPI_PHYSICAL_ADDRESS is 32-bit on 32-bit platforms, 64-bit on
209  *              64-bit platforms.
210  *
211  ******************************************************************************/
212 
213 static ACPI_PHYSICAL_ADDRESS
214 AcpiTbGetRootTableEntry (
215     UINT8                   *TableEntry,
216     UINT32                  TableEntrySize)
217 {
218     UINT64                  Address64;
219 
220 
221     /*
222      * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
223      * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
224      */
225     if (TableEntrySize == ACPI_RSDT_ENTRY_SIZE)
226     {
227         /*
228          * 32-bit platform, RSDT: Return 32-bit table entry
229          * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
230          */
231         return ((ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST_PTR (
232             UINT32, TableEntry)));
233     }
234     else
235     {
236         /*
237          * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
238          * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
239          *  return 64-bit
240          */
241         ACPI_MOVE_64_TO_64 (&Address64, TableEntry);
242 
243 #if ACPI_MACHINE_WIDTH == 32
244         if (Address64 > ACPI_UINT32_MAX)
245         {
246             /* Will truncate 64-bit address to 32 bits, issue warning */
247 
248             ACPI_BIOS_WARNING ((AE_INFO,
249                 "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
250                 " truncating",
251                 ACPI_FORMAT_UINT64 (Address64)));
252         }
253 #endif
254         return ((ACPI_PHYSICAL_ADDRESS) (Address64));
255     }
256 }
257 
258 
259 /*******************************************************************************
260  *
261  * FUNCTION:    AcpiTbParseRootTable
262  *
263  * PARAMETERS:  RsdpAddress         - Pointer to the RSDP
264  *
265  * RETURN:      Status
266  *
267  * DESCRIPTION: This function is called to parse the Root System Description
268  *              Table (RSDT or XSDT)
269  *
270  * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
271  *              be mapped and cannot be copied because it contains the actual
272  *              memory location of the ACPI Global Lock.
273  *
274  ******************************************************************************/
275 
276 ACPI_STATUS ACPI_INIT_FUNCTION
277 AcpiTbParseRootTable (
278     ACPI_PHYSICAL_ADDRESS   RsdpAddress)
279 {
280     ACPI_TABLE_RSDP         *Rsdp;
281     UINT32                  TableEntrySize;
282     UINT32                  i;
283     UINT32                  TableCount;
284     ACPI_TABLE_HEADER       *Table;
285     ACPI_PHYSICAL_ADDRESS   Address;
286     UINT32                  Length;
287     UINT8                   *TableEntry;
288     ACPI_STATUS             Status;
289     UINT32                  TableIndex;
290 
291 
292     ACPI_FUNCTION_TRACE (TbParseRootTable);
293 
294 
295     /* Map the entire RSDP and extract the address of the RSDT or XSDT */
296 
297     Rsdp = AcpiOsMapMemory (RsdpAddress, sizeof (ACPI_TABLE_RSDP));
298     if (!Rsdp)
299     {
300         return_ACPI_STATUS (AE_NO_MEMORY);
301     }
302 
303     AcpiTbPrintTableHeader (RsdpAddress,
304         ACPI_CAST_PTR (ACPI_TABLE_HEADER, Rsdp));
305 
306     /* Use XSDT if present and not overridden. Otherwise, use RSDT */
307 
308     if ((Rsdp->Revision > 1) &&
309         Rsdp->XsdtPhysicalAddress &&
310         !AcpiGbl_DoNotUseXsdt)
311     {
312         /*
313          * RSDP contains an XSDT (64-bit physical addresses). We must use
314          * the XSDT if the revision is > 1 and the XSDT pointer is present,
315          * as per the ACPI specification.
316          */
317         Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->XsdtPhysicalAddress;
318         TableEntrySize = ACPI_XSDT_ENTRY_SIZE;
319     }
320     else
321     {
322         /* Root table is an RSDT (32-bit physical addresses) */
323 
324         Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress;
325         TableEntrySize = ACPI_RSDT_ENTRY_SIZE;
326     }
327 
328     /*
329      * It is not possible to map more than one entry in some environments,
330      * so unmap the RSDP here before mapping other tables
331      */
332     AcpiOsUnmapMemory (Rsdp, sizeof (ACPI_TABLE_RSDP));
333 
334     /* Map the RSDT/XSDT table header to get the full table length */
335 
336     Table = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
337     if (!Table)
338     {
339         return_ACPI_STATUS (AE_NO_MEMORY);
340     }
341 
342     AcpiTbPrintTableHeader (Address, Table);
343 
344     /*
345      * Validate length of the table, and map entire table.
346      * Minimum length table must contain at least one entry.
347      */
348     Length = Table->Length;
349     AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER));
350 
351     if (Length < (sizeof (ACPI_TABLE_HEADER) + TableEntrySize))
352     {
353         ACPI_BIOS_ERROR ((AE_INFO,
354             "Invalid table length 0x%X in RSDT/XSDT", Length));
355         return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
356     }
357 
358     Table = AcpiOsMapMemory (Address, Length);
359     if (!Table)
360     {
361         return_ACPI_STATUS (AE_NO_MEMORY);
362     }
363 
364     /* Validate the root table checksum */
365 
366     Status = AcpiTbVerifyChecksum (Table, Length);
367     if (ACPI_FAILURE (Status))
368     {
369         AcpiOsUnmapMemory (Table, Length);
370         return_ACPI_STATUS (Status);
371     }
372 
373     /* Get the number of entries and pointer to first entry */
374 
375     TableCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) /
376         TableEntrySize);
377     TableEntry = ACPI_ADD_PTR (UINT8, Table, sizeof (ACPI_TABLE_HEADER));
378 
379     /* Initialize the root table array from the RSDT/XSDT */
380 
381     for (i = 0; i < TableCount; i++)
382     {
383         /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
384 
385         Address = AcpiTbGetRootTableEntry (TableEntry, TableEntrySize);
386 
387         /* Skip NULL entries in RSDT/XSDT */
388 
389         if (!Address)
390         {
391             goto NextTable;
392         }
393 
394         Status = AcpiTbInstallStandardTable (Address,
395             ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, FALSE, TRUE, &TableIndex);
396 
397         if (ACPI_SUCCESS (Status) &&
398             ACPI_COMPARE_NAMESEG (
399                 &AcpiGbl_RootTableList.Tables[TableIndex].Signature,
400                 ACPI_SIG_FADT))
401         {
402             AcpiGbl_FadtIndex = TableIndex;
403             AcpiTbParseFadt ();
404         }
405 
406 NextTable:
407 
408         TableEntry += TableEntrySize;
409     }
410 
411     AcpiOsUnmapMemory (Table, Length);
412     return_ACPI_STATUS (AE_OK);
413 }
414 
415 
416 /*******************************************************************************
417  *
418  * FUNCTION:    AcpiTbGetTable
419  *
420  * PARAMETERS:  TableDesc           - Table descriptor
421  *              OutTable            - Where the pointer to the table is returned
422  *
423  * RETURN:      Status and pointer to the requested table
424  *
425  * DESCRIPTION: Increase a reference to a table descriptor and return the
426  *              validated table pointer.
427  *              If the table descriptor is an entry of the root table list,
428  *              this API must be invoked with ACPI_MTX_TABLES acquired.
429  *
430  ******************************************************************************/
431 
432 ACPI_STATUS
433 AcpiTbGetTable (
434     ACPI_TABLE_DESC        *TableDesc,
435     ACPI_TABLE_HEADER      **OutTable)
436 {
437     ACPI_STATUS            Status;
438 
439 
440     ACPI_FUNCTION_TRACE (AcpiTbGetTable);
441 
442 
443     if (TableDesc->ValidationCount == 0)
444     {
445         /* Table need to be "VALIDATED" */
446 
447         Status = AcpiTbValidateTable (TableDesc);
448         if (ACPI_FAILURE (Status))
449         {
450             return_ACPI_STATUS (Status);
451         }
452     }
453 
454     if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS)
455     {
456         TableDesc->ValidationCount++;
457 
458         /*
459          * Detect ValidationCount overflows to ensure that the warning
460          * message will only be printed once.
461          */
462         if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS)
463         {
464             ACPI_WARNING((AE_INFO,
465                 "Table %p, Validation count overflows\n", TableDesc));
466         }
467     }
468 
469     *OutTable = TableDesc->Pointer;
470     return_ACPI_STATUS (AE_OK);
471 }
472 
473 
474 /*******************************************************************************
475  *
476  * FUNCTION:    AcpiTbPutTable
477  *
478  * PARAMETERS:  TableDesc           - Table descriptor
479  *
480  * RETURN:      None
481  *
482  * DESCRIPTION: Decrease a reference to a table descriptor and release the
483  *              validated table pointer if no references.
484  *              If the table descriptor is an entry of the root table list,
485  *              this API must be invoked with ACPI_MTX_TABLES acquired.
486  *
487  ******************************************************************************/
488 
489 void
490 AcpiTbPutTable (
491     ACPI_TABLE_DESC        *TableDesc)
492 {
493 
494     ACPI_FUNCTION_TRACE (AcpiTbPutTable);
495 
496 
497     if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS)
498     {
499         TableDesc->ValidationCount--;
500 
501         /*
502          * Detect ValidationCount underflows to ensure that the warning
503          * message will only be printed once.
504          */
505         if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS)
506         {
507             ACPI_WARNING ((AE_INFO,
508                 "Table %p, Validation count underflows\n", TableDesc));
509             return_VOID;
510         }
511     }
512 
513     if (TableDesc->ValidationCount == 0)
514     {
515         /* Table need to be "INVALIDATED" */
516 
517         AcpiTbInvalidateTable (TableDesc);
518     }
519 
520     return_VOID;
521 }
522