tbutils.c revision 233250
1130561Sobrien/******************************************************************************
277298Sobrien *
3218822Sdim * Module Name: tbutils   - table utilities
438889Sjdp *
533965Sjdp *****************************************************************************/
6130561Sobrien
733965Sjdp/*
8130561Sobrien * Copyright (C) 2000 - 2012, Intel Corp.
9130561Sobrien * All rights reserved.
10130561Sobrien *
11130561Sobrien * Redistribution and use in source and binary forms, with or without
1233965Sjdp * modification, are permitted provided that the following conditions
13130561Sobrien * are met:
14130561Sobrien * 1. Redistributions of source code must retain the above copyright
15130561Sobrien *    notice, this list of conditions, and the following disclaimer,
16130561Sobrien *    without modification.
1733965Sjdp * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18130561Sobrien *    substantially similar to the "NO WARRANTY" disclaimer below
19130561Sobrien *    ("Disclaimer") and any redistribution must be conditioned upon
20218822Sdim *    including a substantially similar Disclaimer requirement for further
21218822Sdim *    binary redistribution.
2233965Sjdp * 3. Neither the names of the above-listed copyright holders nor the names
23130561Sobrien *    of any contributors may be used to endorse or promote products derived
2433965Sjdp *    from this software without specific prior written permission.
2533965Sjdp *
2633965Sjdp * Alternatively, this software may be distributed under the terms of the
2733965Sjdp * GNU General Public License ("GPL") version 2 as published by the Free
2833965Sjdp * Software Foundation.
2933965Sjdp *
3033965Sjdp * NO WARRANTY
3133965Sjdp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3233965Sjdp * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3333965Sjdp * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3433965Sjdp * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3533965Sjdp * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3633965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3733965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3833965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3933965Sjdp * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4033965Sjdp * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4133965Sjdp * POSSIBILITY OF SUCH DAMAGES.
4233965Sjdp */
4333965Sjdp
4433965Sjdp#define __TBUTILS_C__
4533965Sjdp
4633965Sjdp#include <contrib/dev/acpica/include/acpi.h>
4733965Sjdp#include <contrib/dev/acpica/include/accommon.h>
4833965Sjdp#include <contrib/dev/acpica/include/actables.h>
4933965Sjdp
5033965Sjdp#define _COMPONENT          ACPI_TABLES
5133965Sjdp        ACPI_MODULE_NAME    ("tbutils")
5233965Sjdp
5333965Sjdp
5433965Sjdp/* Local prototypes */
5533965Sjdp
5633965Sjdpstatic void
5733965SjdpAcpiTbFixString (
5833965Sjdp    char                    *String,
5933965Sjdp    ACPI_SIZE               Length);
6033965Sjdp
6133965Sjdpstatic void
6233965SjdpAcpiTbCleanupTableHeader (
6333965Sjdp    ACPI_TABLE_HEADER       *OutHeader,
6433965Sjdp    ACPI_TABLE_HEADER       *Header);
6533965Sjdp
6633965Sjdpstatic ACPI_PHYSICAL_ADDRESS
67130561SobrienAcpiTbGetRootTableEntry (
6833965Sjdp    UINT8                   *TableEntry,
6933965Sjdp    UINT32                  TableEntrySize);
7033965Sjdp
7133965Sjdp
7233965Sjdp#if (!ACPI_REDUCED_HARDWARE)
7333965Sjdp/*******************************************************************************
7433965Sjdp *
7533965Sjdp * FUNCTION:    AcpiTbInitializeFacs
7633965Sjdp *
7733965Sjdp * PARAMETERS:  None
7833965Sjdp *
7933965Sjdp * RETURN:      Status
8033965Sjdp *
8133965Sjdp * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global
8233965Sjdp *              for accessing the Global Lock and Firmware Waking Vector
8333965Sjdp *
8433965Sjdp ******************************************************************************/
8533965Sjdp
8633965SjdpACPI_STATUS
8733965SjdpAcpiTbInitializeFacs (
88130561Sobrien    void)
8933965Sjdp{
90130561Sobrien    ACPI_STATUS             Status;
9133965Sjdp
9233965Sjdp
93104834Sobrien    /* If Hardware Reduced flag is set, there is no FACS */
9489857Sobrien
9533965Sjdp    if (AcpiGbl_ReducedHardware)
9633965Sjdp    {
9733965Sjdp        AcpiGbl_FACS = NULL;
9833965Sjdp        return (AE_OK);
9938889Sjdp    }
10033965Sjdp
10133965Sjdp    Status = AcpiGetTableByIndex (ACPI_TABLE_INDEX_FACS,
10233965Sjdp                ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &AcpiGbl_FACS));
10333965Sjdp    return (Status);
10433965Sjdp}
10533965Sjdp#endif /* !ACPI_REDUCED_HARDWARE */
10633965Sjdp
10760484Sobrien
10833965Sjdp/*******************************************************************************
10933965Sjdp *
11060484Sobrien * FUNCTION:    AcpiTbTablesLoaded
11133965Sjdp *
11233965Sjdp * PARAMETERS:  None
11333965Sjdp *
11433965Sjdp * RETURN:      TRUE if required ACPI tables are loaded
11533965Sjdp *
11633965Sjdp * DESCRIPTION: Determine if the minimum required ACPI tables are present
11733965Sjdp *              (FADT, FACS, DSDT)
11833965Sjdp *
11977298Sobrien ******************************************************************************/
120130561Sobrien
121130561SobrienBOOLEAN
12260484SobrienAcpiTbTablesLoaded (
12360484Sobrien    void)
12460484Sobrien{
12560484Sobrien
12660484Sobrien    if (AcpiGbl_RootTableList.CurrentTableCount >= 3)
12777298Sobrien    {
12833965Sjdp        return (TRUE);
129130561Sobrien    }
13077298Sobrien
131130561Sobrien    return (FALSE);
132130561Sobrien}
13377298Sobrien
13477298Sobrien
13538889Sjdp/*******************************************************************************
13677298Sobrien *
13733965Sjdp * FUNCTION:    AcpiTbFixString
138130561Sobrien *
13933965Sjdp * PARAMETERS:  String              - String to be repaired
14077298Sobrien *              Length              - Maximum length
14177298Sobrien *
14233965Sjdp * RETURN:      None
14338889Sjdp *
14477298Sobrien * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
14538889Sjdp *              with a question mark '?'.
14677298Sobrien *
14777298Sobrien ******************************************************************************/
14833965Sjdp
14933965Sjdpstatic void
15077298SobrienAcpiTbFixString (
15177298Sobrien    char                    *String,
152130561Sobrien    ACPI_SIZE               Length)
15377298Sobrien{
15438889Sjdp
15533965Sjdp    while (Length && *String)
15677298Sobrien    {
15777298Sobrien        if (!ACPI_IS_PRINT (*String))
15833965Sjdp        {
159130561Sobrien            *String = '?';
160130561Sobrien        }
161130561Sobrien        String++;
162130561Sobrien        Length--;
163130561Sobrien    }
164130561Sobrien}
165130561Sobrien
166130561Sobrien
167130561Sobrien/*******************************************************************************
168130561Sobrien *
16977298Sobrien * FUNCTION:    AcpiTbCleanupTableHeader
17033965Sjdp *
17138889Sjdp * PARAMETERS:  OutHeader           - Where the cleaned header is returned
17238889Sjdp *              Header              - Input ACPI table header
17338889Sjdp *
17438889Sjdp * RETURN:      Returns the cleaned header in OutHeader
17538889Sjdp *
17633965Sjdp * DESCRIPTION: Copy the table header and ensure that all "string" fields in
17738889Sjdp *              the header consist of printable characters.
17833965Sjdp *
17960484Sobrien ******************************************************************************/
18060484Sobrien
18160484Sobrienstatic void
18260484SobrienAcpiTbCleanupTableHeader (
18333965Sjdp    ACPI_TABLE_HEADER       *OutHeader,
18460484Sobrien    ACPI_TABLE_HEADER       *Header)
18560484Sobrien{
18660484Sobrien
18760484Sobrien    ACPI_MEMCPY (OutHeader, Header, sizeof (ACPI_TABLE_HEADER));
18860484Sobrien
18960484Sobrien    AcpiTbFixString (OutHeader->Signature, ACPI_NAME_SIZE);
19060484Sobrien    AcpiTbFixString (OutHeader->OemId, ACPI_OEM_ID_SIZE);
19160484Sobrien    AcpiTbFixString (OutHeader->OemTableId, ACPI_OEM_TABLE_ID_SIZE);
19260484Sobrien    AcpiTbFixString (OutHeader->AslCompilerId, ACPI_NAME_SIZE);
19360484Sobrien}
19460484Sobrien
19533965Sjdp
19677298Sobrien/*******************************************************************************
19733965Sjdp *
19838889Sjdp * FUNCTION:    AcpiTbPrintTableHeader
19938889Sjdp *
20033965Sjdp * PARAMETERS:  Address             - Table physical address
20138889Sjdp *              Header              - Table header
20238889Sjdp *
20338889Sjdp * RETURN:      None
20438889Sjdp *
20538889Sjdp * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
20633965Sjdp *
20777298Sobrien ******************************************************************************/
20833965Sjdp
20933965Sjdpvoid
210130561SobrienAcpiTbPrintTableHeader (
211130561Sobrien    ACPI_PHYSICAL_ADDRESS   Address,
212130561Sobrien    ACPI_TABLE_HEADER       *Header)
213130561Sobrien{
214130561Sobrien    ACPI_TABLE_HEADER       LocalHeader;
215130561Sobrien
216130561Sobrien
217130561Sobrien    /*
218130561Sobrien     * The reason that the Address is cast to a void pointer is so that we
219130561Sobrien     * can use %p which will work properly on both 32-bit and 64-bit hosts.
220130561Sobrien     */
22133965Sjdp    if (ACPI_COMPARE_NAME (Header->Signature, ACPI_SIG_FACS))
22233965Sjdp    {
223130561Sobrien        /* FACS only has signature and length fields */
22433965Sjdp
22533965Sjdp        ACPI_INFO ((AE_INFO, "%4.4s %p %05X",
22633965Sjdp            Header->Signature, ACPI_CAST_PTR (void, Address),
22777298Sobrien            Header->Length));
22877298Sobrien    }
22977298Sobrien    else if (ACPI_COMPARE_NAME (Header->Signature, ACPI_SIG_RSDP))
23077298Sobrien    {
23133965Sjdp        /* RSDP has no common fields */
23233965Sjdp
23333965Sjdp        ACPI_MEMCPY (LocalHeader.OemId,
23433965Sjdp            ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->OemId, ACPI_OEM_ID_SIZE);
23533965Sjdp        AcpiTbFixString (LocalHeader.OemId, ACPI_OEM_ID_SIZE);
236130561Sobrien
23733965Sjdp        ACPI_INFO ((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
23860484Sobrien            ACPI_CAST_PTR (void, Address),
23933965Sjdp            (ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision > 0) ?
24033965Sjdp                ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Length : 20,
24133965Sjdp            ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision,
242130561Sobrien            LocalHeader.OemId));
24333965Sjdp    }
24460484Sobrien    else
24533965Sjdp    {
24633965Sjdp        /* Standard ACPI table with full common header */
24733965Sjdp
248130561Sobrien        AcpiTbCleanupTableHeader (&LocalHeader, Header);
24933965Sjdp
25077298Sobrien        ACPI_INFO ((AE_INFO,
25133965Sjdp            "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
25233965Sjdp            LocalHeader.Signature, ACPI_CAST_PTR (void, Address),
25333965Sjdp            LocalHeader.Length, LocalHeader.Revision, LocalHeader.OemId,
25433965Sjdp            LocalHeader.OemTableId, LocalHeader.OemRevision,
25533965Sjdp            LocalHeader.AslCompilerId, LocalHeader.AslCompilerRevision));
25633965Sjdp    }
25733965Sjdp}
25833965Sjdp
25933965Sjdp
26077298Sobrien/*******************************************************************************
261130561Sobrien *
26233965Sjdp * FUNCTION:    AcpiTbValidateChecksum
26333965Sjdp *
264104834Sobrien * PARAMETERS:  Table               - ACPI table to verify
26538889Sjdp *              Length              - Length of entire table
26633965Sjdp *
26733965Sjdp * RETURN:      Status
26833965Sjdp *
26933965Sjdp * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
27033965Sjdp *              exception on bad checksum.
27133965Sjdp *
27233965Sjdp ******************************************************************************/
273130561Sobrien
27433965SjdpACPI_STATUS
27533965SjdpAcpiTbVerifyChecksum (
27633965Sjdp    ACPI_TABLE_HEADER       *Table,
27733965Sjdp    UINT32                  Length)
27833965Sjdp{
27933965Sjdp    UINT8                   Checksum;
280130561Sobrien
28133965Sjdp
28233965Sjdp    /* Compute the checksum on the table */
28333965Sjdp
28433965Sjdp    Checksum = AcpiTbChecksum (ACPI_CAST_PTR (UINT8, Table), Length);
28533965Sjdp
28638889Sjdp    /* Checksum ok? (should be zero) */
28733965Sjdp
28833965Sjdp    if (Checksum)
28933965Sjdp    {
29033965Sjdp        ACPI_WARNING ((AE_INFO,
29133965Sjdp            "Incorrect checksum in table [%4.4s] - 0x%2.2X, should be 0x%2.2X",
29233965Sjdp            Table->Signature, Table->Checksum,
29333965Sjdp            (UINT8) (Table->Checksum - Checksum)));
29438889Sjdp
29538889Sjdp#if (ACPI_CHECKSUM_ABORT)
29638889Sjdp        return (AE_BAD_CHECKSUM);
29738889Sjdp#endif
29838889Sjdp    }
29938889Sjdp
30038889Sjdp    return (AE_OK);
30138889Sjdp}
30238889Sjdp
30338889Sjdp
30438889Sjdp/*******************************************************************************
30538889Sjdp *
30638889Sjdp * FUNCTION:    AcpiTbChecksum
30738889Sjdp *
30838889Sjdp * PARAMETERS:  Buffer          - Pointer to memory region to be checked
30938889Sjdp *              Length          - Length of this memory region
31038889Sjdp *
31138889Sjdp * RETURN:      Checksum (UINT8)
31233965Sjdp *
31338889Sjdp * DESCRIPTION: Calculates circular checksum of memory region.
31433965Sjdp *
31577298Sobrien ******************************************************************************/
31677298Sobrien
31738889SjdpUINT8
31833965SjdpAcpiTbChecksum (
31933965Sjdp    UINT8                   *Buffer,
32060484Sobrien    UINT32                  Length)
32160484Sobrien{
32260484Sobrien    UINT8                   Sum = 0;
32360484Sobrien    UINT8                   *End = Buffer + Length;
32460484Sobrien
32560484Sobrien
32660484Sobrien    while (Buffer < End)
32760484Sobrien    {
32877298Sobrien        Sum = (UINT8) (Sum + *(Buffer++));
32977298Sobrien    }
33077298Sobrien
33177298Sobrien    return Sum;
33260484Sobrien}
33360484Sobrien
33460484Sobrien
33577298Sobrien/*******************************************************************************
33660484Sobrien *
33760484Sobrien * FUNCTION:    AcpiTbCheckDsdtHeader
33860484Sobrien *
33960484Sobrien * PARAMETERS:  None
34077298Sobrien *
34177298Sobrien * RETURN:      None
34277298Sobrien *
34377298Sobrien * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect
34460484Sobrien *              if the DSDT has been replaced from outside the OS and/or if
34560484Sobrien *              the DSDT header has been corrupted.
34660484Sobrien *
34760484Sobrien ******************************************************************************/
34860484Sobrien
34960484Sobrienvoid
35060484SobrienAcpiTbCheckDsdtHeader (
35160484Sobrien    void)
35277298Sobrien{
35377298Sobrien
35477298Sobrien    /* Compare original length and checksum to current values */
35560484Sobrien
35660484Sobrien    if (AcpiGbl_OriginalDsdtHeader.Length != AcpiGbl_DSDT->Length ||
35777298Sobrien        AcpiGbl_OriginalDsdtHeader.Checksum != AcpiGbl_DSDT->Checksum)
35860484Sobrien    {
35960484Sobrien        ACPI_ERROR ((AE_INFO,
36089857Sobrien            "The DSDT has been corrupted or replaced - old, new headers below"));
36177298Sobrien        AcpiTbPrintTableHeader (0, &AcpiGbl_OriginalDsdtHeader);
36260484Sobrien        AcpiTbPrintTableHeader (0, AcpiGbl_DSDT);
36377298Sobrien
36460484Sobrien        /* Disable further error messages */
36560484Sobrien
36677298Sobrien        AcpiGbl_OriginalDsdtHeader.Length = AcpiGbl_DSDT->Length;
36760484Sobrien        AcpiGbl_OriginalDsdtHeader.Checksum = AcpiGbl_DSDT->Checksum;
36860484Sobrien    }
36960484Sobrien}
37060484Sobrien
37138889Sjdp
37238889Sjdp/*******************************************************************************
37338889Sjdp *
374130561Sobrien * FUNCTION:    AcpiTbCopyDsdt
37538889Sjdp *
37638889Sjdp * PARAMETERS:  TableDesc           - Installed table to copy
37733965Sjdp *
37838889Sjdp * RETURN:      None
37938889Sjdp *
38077298Sobrien * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory.
38138889Sjdp *              Some very bad BIOSs are known to either corrupt the DSDT or
38238889Sjdp *              install a new, bad DSDT. This copy works around the problem.
38338889Sjdp *
38460484Sobrien ******************************************************************************/
38538889Sjdp
38660484SobrienACPI_TABLE_HEADER *
38777298SobrienAcpiTbCopyDsdt (
38838889Sjdp    UINT32                  TableIndex)
38938889Sjdp{
39038889Sjdp    ACPI_TABLE_HEADER       *NewTable;
39138889Sjdp    ACPI_TABLE_DESC         *TableDesc;
39238889Sjdp
39338889Sjdp
39438889Sjdp    TableDesc = &AcpiGbl_RootTableList.Tables[TableIndex];
39538889Sjdp
39638889Sjdp    NewTable = ACPI_ALLOCATE (TableDesc->Length);
39738889Sjdp    if (!NewTable)
39838889Sjdp    {
39977298Sobrien        ACPI_ERROR ((AE_INFO, "Could not copy DSDT of length 0x%X",
40038889Sjdp            TableDesc->Length));
40138889Sjdp        return (NULL);
40238889Sjdp    }
40338889Sjdp
40438889Sjdp    ACPI_MEMCPY (NewTable, TableDesc->Pointer, TableDesc->Length);
40538889Sjdp    AcpiTbDeleteTable (TableDesc);
40638889Sjdp    TableDesc->Pointer = NewTable;
40738889Sjdp    TableDesc->Flags = ACPI_TABLE_ORIGIN_ALLOCATED;
40838889Sjdp
40938889Sjdp    ACPI_INFO ((AE_INFO,
41038889Sjdp        "Forced DSDT copy: length 0x%05X copied locally, original unmapped",
41138889Sjdp        NewTable->Length));
41238889Sjdp
41338889Sjdp    return (NewTable);
41438889Sjdp}
41533965Sjdp
41633965Sjdp
41733965Sjdp/*******************************************************************************
41833965Sjdp *
41933965Sjdp * FUNCTION:    AcpiTbInstallTable
42033965Sjdp *
42133965Sjdp * PARAMETERS:  Address                 - Physical address of DSDT or FACS
42233965Sjdp *              Signature               - Table signature, NULL if no need to
42333965Sjdp *                                        match
424130561Sobrien *              TableIndex              - Index into root table array
42533965Sjdp *
42633965Sjdp * RETURN:      None
42733965Sjdp *
42833965Sjdp * DESCRIPTION: Install an ACPI table into the global data structure. The
42933965Sjdp *              table override mechanism is called to allow the host
43033965Sjdp *              OS to replace any table before it is installed in the root
43133965Sjdp *              table array.
43233965Sjdp *
43333965Sjdp ******************************************************************************/
43433965Sjdp
43533965Sjdpvoid
43633965SjdpAcpiTbInstallTable (
43733965Sjdp    ACPI_PHYSICAL_ADDRESS   Address,
43833965Sjdp    char                    *Signature,
43933965Sjdp    UINT32                  TableIndex)
44033965Sjdp{
44133965Sjdp    ACPI_TABLE_HEADER       *Table;
44233965Sjdp    ACPI_TABLE_HEADER       *FinalTable;
44333965Sjdp    ACPI_TABLE_DESC         *TableDesc;
44433965Sjdp
44533965Sjdp
44677298Sobrien    if (!Address)
44777298Sobrien    {
44877298Sobrien        ACPI_ERROR ((AE_INFO, "Null physical address for ACPI table [%s]",
44933965Sjdp            Signature));
45033965Sjdp        return;
451130561Sobrien    }
45233965Sjdp
45333965Sjdp    /* Map just the table header */
45433965Sjdp
45533965Sjdp    Table = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
45633965Sjdp    if (!Table)
45733965Sjdp    {
45877298Sobrien        ACPI_ERROR ((AE_INFO, "Could not map memory for table [%s] at %p",
45938889Sjdp            Signature, ACPI_CAST_PTR (void, Address)));
46038889Sjdp        return;
46138889Sjdp    }
46238889Sjdp
46338889Sjdp    /* Skip SSDT when DSDT is overriden */
46433965Sjdp
46538889Sjdp    if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_SSDT) &&
46638889Sjdp       (AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Flags &
46738889Sjdp            ACPI_TABLE_ORIGIN_OVERRIDE))
46838889Sjdp    {
46938889Sjdp        ACPI_INFO ((AE_INFO,
47038889Sjdp            "%4.4s @ 0x%p Table override, replaced with:", ACPI_SIG_SSDT,
47138889Sjdp            ACPI_CAST_PTR (void, Address)));
47289857Sobrien        AcpiTbPrintTableHeader (
47338889Sjdp            AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Address,
47438889Sjdp            AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Pointer);
47538889Sjdp        goto UnmapAndExit;
47638889Sjdp    }
47738889Sjdp
47877298Sobrien    /* If a particular signature is expected (DSDT/FACS), it must match */
47938889Sjdp
48038889Sjdp    if (Signature &&
48177298Sobrien        !ACPI_COMPARE_NAME (Table->Signature, Signature))
48233965Sjdp    {
48333965Sjdp        ACPI_ERROR ((AE_INFO,
48438889Sjdp            "Invalid signature 0x%X for ACPI table, expected [%s]",
48533965Sjdp            *ACPI_CAST_PTR (UINT32, Table->Signature), Signature));
48677298Sobrien        goto UnmapAndExit;
48777298Sobrien    }
48833965Sjdp
48933965Sjdp    /*
49033965Sjdp     * Initialize the table entry. Set the pointer to NULL, since the
49133965Sjdp     * table is not fully mapped at this time.
49233965Sjdp     */
49333965Sjdp    TableDesc = &AcpiGbl_RootTableList.Tables[TableIndex];
49433965Sjdp
49538889Sjdp    TableDesc->Address = Address;
49633965Sjdp    TableDesc->Pointer = NULL;
49733965Sjdp    TableDesc->Length = Table->Length;
49833965Sjdp    TableDesc->Flags = ACPI_TABLE_ORIGIN_MAPPED;
49933965Sjdp    ACPI_MOVE_32_TO_32 (TableDesc->Signature.Ascii, Table->Signature);
50033965Sjdp
50189857Sobrien    /*
50289857Sobrien     * ACPI Table Override:
50389857Sobrien     *
50489857Sobrien     * Before we install the table, let the host OS override it with a new
50589857Sobrien     * one if desired. Any table within the RSDT/XSDT can be replaced,
50689857Sobrien     * including the DSDT which is pointed to by the FADT.
50733965Sjdp     *
50833965Sjdp     * NOTE: If the table is overridden, then FinalTable will contain a
50933965Sjdp     * mapped pointer to the full new table. If the table is not overridden,
51033965Sjdp     * or if there has been a physical override, then the table will be
51133965Sjdp     * fully mapped later (in verify table). In any case, we must
51233965Sjdp     * unmap the header that was mapped above.
51333965Sjdp     */
51433965Sjdp    FinalTable = AcpiTbTableOverride (Table, TableDesc);
51533965Sjdp    if (!FinalTable)
51633965Sjdp    {
51777298Sobrien        FinalTable = Table; /* There was no override */
51877298Sobrien    }
51977298Sobrien
52033965Sjdp    AcpiTbPrintTableHeader (TableDesc->Address, FinalTable);
52133965Sjdp
522130561Sobrien    /* Set the global integer width (based upon revision of the DSDT) */
52333965Sjdp
52433965Sjdp    if (TableIndex == ACPI_TABLE_INDEX_DSDT)
52577298Sobrien    {
52677298Sobrien        AcpiUtSetIntegerWidth (FinalTable->Revision);
52777298Sobrien    }
52833965Sjdp
52933965Sjdp    /*
53033965Sjdp     * If we have a physical override during this early loading of the ACPI
53133965Sjdp     * tables, unmap the table for now. It will be mapped again later when
53233965Sjdp     * it is actually used. This supports very early loading of ACPI tables,
53333965Sjdp     * before virtual memory is fully initialized and running within the
53433965Sjdp     * host OS. Note: A logical override has the ACPI_TABLE_ORIGIN_OVERRIDE
53533965Sjdp     * flag set and will not be deleted below.
53633965Sjdp     */
53733965Sjdp    if (FinalTable != Table)
53833965Sjdp    {
53933965Sjdp        AcpiTbDeleteTable (TableDesc);
54033965Sjdp    }
54133965Sjdp
54233965Sjdp
54333965SjdpUnmapAndExit:
54433965Sjdp
54533965Sjdp    /* Always unmap the table header that we mapped above */
54633965Sjdp
54733965Sjdp    AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER));
54833965Sjdp}
54933965Sjdp
55033965Sjdp
55133965Sjdp/*******************************************************************************
55233965Sjdp *
55333965Sjdp * FUNCTION:    AcpiTbGetRootTableEntry
55433965Sjdp *
55533965Sjdp * PARAMETERS:  TableEntry          - Pointer to the RSDT/XSDT table entry
55633965Sjdp *              TableEntrySize      - sizeof 32 or 64 (RSDT or XSDT)
55733965Sjdp *
55833965Sjdp * RETURN:      Physical address extracted from the root table
55933965Sjdp *
56033965Sjdp * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
56133965Sjdp *              both 32-bit and 64-bit platforms
56233965Sjdp *
56333965Sjdp * NOTE:        ACPI_PHYSICAL_ADDRESS is 32-bit on 32-bit platforms, 64-bit on
56433965Sjdp *              64-bit platforms.
565130561Sobrien *
56633965Sjdp ******************************************************************************/
56738889Sjdp
56833965Sjdpstatic ACPI_PHYSICAL_ADDRESS
56977298SobrienAcpiTbGetRootTableEntry (
57033965Sjdp    UINT8                   *TableEntry,
57133965Sjdp    UINT32                  TableEntrySize)
57260484Sobrien{
57333965Sjdp    UINT64                  Address64;
57477298Sobrien
57533965Sjdp
57633965Sjdp    /*
57733965Sjdp     * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
57833965Sjdp     * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
57933965Sjdp     */
58033965Sjdp    if (TableEntrySize == sizeof (UINT32))
58133965Sjdp    {
58233965Sjdp        /*
58377298Sobrien         * 32-bit platform, RSDT: Return 32-bit table entry
58433965Sjdp         * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
58533965Sjdp         */
58677298Sobrien        return ((ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST_PTR (UINT32, TableEntry)));
58760484Sobrien    }
58860484Sobrien    else
58938889Sjdp    {
59033965Sjdp        /*
59177298Sobrien         * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
592130561Sobrien         * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
59333965Sjdp         *  return 64-bit
59433965Sjdp         */
59533965Sjdp        ACPI_MOVE_64_TO_64 (&Address64, TableEntry);
59660484Sobrien
59733965Sjdp#if ACPI_MACHINE_WIDTH == 32
59860484Sobrien        if (Address64 > ACPI_UINT32_MAX)
59933965Sjdp        {
600104834Sobrien            /* Will truncate 64-bit address to 32 bits, issue warning */
601104834Sobrien
602104834Sobrien            ACPI_WARNING ((AE_INFO,
603104834Sobrien                "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
60433965Sjdp                " truncating",
605104834Sobrien                ACPI_FORMAT_UINT64 (Address64)));
606104834Sobrien        }
607104834Sobrien#endif
608104834Sobrien        return ((ACPI_PHYSICAL_ADDRESS) (Address64));
609104834Sobrien    }
610104834Sobrien}
611130561Sobrien
612130561Sobrien
613104834Sobrien/*******************************************************************************
614104834Sobrien *
615104834Sobrien * FUNCTION:    AcpiTbParseRootTable
616104834Sobrien *
61733965Sjdp * PARAMETERS:  Rsdp                    - Pointer to the RSDP
618104834Sobrien *
619104834Sobrien * RETURN:      Status
62033965Sjdp *
621104834Sobrien * DESCRIPTION: This function is called to parse the Root System Description
622104834Sobrien *              Table (RSDT or XSDT)
623104834Sobrien *
624104834Sobrien * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
62533965Sjdp *              be mapped and cannot be copied because it contains the actual
62633965Sjdp *              memory location of the ACPI Global Lock.
62733965Sjdp *
62838889Sjdp ******************************************************************************/
62933965Sjdp
63033965SjdpACPI_STATUS
63133965SjdpAcpiTbParseRootTable (
63233965Sjdp    ACPI_PHYSICAL_ADDRESS   RsdpAddress)
633130561Sobrien{
634130561Sobrien    ACPI_TABLE_RSDP         *Rsdp;
63533965Sjdp    UINT32                  TableEntrySize;
63633965Sjdp    UINT32                  i;
63733965Sjdp    UINT32                  TableCount;
63833965Sjdp    ACPI_TABLE_HEADER       *Table;
63960484Sobrien    ACPI_PHYSICAL_ADDRESS   Address;
64033965Sjdp    UINT32                  Length;
64160484Sobrien    UINT8                   *TableEntry;
64233965Sjdp    ACPI_STATUS             Status;
64377298Sobrien
64433965Sjdp
64538889Sjdp    ACPI_FUNCTION_TRACE (TbParseRootTable);
64677298Sobrien
64777298Sobrien
64877298Sobrien    /*
64933965Sjdp     * Map the entire RSDP and extract the address of the RSDT or XSDT
65033965Sjdp     */
65133965Sjdp    Rsdp = AcpiOsMapMemory (RsdpAddress, sizeof (ACPI_TABLE_RSDP));
65233965Sjdp    if (!Rsdp)
65333965Sjdp    {
65433965Sjdp        return_ACPI_STATUS (AE_NO_MEMORY);
65577298Sobrien    }
65677298Sobrien
65777298Sobrien    AcpiTbPrintTableHeader (RsdpAddress,
65833965Sjdp        ACPI_CAST_PTR (ACPI_TABLE_HEADER, Rsdp));
65933965Sjdp
66060484Sobrien    /* Differentiate between RSDT and XSDT root tables */
66133965Sjdp
66260484Sobrien    if (Rsdp->Revision > 1 && Rsdp->XsdtPhysicalAddress)
66360484Sobrien    {
66460484Sobrien        /*
66533965Sjdp         * Root table is an XSDT (64-bit physical addresses). We must use the
66660484Sobrien         * XSDT if the revision is > 1 and the XSDT pointer is present, as per
66760484Sobrien         * the ACPI specification.
66877298Sobrien         */
66960484Sobrien        Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->XsdtPhysicalAddress;
67060484Sobrien        TableEntrySize = sizeof (UINT64);
67160484Sobrien    }
67233965Sjdp    else
67360484Sobrien    {
67460484Sobrien        /* Root table is an RSDT (32-bit physical addresses) */
67577298Sobrien
67660484Sobrien        Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress;
67760484Sobrien        TableEntrySize = sizeof (UINT32);
67877298Sobrien    }
67960484Sobrien
68033965Sjdp    /*
68160484Sobrien     * It is not possible to map more than one entry in some environments,
68260484Sobrien     * so unmap the RSDP here before mapping other tables
68360484Sobrien     */
68433965Sjdp    AcpiOsUnmapMemory (Rsdp, sizeof (ACPI_TABLE_RSDP));
68577298Sobrien
68660484Sobrien
68760484Sobrien    /* Map the RSDT/XSDT table header to get the full table length */
68877298Sobrien
68960484Sobrien    Table = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
69060484Sobrien    if (!Table)
69177298Sobrien    {
69260484Sobrien        return_ACPI_STATUS (AE_NO_MEMORY);
69360484Sobrien    }
69460484Sobrien
69577298Sobrien    AcpiTbPrintTableHeader (Address, Table);
69660484Sobrien
69760484Sobrien    /* Get the length of the full table, verify length and map entire table */
69860484Sobrien
69960484Sobrien    Length = Table->Length;
70060484Sobrien    AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER));
70160484Sobrien
70277298Sobrien    if (Length < sizeof (ACPI_TABLE_HEADER))
70360484Sobrien    {
70460484Sobrien        ACPI_ERROR ((AE_INFO, "Invalid length 0x%X in RSDT/XSDT", Length));
70560484Sobrien        return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
70677298Sobrien    }
70760484Sobrien
70877298Sobrien    Table = AcpiOsMapMemory (Address, Length);
70933965Sjdp    if (!Table)
71077298Sobrien    {
71177298Sobrien        return_ACPI_STATUS (AE_NO_MEMORY);
71260484Sobrien    }
71377298Sobrien
71460484Sobrien    /* Validate the root table checksum */
71533965Sjdp
71677298Sobrien    Status = AcpiTbVerifyChecksum (Table, Length);
71777298Sobrien    if (ACPI_FAILURE (Status))
71877298Sobrien    {
71960484Sobrien        AcpiOsUnmapMemory (Table, Length);
72060484Sobrien        return_ACPI_STATUS (Status);
72160484Sobrien    }
72277298Sobrien
72360484Sobrien    /* Calculate the number of tables described in the root table */
72433965Sjdp
72533965Sjdp    TableCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) /
72633965Sjdp        TableEntrySize);
72760484Sobrien
72833965Sjdp    /*
72933965Sjdp     * First two entries in the table array are reserved for the DSDT
73077298Sobrien     * and FACS, which are not actually present in the RSDT/XSDT - they
73160484Sobrien     * come from the FADT
73277298Sobrien     */
73333965Sjdp    TableEntry = ACPI_CAST_PTR (UINT8, Table) + sizeof (ACPI_TABLE_HEADER);
73433965Sjdp    AcpiGbl_RootTableList.CurrentTableCount = 2;
73533965Sjdp
73633965Sjdp    /*
73733965Sjdp     * Initialize the root table array from the RSDT/XSDT
738130561Sobrien     */
73933965Sjdp    for (i = 0; i < TableCount; i++)
74033965Sjdp    {
74133965Sjdp        if (AcpiGbl_RootTableList.CurrentTableCount >=
74233965Sjdp            AcpiGbl_RootTableList.MaxTableCount)
74333965Sjdp        {
74433965Sjdp            /* There is no more room in the root table array, attempt resize */
74533965Sjdp
74633965Sjdp            Status = AcpiTbResizeRootTableList ();
74733965Sjdp            if (ACPI_FAILURE (Status))
74833965Sjdp            {
74938889Sjdp                ACPI_WARNING ((AE_INFO, "Truncating %u table entries!",
75038889Sjdp                    (unsigned) (TableCount -
75133965Sjdp                    (AcpiGbl_RootTableList.CurrentTableCount - 2))));
75238889Sjdp                break;
75360484Sobrien            }
75438889Sjdp        }
755218822Sdim
75633965Sjdp        /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
75733965Sjdp
75833965Sjdp        AcpiGbl_RootTableList.Tables[AcpiGbl_RootTableList.CurrentTableCount].Address =
75933965Sjdp            AcpiTbGetRootTableEntry (TableEntry, TableEntrySize);
76033965Sjdp
76133965Sjdp        TableEntry += TableEntrySize;
76233965Sjdp        AcpiGbl_RootTableList.CurrentTableCount++;
76333965Sjdp    }
76433965Sjdp
76533965Sjdp    /*
76633965Sjdp     * It is not possible to map more than one entry in some environments,
76733965Sjdp     * so unmap the root table here before mapping other tables
76833965Sjdp     */
76933965Sjdp    AcpiOsUnmapMemory (Table, Length);
77033965Sjdp
77133965Sjdp    /*
77233965Sjdp     * Complete the initialization of the root table array by examining
77333965Sjdp     * the header of each table
77433965Sjdp     */
77533965Sjdp    for (i = 2; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
77633965Sjdp    {
77733965Sjdp        AcpiTbInstallTable (AcpiGbl_RootTableList.Tables[i].Address,
77833965Sjdp            NULL, i);
77933965Sjdp
78033965Sjdp        /* Special case for FADT - get the DSDT and FACS */
78133965Sjdp
78233965Sjdp        if (ACPI_COMPARE_NAME (
78333965Sjdp                &AcpiGbl_RootTableList.Tables[i].Signature, ACPI_SIG_FADT))
78433965Sjdp        {
78560484Sobrien            AcpiTbParseFadt (i);
78638889Sjdp        }
78738889Sjdp    }
78860484Sobrien
78960484Sobrien    return_ACPI_STATUS (AE_OK);
79038889Sjdp}
79138889Sjdp