1/******************************************************************************
2 *
3 * Module Name: tbutils - ACPI Table utilities
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2023, 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
54static ACPI_PHYSICAL_ADDRESS
55AcpiTbGetRootTableEntry (
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
74ACPI_STATUS
75AcpiTbInitializeFacs (
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
123void
124AcpiTbCheckDsdtHeader (
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
162ACPI_TABLE_HEADER *
163AcpiTbCopyDsdt (
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
213static ACPI_PHYSICAL_ADDRESS
214AcpiTbGetRootTableEntry (
215    UINT8                   *TableEntry,
216    UINT32                  TableEntrySize)
217{
218    UINT32                  Address32;
219    UINT64                  Address64;
220
221
222    /*
223     * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
224     * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
225     */
226    if (TableEntrySize == ACPI_RSDT_ENTRY_SIZE)
227    {
228        /*
229         * 32-bit platform, RSDT: Return 32-bit table entry
230         * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
231         */
232        ACPI_MOVE_32_TO_32(&Address32, TableEntry);
233        return Address32;
234    }
235    else
236    {
237        /*
238         * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
239         * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
240         *  return 64-bit
241         */
242        ACPI_MOVE_64_TO_64 (&Address64, TableEntry);
243
244#if ACPI_MACHINE_WIDTH == 32
245        if (Address64 > ACPI_UINT32_MAX)
246        {
247            /* Will truncate 64-bit address to 32 bits, issue warning */
248
249            ACPI_BIOS_WARNING ((AE_INFO,
250                "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
251                " truncating",
252                ACPI_FORMAT_UINT64 (Address64)));
253        }
254#endif
255        return ((ACPI_PHYSICAL_ADDRESS) (Address64));
256    }
257}
258
259
260/*******************************************************************************
261 *
262 * FUNCTION:    AcpiTbParseRootTable
263 *
264 * PARAMETERS:  RsdpAddress         - Pointer to the RSDP
265 *
266 * RETURN:      Status
267 *
268 * DESCRIPTION: This function is called to parse the Root System Description
269 *              Table (RSDT or XSDT)
270 *
271 * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
272 *              be mapped and cannot be copied because it contains the actual
273 *              memory location of the ACPI Global Lock.
274 *
275 ******************************************************************************/
276
277ACPI_STATUS ACPI_INIT_FUNCTION
278AcpiTbParseRootTable (
279    ACPI_PHYSICAL_ADDRESS   RsdpAddress)
280{
281    ACPI_TABLE_RSDP         *Rsdp;
282    UINT32                  TableEntrySize;
283    UINT32                  i;
284    UINT32                  TableCount;
285    ACPI_TABLE_HEADER       *Table;
286    ACPI_PHYSICAL_ADDRESS   Address;
287    UINT32                  Length;
288    UINT8                   *TableEntry;
289    ACPI_STATUS             Status;
290    UINT32                  TableIndex;
291
292
293    ACPI_FUNCTION_TRACE (TbParseRootTable);
294
295
296    /* Map the entire RSDP and extract the address of the RSDT or XSDT */
297
298    Rsdp = AcpiOsMapMemory (RsdpAddress, sizeof (ACPI_TABLE_RSDP));
299    if (!Rsdp)
300    {
301        return_ACPI_STATUS (AE_NO_MEMORY);
302    }
303
304    AcpiTbPrintTableHeader (RsdpAddress,
305        ACPI_CAST_PTR (ACPI_TABLE_HEADER, Rsdp));
306
307    /* Use XSDT if present and not overridden. Otherwise, use RSDT */
308
309    if ((Rsdp->Revision > 1) &&
310        Rsdp->XsdtPhysicalAddress &&
311        !AcpiGbl_DoNotUseXsdt)
312    {
313        /*
314         * RSDP contains an XSDT (64-bit physical addresses). We must use
315         * the XSDT if the revision is > 1 and the XSDT pointer is present,
316         * as per the ACPI specification.
317         */
318        Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->XsdtPhysicalAddress;
319        TableEntrySize = ACPI_XSDT_ENTRY_SIZE;
320    }
321    else
322    {
323        /* Root table is an RSDT (32-bit physical addresses) */
324
325        Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress;
326        TableEntrySize = ACPI_RSDT_ENTRY_SIZE;
327    }
328
329    /*
330     * It is not possible to map more than one entry in some environments,
331     * so unmap the RSDP here before mapping other tables
332     */
333    AcpiOsUnmapMemory (Rsdp, sizeof (ACPI_TABLE_RSDP));
334
335    /* Map the RSDT/XSDT table header to get the full table length */
336
337    Table = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
338    if (!Table)
339    {
340        return_ACPI_STATUS (AE_NO_MEMORY);
341    }
342
343    AcpiTbPrintTableHeader (Address, Table);
344
345    /*
346     * Validate length of the table, and map entire table.
347     * Minimum length table must contain at least one entry.
348     */
349    Length = Table->Length;
350    AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER));
351
352    if (Length < (sizeof (ACPI_TABLE_HEADER) + TableEntrySize))
353    {
354        ACPI_BIOS_ERROR ((AE_INFO,
355            "Invalid table length 0x%X in RSDT/XSDT", Length));
356        return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
357    }
358
359    Table = AcpiOsMapMemory (Address, Length);
360    if (!Table)
361    {
362        return_ACPI_STATUS (AE_NO_MEMORY);
363    }
364
365    /* Validate the root table checksum */
366
367    Status = AcpiUtVerifyChecksum (Table, Length);
368    if (ACPI_FAILURE (Status))
369    {
370        AcpiOsUnmapMemory (Table, Length);
371        return_ACPI_STATUS (Status);
372    }
373
374    /* Get the number of entries and pointer to first entry */
375
376    TableCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) /
377        TableEntrySize);
378    TableEntry = ACPI_ADD_PTR (UINT8, Table, sizeof (ACPI_TABLE_HEADER));
379
380    /* Initialize the root table array from the RSDT/XSDT */
381
382    for (i = 0; i < TableCount; i++)
383    {
384        /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
385
386        Address = AcpiTbGetRootTableEntry (TableEntry, TableEntrySize);
387
388        /* Skip NULL entries in RSDT/XSDT */
389
390        if (!Address)
391        {
392            goto NextTable;
393        }
394
395        Status = AcpiTbInstallStandardTable (Address,
396            ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, NULL, FALSE, TRUE,
397            &TableIndex);
398
399        if (ACPI_SUCCESS (Status) &&
400            ACPI_COMPARE_NAMESEG (
401                &AcpiGbl_RootTableList.Tables[TableIndex].Signature,
402                ACPI_SIG_FADT))
403        {
404            AcpiGbl_FadtIndex = TableIndex;
405            AcpiTbParseFadt ();
406        }
407
408NextTable:
409
410        TableEntry += TableEntrySize;
411    }
412
413    AcpiOsUnmapMemory (Table, Length);
414    return_ACPI_STATUS (AE_OK);
415}
416
417
418/*******************************************************************************
419 *
420 * FUNCTION:    AcpiTbGetTable
421 *
422 * PARAMETERS:  TableDesc           - Table descriptor
423 *              OutTable            - Where the pointer to the table is returned
424 *
425 * RETURN:      Status and pointer to the requested table
426 *
427 * DESCRIPTION: Increase a reference to a table descriptor and return the
428 *              validated table pointer.
429 *              If the table descriptor is an entry of the root table list,
430 *              this API must be invoked with ACPI_MTX_TABLES acquired.
431 *
432 ******************************************************************************/
433
434ACPI_STATUS
435AcpiTbGetTable (
436    ACPI_TABLE_DESC        *TableDesc,
437    ACPI_TABLE_HEADER      **OutTable)
438{
439    ACPI_STATUS            Status;
440
441
442    ACPI_FUNCTION_TRACE (AcpiTbGetTable);
443
444
445    if (TableDesc->ValidationCount == 0)
446    {
447        /* Table need to be "VALIDATED" */
448
449        Status = AcpiTbValidateTable (TableDesc);
450        if (ACPI_FAILURE (Status))
451        {
452            return_ACPI_STATUS (Status);
453        }
454    }
455
456    if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS)
457    {
458        TableDesc->ValidationCount++;
459
460        /*
461         * Detect ValidationCount overflows to ensure that the warning
462         * message will only be printed once.
463         */
464        if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS)
465        {
466            ACPI_WARNING((AE_INFO,
467                "Table %p, Validation count overflows\n", TableDesc));
468        }
469    }
470
471    *OutTable = TableDesc->Pointer;
472    return_ACPI_STATUS (AE_OK);
473}
474
475
476/*******************************************************************************
477 *
478 * FUNCTION:    AcpiTbPutTable
479 *
480 * PARAMETERS:  TableDesc           - Table descriptor
481 *
482 * RETURN:      None
483 *
484 * DESCRIPTION: Decrease a reference to a table descriptor and release the
485 *              validated table pointer if no references.
486 *              If the table descriptor is an entry of the root table list,
487 *              this API must be invoked with ACPI_MTX_TABLES acquired.
488 *
489 ******************************************************************************/
490
491void
492AcpiTbPutTable (
493    ACPI_TABLE_DESC        *TableDesc)
494{
495
496    ACPI_FUNCTION_TRACE (AcpiTbPutTable);
497
498
499    if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS)
500    {
501        TableDesc->ValidationCount--;
502
503        /*
504         * Detect ValidationCount underflows to ensure that the warning
505         * message will only be printed once.
506         */
507        if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS)
508        {
509            ACPI_WARNING ((AE_INFO,
510                "Table %p, Validation count underflows\n", TableDesc));
511            return_VOID;
512        }
513    }
514
515    if (TableDesc->ValidationCount == 0)
516    {
517        /* Table need to be "INVALIDATED" */
518
519        AcpiTbInvalidateTable (TableDesc);
520    }
521
522    return_VOID;
523}
524