167754Smsmith/******************************************************************************
267754Smsmith *
3167802Sjkim * Module Name: tbutils   - table utilities
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8217365Sjkim * Copyright (C) 2000 - 2011, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
4467754Smsmith#define __TBUTILS_C__
4567754Smsmith
46193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
47193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
48193341Sjkim#include <contrib/dev/acpica/include/actables.h>
4967754Smsmith
5077424Smsmith#define _COMPONENT          ACPI_TABLES
5191116Smsmith        ACPI_MODULE_NAME    ("tbutils")
5267754Smsmith
53151937Sjkim/* Local prototypes */
5467754Smsmith
55197104Sjkimstatic void
56197104SjkimAcpiTbFixString (
57197104Sjkim    char                    *String,
58197104Sjkim    ACPI_SIZE               Length);
59197104Sjkim
60197104Sjkimstatic void
61197104SjkimAcpiTbCleanupTableHeader (
62197104Sjkim    ACPI_TABLE_HEADER       *OutHeader,
63197104Sjkim    ACPI_TABLE_HEADER       *Header);
64197104Sjkim
65167802Sjkimstatic ACPI_PHYSICAL_ADDRESS
66167802SjkimAcpiTbGetRootTableEntry (
67167802Sjkim    UINT8                   *TableEntry,
68193267Sjkim    UINT32                  TableEntrySize);
69151937Sjkim
70151937Sjkim
7167754Smsmith/*******************************************************************************
7267754Smsmith *
73193267Sjkim * FUNCTION:    AcpiTbInitializeFacs
74193267Sjkim *
75193267Sjkim * PARAMETERS:  None
76193267Sjkim *
77193267Sjkim * RETURN:      Status
78193267Sjkim *
79193267Sjkim * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global
80193267Sjkim *              for accessing the Global Lock and Firmware Waking Vector
81193267Sjkim *
82193267Sjkim ******************************************************************************/
83193267Sjkim
84193267SjkimACPI_STATUS
85193267SjkimAcpiTbInitializeFacs (
86193267Sjkim    void)
87193267Sjkim{
88193267Sjkim    ACPI_STATUS             Status;
89193267Sjkim
90193267Sjkim
91193267Sjkim    Status = AcpiGetTableByIndex (ACPI_TABLE_INDEX_FACS,
92193267Sjkim                ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &AcpiGbl_FACS));
93193267Sjkim    return (Status);
94193267Sjkim}
95193267Sjkim
96193267Sjkim
97193267Sjkim/*******************************************************************************
98193267Sjkim *
99167802Sjkim * FUNCTION:    AcpiTbTablesLoaded
10067754Smsmith *
101167802Sjkim * PARAMETERS:  None
10267754Smsmith *
103167802Sjkim * RETURN:      TRUE if required ACPI tables are loaded
10467754Smsmith *
105167802Sjkim * DESCRIPTION: Determine if the minimum required ACPI tables are present
106167802Sjkim *              (FADT, FACS, DSDT)
107151937Sjkim *
10867754Smsmith ******************************************************************************/
10967754Smsmith
110167802SjkimBOOLEAN
111167802SjkimAcpiTbTablesLoaded (
112167802Sjkim    void)
11367754Smsmith{
11467754Smsmith
115207344Sjkim    if (AcpiGbl_RootTableList.CurrentTableCount >= 3)
116167802Sjkim    {
117167802Sjkim        return (TRUE);
118167802Sjkim    }
11983174Smsmith
120167802Sjkim    return (FALSE);
121167802Sjkim}
12267754Smsmith
12382367Smsmith
124167802Sjkim/*******************************************************************************
125167802Sjkim *
126197104Sjkim * FUNCTION:    AcpiTbFixString
127197104Sjkim *
128197104Sjkim * PARAMETERS:  String              - String to be repaired
129197104Sjkim *              Length              - Maximum length
130197104Sjkim *
131197104Sjkim * RETURN:      None
132197104Sjkim *
133197104Sjkim * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
134197104Sjkim *              with a question mark '?'.
135197104Sjkim *
136197104Sjkim ******************************************************************************/
137197104Sjkim
138197104Sjkimstatic void
139197104SjkimAcpiTbFixString (
140197104Sjkim    char                    *String,
141197104Sjkim    ACPI_SIZE               Length)
142197104Sjkim{
143197104Sjkim
144197104Sjkim    while (Length && *String)
145197104Sjkim    {
146197104Sjkim        if (!ACPI_IS_PRINT (*String))
147197104Sjkim        {
148197104Sjkim            *String = '?';
149197104Sjkim        }
150197104Sjkim        String++;
151197104Sjkim        Length--;
152197104Sjkim    }
153197104Sjkim}
154197104Sjkim
155197104Sjkim
156197104Sjkim/*******************************************************************************
157197104Sjkim *
158197104Sjkim * FUNCTION:    AcpiTbCleanupTableHeader
159197104Sjkim *
160197104Sjkim * PARAMETERS:  OutHeader           - Where the cleaned header is returned
161197104Sjkim *              Header              - Input ACPI table header
162197104Sjkim *
163197104Sjkim * RETURN:      Returns the cleaned header in OutHeader
164197104Sjkim *
165197104Sjkim * DESCRIPTION: Copy the table header and ensure that all "string" fields in
166197104Sjkim *              the header consist of printable characters.
167197104Sjkim *
168197104Sjkim ******************************************************************************/
169197104Sjkim
170197104Sjkimstatic void
171197104SjkimAcpiTbCleanupTableHeader (
172197104Sjkim    ACPI_TABLE_HEADER       *OutHeader,
173197104Sjkim    ACPI_TABLE_HEADER       *Header)
174197104Sjkim{
175197104Sjkim
176197104Sjkim    ACPI_MEMCPY (OutHeader, Header, sizeof (ACPI_TABLE_HEADER));
177197104Sjkim
178197104Sjkim    AcpiTbFixString (OutHeader->Signature, ACPI_NAME_SIZE);
179197104Sjkim    AcpiTbFixString (OutHeader->OemId, ACPI_OEM_ID_SIZE);
180197104Sjkim    AcpiTbFixString (OutHeader->OemTableId, ACPI_OEM_TABLE_ID_SIZE);
181197104Sjkim    AcpiTbFixString (OutHeader->AslCompilerId, ACPI_NAME_SIZE);
182197104Sjkim}
183197104Sjkim
184197104Sjkim
185197104Sjkim/*******************************************************************************
186197104Sjkim *
187167802Sjkim * FUNCTION:    AcpiTbPrintTableHeader
188167802Sjkim *
189167802Sjkim * PARAMETERS:  Address             - Table physical address
190167802Sjkim *              Header              - Table header
191167802Sjkim *
192167802Sjkim * RETURN:      None
193167802Sjkim *
194167802Sjkim * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
195167802Sjkim *
196167802Sjkim ******************************************************************************/
197151937Sjkim
198167802Sjkimvoid
199167802SjkimAcpiTbPrintTableHeader (
200167802Sjkim    ACPI_PHYSICAL_ADDRESS   Address,
201167802Sjkim    ACPI_TABLE_HEADER       *Header)
202167802Sjkim{
203197104Sjkim    ACPI_TABLE_HEADER       LocalHeader;
204151937Sjkim
205197104Sjkim
206193267Sjkim    /*
207193267Sjkim     * The reason that the Address is cast to a void pointer is so that we
208193267Sjkim     * can use %p which will work properly on both 32-bit and 64-bit hosts.
209193267Sjkim     */
210167802Sjkim    if (ACPI_COMPARE_NAME (Header->Signature, ACPI_SIG_FACS))
211167802Sjkim    {
212193267Sjkim        /* FACS only has signature and length fields */
213151937Sjkim
214193267Sjkim        ACPI_INFO ((AE_INFO, "%4.4s %p %05X",
215193267Sjkim            Header->Signature, ACPI_CAST_PTR (void, Address),
216193267Sjkim            Header->Length));
217167802Sjkim    }
218167802Sjkim    else if (ACPI_COMPARE_NAME (Header->Signature, ACPI_SIG_RSDP))
21967754Smsmith    {
220167802Sjkim        /* RSDP has no common fields */
22167754Smsmith
222197104Sjkim        ACPI_MEMCPY (LocalHeader.OemId,
223197104Sjkim            ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->OemId, ACPI_OEM_ID_SIZE);
224197104Sjkim        AcpiTbFixString (LocalHeader.OemId, ACPI_OEM_ID_SIZE);
225197104Sjkim
226193267Sjkim        ACPI_INFO ((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
227167802Sjkim            ACPI_CAST_PTR (void, Address),
228167802Sjkim            (ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision > 0) ?
229167802Sjkim                ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Length : 20,
230167802Sjkim            ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision,
231197104Sjkim            LocalHeader.OemId));
232167802Sjkim    }
233167802Sjkim    else
234167802Sjkim    {
235167802Sjkim        /* Standard ACPI table with full common header */
236151937Sjkim
237197104Sjkim        AcpiTbCleanupTableHeader (&LocalHeader, Header);
238197104Sjkim
239167802Sjkim        ACPI_INFO ((AE_INFO,
240193267Sjkim            "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
241197104Sjkim            LocalHeader.Signature, ACPI_CAST_PTR (void, Address),
242197104Sjkim            LocalHeader.Length, LocalHeader.Revision, LocalHeader.OemId,
243197104Sjkim            LocalHeader.OemTableId, LocalHeader.OemRevision,
244197104Sjkim            LocalHeader.AslCompilerId, LocalHeader.AslCompilerRevision));
24567754Smsmith    }
24667754Smsmith}
24767754Smsmith
24867754Smsmith
24967754Smsmith/*******************************************************************************
25067754Smsmith *
251167802Sjkim * FUNCTION:    AcpiTbValidateChecksum
25267754Smsmith *
253167802Sjkim * PARAMETERS:  Table               - ACPI table to verify
254167802Sjkim *              Length              - Length of entire table
25567754Smsmith *
25667754Smsmith * RETURN:      Status
25767754Smsmith *
258167802Sjkim * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
259167802Sjkim *              exception on bad checksum.
26067754Smsmith *
26167754Smsmith ******************************************************************************/
26267754Smsmith
26367754SmsmithACPI_STATUS
264167802SjkimAcpiTbVerifyChecksum (
265167802Sjkim    ACPI_TABLE_HEADER       *Table,
266167802Sjkim    UINT32                  Length)
26767754Smsmith{
268167802Sjkim    UINT8                   Checksum;
26967754Smsmith
27067754Smsmith
271167802Sjkim    /* Compute the checksum on the table */
27277424Smsmith
273167802Sjkim    Checksum = AcpiTbChecksum (ACPI_CAST_PTR (UINT8, Table), Length);
27477424Smsmith
275167802Sjkim    /* Checksum ok? (should be zero) */
27667754Smsmith
277167802Sjkim    if (Checksum)
27867754Smsmith    {
279167802Sjkim        ACPI_WARNING ((AE_INFO,
280204773Sjkim            "Incorrect checksum in table [%4.4s] - 0x%2.2X, should be 0x%2.2X",
281193267Sjkim            Table->Signature, Table->Checksum,
282193267Sjkim            (UINT8) (Table->Checksum - Checksum)));
283151937Sjkim
284167802Sjkim#if (ACPI_CHECKSUM_ABORT)
285167802Sjkim        return (AE_BAD_CHECKSUM);
286167802Sjkim#endif
28767754Smsmith    }
28867754Smsmith
289167802Sjkim    return (AE_OK);
290167802Sjkim}
29167754Smsmith
29267754Smsmith
293167802Sjkim/*******************************************************************************
294167802Sjkim *
295167802Sjkim * FUNCTION:    AcpiTbChecksum
296167802Sjkim *
297167802Sjkim * PARAMETERS:  Buffer          - Pointer to memory region to be checked
298167802Sjkim *              Length          - Length of this memory region
299167802Sjkim *
300167802Sjkim * RETURN:      Checksum (UINT8)
301167802Sjkim *
302167802Sjkim * DESCRIPTION: Calculates circular checksum of memory region.
303167802Sjkim *
304167802Sjkim ******************************************************************************/
305151937Sjkim
306167802SjkimUINT8
307167802SjkimAcpiTbChecksum (
308167802Sjkim    UINT8                   *Buffer,
309193267Sjkim    UINT32                  Length)
310167802Sjkim{
311167802Sjkim    UINT8                   Sum = 0;
312167802Sjkim    UINT8                   *End = Buffer + Length;
31367754Smsmith
31467754Smsmith
315167802Sjkim    while (Buffer < End)
31667754Smsmith    {
317167802Sjkim        Sum = (UINT8) (Sum + *(Buffer++));
31867754Smsmith    }
31967754Smsmith
320167802Sjkim    return Sum;
32167754Smsmith}
32267754Smsmith
32367754Smsmith
32467754Smsmith/*******************************************************************************
32567754Smsmith *
326206117Sjkim * FUNCTION:    AcpiTbCheckDsdtHeader
327206117Sjkim *
328206117Sjkim * PARAMETERS:  None
329206117Sjkim *
330206117Sjkim * RETURN:      None
331206117Sjkim *
332206117Sjkim * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect
333206117Sjkim *              if the DSDT has been replaced from outside the OS and/or if
334206117Sjkim *              the DSDT header has been corrupted.
335206117Sjkim *
336206117Sjkim ******************************************************************************/
337206117Sjkim
338206117Sjkimvoid
339206117SjkimAcpiTbCheckDsdtHeader (
340206117Sjkim    void)
341206117Sjkim{
342206117Sjkim
343206117Sjkim    /* Compare original length and checksum to current values */
344206117Sjkim
345206117Sjkim    if (AcpiGbl_OriginalDsdtHeader.Length != AcpiGbl_DSDT->Length ||
346206117Sjkim        AcpiGbl_OriginalDsdtHeader.Checksum != AcpiGbl_DSDT->Checksum)
347206117Sjkim    {
348206117Sjkim        ACPI_ERROR ((AE_INFO,
349206117Sjkim            "The DSDT has been corrupted or replaced - old, new headers below"));
350206117Sjkim        AcpiTbPrintTableHeader (0, &AcpiGbl_OriginalDsdtHeader);
351206117Sjkim        AcpiTbPrintTableHeader (0, AcpiGbl_DSDT);
352206117Sjkim
353206117Sjkim        /* Disable further error messages */
354206117Sjkim
355206117Sjkim        AcpiGbl_OriginalDsdtHeader.Length = AcpiGbl_DSDT->Length;
356206117Sjkim        AcpiGbl_OriginalDsdtHeader.Checksum = AcpiGbl_DSDT->Checksum;
357206117Sjkim    }
358206117Sjkim}
359206117Sjkim
360206117Sjkim
361206117Sjkim/*******************************************************************************
362206117Sjkim *
363206117Sjkim * FUNCTION:    AcpiTbCopyDsdt
364206117Sjkim *
365206117Sjkim * PARAMETERS:  TableDesc           - Installed table to copy
366206117Sjkim *
367206117Sjkim * RETURN:      None
368206117Sjkim *
369206117Sjkim * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory.
370206117Sjkim *              Some very bad BIOSs are known to either corrupt the DSDT or
371206117Sjkim *              install a new, bad DSDT. This copy works around the problem.
372206117Sjkim *
373206117Sjkim ******************************************************************************/
374206117Sjkim
375206117SjkimACPI_TABLE_HEADER *
376206117SjkimAcpiTbCopyDsdt (
377206117Sjkim    UINT32                  TableIndex)
378206117Sjkim{
379206117Sjkim    ACPI_TABLE_HEADER       *NewTable;
380206117Sjkim    ACPI_TABLE_DESC         *TableDesc;
381206117Sjkim
382206117Sjkim
383206117Sjkim    TableDesc = &AcpiGbl_RootTableList.Tables[TableIndex];
384206117Sjkim
385206117Sjkim    NewTable = ACPI_ALLOCATE (TableDesc->Length);
386206117Sjkim    if (!NewTable)
387206117Sjkim    {
388206117Sjkim        ACPI_ERROR ((AE_INFO, "Could not copy DSDT of length 0x%X",
389206117Sjkim            TableDesc->Length));
390206117Sjkim        return (NULL);
391206117Sjkim    }
392206117Sjkim
393206117Sjkim    ACPI_MEMCPY (NewTable, TableDesc->Pointer, TableDesc->Length);
394206117Sjkim    AcpiTbDeleteTable (TableDesc);
395206117Sjkim    TableDesc->Pointer = NewTable;
396206117Sjkim    TableDesc->Flags = ACPI_TABLE_ORIGIN_ALLOCATED;
397206117Sjkim
398206117Sjkim    ACPI_INFO ((AE_INFO,
399206117Sjkim        "Forced DSDT copy: length 0x%05X copied locally, original unmapped",
400206117Sjkim        NewTable->Length));
401206117Sjkim
402206117Sjkim    return (NewTable);
403206117Sjkim}
404206117Sjkim
405206117Sjkim
406206117Sjkim/*******************************************************************************
407206117Sjkim *
408167802Sjkim * FUNCTION:    AcpiTbInstallTable
40967754Smsmith *
410167802Sjkim * PARAMETERS:  Address                 - Physical address of DSDT or FACS
411167802Sjkim *              Signature               - Table signature, NULL if no need to
412167802Sjkim *                                        match
413167802Sjkim *              TableIndex              - Index into root table array
41467754Smsmith *
415167802Sjkim * RETURN:      None
41667754Smsmith *
417193267Sjkim * DESCRIPTION: Install an ACPI table into the global data structure. The
418193267Sjkim *              table override mechanism is implemented here to allow the host
419193267Sjkim *              OS to replace any table before it is installed in the root
420193267Sjkim *              table array.
42167754Smsmith *
42267754Smsmith ******************************************************************************/
42367754Smsmith
424167802Sjkimvoid
425167802SjkimAcpiTbInstallTable (
426167802Sjkim    ACPI_PHYSICAL_ADDRESS   Address,
427167802Sjkim    char                    *Signature,
428193267Sjkim    UINT32                  TableIndex)
42967754Smsmith{
430193267Sjkim    UINT8                   Flags;
431193267Sjkim    ACPI_STATUS             Status;
432193267Sjkim    ACPI_TABLE_HEADER       *TableToInstall;
433193267Sjkim    ACPI_TABLE_HEADER       *MappedTable;
434193267Sjkim    ACPI_TABLE_HEADER       *OverrideTable = NULL;
43567754Smsmith
43667754Smsmith
437167802Sjkim    if (!Address)
438167802Sjkim    {
439167802Sjkim        ACPI_ERROR ((AE_INFO, "Null physical address for ACPI table [%s]",
440167802Sjkim            Signature));
441167802Sjkim        return;
442167802Sjkim    }
44367754Smsmith
444167802Sjkim    /* Map just the table header */
44567754Smsmith
446193267Sjkim    MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
447193267Sjkim    if (!MappedTable)
448167802Sjkim    {
449167802Sjkim        return;
450167802Sjkim    }
45167754Smsmith
452193453Sjkim    /* Skip SSDT when DSDT is overriden */
453193453Sjkim
454193453Sjkim    if (ACPI_COMPARE_NAME (MappedTable->Signature, ACPI_SIG_SSDT) &&
455193453Sjkim       (AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Flags &
456193453Sjkim            ACPI_TABLE_ORIGIN_OVERRIDE))
457193453Sjkim    {
458193453Sjkim        ACPI_INFO ((AE_INFO,
459193453Sjkim            "%4.4s @ 0x%p Table override, replaced with:", ACPI_SIG_SSDT,
460193453Sjkim            ACPI_CAST_PTR (void, Address)));
461193453Sjkim        AcpiTbPrintTableHeader (
462193453Sjkim            AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Address,
463193453Sjkim            AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Pointer);
464193453Sjkim        goto UnmapAndExit;
465193453Sjkim    }
466193453Sjkim
467193267Sjkim    /* If a particular signature is expected (DSDT/FACS), it must match */
46867754Smsmith
469167802Sjkim    if (Signature &&
470193267Sjkim        !ACPI_COMPARE_NAME (MappedTable->Signature, Signature))
471167802Sjkim    {
472193267Sjkim        ACPI_ERROR ((AE_INFO,
473193267Sjkim            "Invalid signature 0x%X for ACPI table, expected [%s]",
474193267Sjkim            *ACPI_CAST_PTR (UINT32, MappedTable->Signature), Signature));
475167802Sjkim        goto UnmapAndExit;
476167802Sjkim    }
47767754Smsmith
478193267Sjkim    /*
479193267Sjkim     * ACPI Table Override:
480193267Sjkim     *
481193267Sjkim     * Before we install the table, let the host OS override it with a new
482193267Sjkim     * one if desired. Any table within the RSDT/XSDT can be replaced,
483193267Sjkim     * including the DSDT which is pointed to by the FADT.
484193267Sjkim     */
485193267Sjkim    Status = AcpiOsTableOverride (MappedTable, &OverrideTable);
486193267Sjkim    if (ACPI_SUCCESS (Status) && OverrideTable)
487193267Sjkim    {
488193267Sjkim        ACPI_INFO ((AE_INFO,
489193267Sjkim            "%4.4s @ 0x%p Table override, replaced with:",
490193267Sjkim            MappedTable->Signature, ACPI_CAST_PTR (void, Address)));
491193267Sjkim
492193267Sjkim        AcpiGbl_RootTableList.Tables[TableIndex].Pointer = OverrideTable;
493193267Sjkim        Address = ACPI_PTR_TO_PHYSADDR (OverrideTable);
494193267Sjkim
495193267Sjkim        TableToInstall = OverrideTable;
496193267Sjkim        Flags = ACPI_TABLE_ORIGIN_OVERRIDE;
497193267Sjkim    }
498193267Sjkim    else
499193267Sjkim    {
500193267Sjkim        TableToInstall = MappedTable;
501193267Sjkim        Flags = ACPI_TABLE_ORIGIN_MAPPED;
502193267Sjkim    }
503193267Sjkim
504167802Sjkim    /* Initialize the table entry */
505167802Sjkim
506167802Sjkim    AcpiGbl_RootTableList.Tables[TableIndex].Address = Address;
507193267Sjkim    AcpiGbl_RootTableList.Tables[TableIndex].Length = TableToInstall->Length;
508167802Sjkim    AcpiGbl_RootTableList.Tables[TableIndex].Flags = Flags;
509167802Sjkim
510167802Sjkim    ACPI_MOVE_32_TO_32 (
511167802Sjkim        &(AcpiGbl_RootTableList.Tables[TableIndex].Signature),
512193267Sjkim        TableToInstall->Signature);
513167802Sjkim
514193267Sjkim    AcpiTbPrintTableHeader (Address, TableToInstall);
515167802Sjkim
516167802Sjkim    if (TableIndex == ACPI_TABLE_INDEX_DSDT)
51767754Smsmith    {
518167802Sjkim        /* Global integer width is based upon revision of the DSDT */
51967754Smsmith
520193267Sjkim        AcpiUtSetIntegerWidth (TableToInstall->Revision);
52167754Smsmith    }
522167802Sjkim
523167802SjkimUnmapAndExit:
524193267Sjkim    AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
52567754Smsmith}
52667754Smsmith
52767754Smsmith
52867754Smsmith/*******************************************************************************
52967754Smsmith *
530167802Sjkim * FUNCTION:    AcpiTbGetRootTableEntry
53167754Smsmith *
532167802Sjkim * PARAMETERS:  TableEntry          - Pointer to the RSDT/XSDT table entry
533167802Sjkim *              TableEntrySize      - sizeof 32 or 64 (RSDT or XSDT)
53467754Smsmith *
535167802Sjkim * RETURN:      Physical address extracted from the root table
53667754Smsmith *
537167802Sjkim * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
538167802Sjkim *              both 32-bit and 64-bit platforms
53967754Smsmith *
540167802Sjkim * NOTE:        ACPI_PHYSICAL_ADDRESS is 32-bit on 32-bit platforms, 64-bit on
541167802Sjkim *              64-bit platforms.
542167802Sjkim *
54367754Smsmith ******************************************************************************/
54467754Smsmith
545167802Sjkimstatic ACPI_PHYSICAL_ADDRESS
546167802SjkimAcpiTbGetRootTableEntry (
547167802Sjkim    UINT8                   *TableEntry,
548193267Sjkim    UINT32                  TableEntrySize)
54967754Smsmith{
550167802Sjkim    UINT64                  Address64;
55167754Smsmith
55267754Smsmith
553167802Sjkim    /*
554167802Sjkim     * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
555167802Sjkim     * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
556167802Sjkim     */
557167802Sjkim    if (TableEntrySize == sizeof (UINT32))
55867754Smsmith    {
559167802Sjkim        /*
560167802Sjkim         * 32-bit platform, RSDT: Return 32-bit table entry
561167802Sjkim         * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
562167802Sjkim         */
563167802Sjkim        return ((ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST_PTR (UINT32, TableEntry)));
564167802Sjkim    }
565167802Sjkim    else
566167802Sjkim    {
567167802Sjkim        /*
568167802Sjkim         * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
569193267Sjkim         * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
570193267Sjkim         *  return 64-bit
571167802Sjkim         */
572167802Sjkim        ACPI_MOVE_64_TO_64 (&Address64, TableEntry);
57367754Smsmith
574167802Sjkim#if ACPI_MACHINE_WIDTH == 32
575167802Sjkim        if (Address64 > ACPI_UINT32_MAX)
576167802Sjkim        {
577167802Sjkim            /* Will truncate 64-bit address to 32 bits, issue warning */
57867754Smsmith
579167802Sjkim            ACPI_WARNING ((AE_INFO,
580204773Sjkim                "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
581193267Sjkim                " truncating",
582167802Sjkim                ACPI_FORMAT_UINT64 (Address64)));
58367754Smsmith        }
584167802Sjkim#endif
585167802Sjkim        return ((ACPI_PHYSICAL_ADDRESS) (Address64));
58667754Smsmith    }
58767754Smsmith}
58867754Smsmith
58967754Smsmith
590151937Sjkim/*******************************************************************************
591151937Sjkim *
592167802Sjkim * FUNCTION:    AcpiTbParseRootTable
593151937Sjkim *
594167802Sjkim * PARAMETERS:  Rsdp                    - Pointer to the RSDP
595151937Sjkim *
596167802Sjkim * RETURN:      Status
597151937Sjkim *
598167802Sjkim * DESCRIPTION: This function is called to parse the Root System Description
599167802Sjkim *              Table (RSDT or XSDT)
600167802Sjkim *
601167802Sjkim * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
602167802Sjkim *              be mapped and cannot be copied because it contains the actual
603167802Sjkim *              memory location of the ACPI Global Lock.
604167802Sjkim *
605151937Sjkim ******************************************************************************/
606151937Sjkim
607151937SjkimACPI_STATUS
608167802SjkimAcpiTbParseRootTable (
609193267Sjkim    ACPI_PHYSICAL_ADDRESS   RsdpAddress)
610151937Sjkim{
611167802Sjkim    ACPI_TABLE_RSDP         *Rsdp;
612193267Sjkim    UINT32                  TableEntrySize;
613193267Sjkim    UINT32                  i;
614167802Sjkim    UINT32                  TableCount;
615167802Sjkim    ACPI_TABLE_HEADER       *Table;
616167802Sjkim    ACPI_PHYSICAL_ADDRESS   Address;
617167802Sjkim    UINT32                  Length;
618167802Sjkim    UINT8                   *TableEntry;
619167802Sjkim    ACPI_STATUS             Status;
620151937Sjkim
621151937Sjkim
622167802Sjkim    ACPI_FUNCTION_TRACE (TbParseRootTable);
623151937Sjkim
624151937Sjkim
625167802Sjkim    /*
626167802Sjkim     * Map the entire RSDP and extract the address of the RSDT or XSDT
627167802Sjkim     */
628167802Sjkim    Rsdp = AcpiOsMapMemory (RsdpAddress, sizeof (ACPI_TABLE_RSDP));
629167802Sjkim    if (!Rsdp)
630151937Sjkim    {
631167802Sjkim        return_ACPI_STATUS (AE_NO_MEMORY);
632167802Sjkim    }
633167802Sjkim
634193267Sjkim    AcpiTbPrintTableHeader (RsdpAddress,
635193267Sjkim        ACPI_CAST_PTR (ACPI_TABLE_HEADER, Rsdp));
636167802Sjkim
637167802Sjkim    /* Differentiate between RSDT and XSDT root tables */
638167802Sjkim
639167802Sjkim    if (Rsdp->Revision > 1 && Rsdp->XsdtPhysicalAddress)
640167802Sjkim    {
641167802Sjkim        /*
642167802Sjkim         * Root table is an XSDT (64-bit physical addresses). We must use the
643167802Sjkim         * XSDT if the revision is > 1 and the XSDT pointer is present, as per
644167802Sjkim         * the ACPI specification.
645167802Sjkim         */
646167802Sjkim        Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->XsdtPhysicalAddress;
647167802Sjkim        TableEntrySize = sizeof (UINT64);
648167802Sjkim    }
649167802Sjkim    else
650167802Sjkim    {
651167802Sjkim        /* Root table is an RSDT (32-bit physical addresses) */
652167802Sjkim
653167802Sjkim        Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress;
654167802Sjkim        TableEntrySize = sizeof (UINT32);
655167802Sjkim    }
656167802Sjkim
657167802Sjkim    /*
658167802Sjkim     * It is not possible to map more than one entry in some environments,
659167802Sjkim     * so unmap the RSDP here before mapping other tables
660167802Sjkim     */
661167802Sjkim    AcpiOsUnmapMemory (Rsdp, sizeof (ACPI_TABLE_RSDP));
662167802Sjkim
663167802Sjkim
664167802Sjkim    /* Map the RSDT/XSDT table header to get the full table length */
665167802Sjkim
666167802Sjkim    Table = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
667167802Sjkim    if (!Table)
668167802Sjkim    {
669167802Sjkim        return_ACPI_STATUS (AE_NO_MEMORY);
670167802Sjkim    }
671167802Sjkim
672167802Sjkim    AcpiTbPrintTableHeader (Address, Table);
673167802Sjkim
674167802Sjkim    /* Get the length of the full table, verify length and map entire table */
675167802Sjkim
676167802Sjkim    Length = Table->Length;
677167802Sjkim    AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER));
678167802Sjkim
679167802Sjkim    if (Length < sizeof (ACPI_TABLE_HEADER))
680167802Sjkim    {
681167802Sjkim        ACPI_ERROR ((AE_INFO, "Invalid length 0x%X in RSDT/XSDT", Length));
682167802Sjkim        return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
683167802Sjkim    }
684167802Sjkim
685167802Sjkim    Table = AcpiOsMapMemory (Address, Length);
686167802Sjkim    if (!Table)
687167802Sjkim    {
688167802Sjkim        return_ACPI_STATUS (AE_NO_MEMORY);
689167802Sjkim    }
690167802Sjkim
691167802Sjkim    /* Validate the root table checksum */
692167802Sjkim
693167802Sjkim    Status = AcpiTbVerifyChecksum (Table, Length);
694167802Sjkim    if (ACPI_FAILURE (Status))
695167802Sjkim    {
696167802Sjkim        AcpiOsUnmapMemory (Table, Length);
697167802Sjkim        return_ACPI_STATUS (Status);
698167802Sjkim    }
699167802Sjkim
700167802Sjkim    /* Calculate the number of tables described in the root table */
701167802Sjkim
702193267Sjkim    TableCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) /
703193267Sjkim        TableEntrySize);
704167802Sjkim
705167802Sjkim    /*
706193267Sjkim     * First two entries in the table array are reserved for the DSDT
707193267Sjkim     * and FACS, which are not actually present in the RSDT/XSDT - they
708193267Sjkim     * come from the FADT
709167802Sjkim     */
710167802Sjkim    TableEntry = ACPI_CAST_PTR (UINT8, Table) + sizeof (ACPI_TABLE_HEADER);
711207344Sjkim    AcpiGbl_RootTableList.CurrentTableCount = 2;
712167802Sjkim
713167802Sjkim    /*
714167802Sjkim     * Initialize the root table array from the RSDT/XSDT
715167802Sjkim     */
716167802Sjkim    for (i = 0; i < TableCount; i++)
717167802Sjkim    {
718207344Sjkim        if (AcpiGbl_RootTableList.CurrentTableCount >=
719207344Sjkim            AcpiGbl_RootTableList.MaxTableCount)
720151937Sjkim        {
721167802Sjkim            /* There is no more room in the root table array, attempt resize */
722167802Sjkim
723167802Sjkim            Status = AcpiTbResizeRootTableList ();
724167802Sjkim            if (ACPI_FAILURE (Status))
725151937Sjkim            {
726167802Sjkim                ACPI_WARNING ((AE_INFO, "Truncating %u table entries!",
727193267Sjkim                    (unsigned) (TableCount -
728207344Sjkim                    (AcpiGbl_RootTableList.CurrentTableCount - 2))));
729167802Sjkim                break;
730151937Sjkim            }
731167802Sjkim        }
732151937Sjkim
733167802Sjkim        /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
734167802Sjkim
735207344Sjkim        AcpiGbl_RootTableList.Tables[AcpiGbl_RootTableList.CurrentTableCount].Address =
736167802Sjkim            AcpiTbGetRootTableEntry (TableEntry, TableEntrySize);
737167802Sjkim
738167802Sjkim        TableEntry += TableEntrySize;
739207344Sjkim        AcpiGbl_RootTableList.CurrentTableCount++;
740167802Sjkim    }
741167802Sjkim
742167802Sjkim    /*
743167802Sjkim     * It is not possible to map more than one entry in some environments,
744167802Sjkim     * so unmap the root table here before mapping other tables
745167802Sjkim     */
746167802Sjkim    AcpiOsUnmapMemory (Table, Length);
747167802Sjkim
748167802Sjkim    /*
749167802Sjkim     * Complete the initialization of the root table array by examining
750167802Sjkim     * the header of each table
751167802Sjkim     */
752207344Sjkim    for (i = 2; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
753167802Sjkim    {
754167802Sjkim        AcpiTbInstallTable (AcpiGbl_RootTableList.Tables[i].Address,
755193267Sjkim            NULL, i);
756167802Sjkim
757167802Sjkim        /* Special case for FADT - get the DSDT and FACS */
758167802Sjkim
759167802Sjkim        if (ACPI_COMPARE_NAME (
760167802Sjkim                &AcpiGbl_RootTableList.Tables[i].Signature, ACPI_SIG_FADT))
761167802Sjkim        {
762193267Sjkim            AcpiTbParseFadt (i);
763151937Sjkim        }
764151937Sjkim    }
765151937Sjkim
766167802Sjkim    return_ACPI_STATUS (AE_OK);
767151937Sjkim}
768