1/******************************************************************************
2 *
3 * Module Name: osbsdtbl - BSD OSL for obtaining ACPI tables
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 "acpidump.h"
45
46#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__DragonFly__)
47#include <kenv.h>
48#endif
49#include <unistd.h>
50#include <sys/param.h>
51#include <sys/sysctl.h>
52
53
54#define _COMPONENT          ACPI_OS_SERVICES
55        ACPI_MODULE_NAME    ("osbsdtbl")
56
57
58/* Local prototypes */
59
60static ACPI_STATUS
61OslTableInitialize (
62    void);
63
64static ACPI_STATUS
65OslMapTable (
66    ACPI_SIZE               Address,
67    char                    *Signature,
68    ACPI_TABLE_HEADER       **Table);
69
70static ACPI_STATUS
71OslAddTablesToList (
72    void);
73
74static ACPI_STATUS
75OslGetTableViaRoot (
76    char                    *Signature,
77    UINT32                  Instance,
78    ACPI_TABLE_HEADER       **Table,
79    ACPI_PHYSICAL_ADDRESS   *Address);
80
81
82/* Hints for RSDP */
83#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
84#define SYSTEM_KENV         "hint.acpi.0.rsdp"
85#define SYSTEM_SYSCTL       "machdep.acpi_root"
86#elif defined(__NetBSD__)
87#define SYSTEM_SYSCTL       "hw.acpi.root"
88#endif
89
90/* Initialization flags */
91
92UINT8                   Gbl_TableListInitialized = FALSE;
93UINT8                   Gbl_MainTableObtained = FALSE;
94
95/* Local copies of main ACPI tables */
96
97ACPI_TABLE_RSDP         Gbl_Rsdp;
98ACPI_TABLE_FADT         *Gbl_Fadt;
99ACPI_TABLE_RSDT         *Gbl_Rsdt;
100ACPI_TABLE_XSDT         *Gbl_Xsdt;
101
102/* Fadt address */
103
104ACPI_PHYSICAL_ADDRESS   Gbl_FadtAddress;
105
106/* Revision of RSD PTR */
107
108UINT8                   Gbl_Revision;
109
110/* List of information about obtained ACPI tables */
111
112typedef struct          table_info
113{
114    struct table_info       *Next;
115    char                    Signature[4];
116    UINT32                  Instance;
117    ACPI_PHYSICAL_ADDRESS   Address;
118
119} OSL_TABLE_INFO;
120
121OSL_TABLE_INFO          *Gbl_TableListHead = NULL;
122
123
124/******************************************************************************
125 *
126 * FUNCTION:    AcpiOsGetTableByAddress
127 *
128 * PARAMETERS:  Address         - Physical address of the ACPI table
129 *              Table           - Where a pointer to the table is returned
130 *
131 * RETURN:      Status; Table buffer is returned if AE_OK.
132 *              AE_NOT_FOUND: A valid table was not found at the address
133 *
134 * DESCRIPTION: Get an ACPI table via a physical memory address.
135 *
136 *****************************************************************************/
137
138ACPI_STATUS
139AcpiOsGetTableByAddress (
140    ACPI_PHYSICAL_ADDRESS   Address,
141    ACPI_TABLE_HEADER       **Table)
142{
143    ACPI_TABLE_HEADER       *MappedTable;
144    ACPI_TABLE_HEADER       *LocalTable;
145    ACPI_STATUS             Status;
146
147
148    /* Validate the input physical address to avoid program crash */
149
150    if (Address < ACPI_HI_RSDP_WINDOW_BASE)
151    {
152        fprintf (stderr, "Invalid table address: 0x%8.8X%8.8X\n",
153            ACPI_FORMAT_UINT64 (Address));
154        return (AE_BAD_ADDRESS);
155    }
156
157    /* Map the table and validate it */
158
159    Status = OslMapTable (Address, NULL, &MappedTable);
160    if (ACPI_FAILURE (Status))
161    {
162        return (Status);
163    }
164
165    /* Copy table to local buffer and return it */
166
167    LocalTable = calloc (1, MappedTable->Length);
168    if (!LocalTable)
169    {
170        AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
171        return (AE_NO_MEMORY);
172    }
173
174    memcpy (LocalTable, MappedTable, MappedTable->Length);
175    AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
176
177    *Table = LocalTable;
178    return (AE_OK);
179}
180
181
182/******************************************************************************
183 *
184 * FUNCTION:    AcpiOsGetTableByName
185 *
186 * PARAMETERS:  Signature       - ACPI Signature for desired table. Must be
187 *                                a null terminated 4-character string.
188 *              Instance        - Multiple table support for SSDT/UEFI (0...n)
189 *                                Must be 0 for other tables.
190 *              Table           - Where a pointer to the table is returned
191 *              Address         - Where the table physical address is returned
192 *
193 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
194 *              AE_LIMIT: Instance is beyond valid limit
195 *              AE_NOT_FOUND: A table with the signature was not found
196 *
197 * NOTE:        Assumes the input signature is uppercase.
198 *
199 *****************************************************************************/
200
201ACPI_STATUS
202AcpiOsGetTableByName (
203    char                    *Signature,
204    UINT32                  Instance,
205    ACPI_TABLE_HEADER       **Table,
206    ACPI_PHYSICAL_ADDRESS   *Address)
207{
208    ACPI_STATUS             Status;
209
210
211    /* Instance is only valid for SSDT/UEFI tables */
212
213    if (Instance &&
214        !ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT) &&
215        !ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_UEFI))
216    {
217        return (AE_LIMIT);
218    }
219
220    /* Initialize main tables */
221
222    Status = OslTableInitialize ();
223    if (ACPI_FAILURE (Status))
224    {
225        return (Status);
226    }
227
228    /*
229     * If one of the main ACPI tables was requested (RSDT/XSDT/FADT),
230     * simply return it immediately.
231     */
232    if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_XSDT))
233    {
234        if (!Gbl_Revision)
235        {
236            return (AE_NOT_FOUND);
237        }
238
239        *Address = Gbl_Rsdp.XsdtPhysicalAddress;
240        *Table = (ACPI_TABLE_HEADER *) Gbl_Xsdt;
241        return (AE_OK);
242    }
243
244    if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_RSDT))
245    {
246        if (!Gbl_Rsdp.RsdtPhysicalAddress)
247        {
248            return (AE_NOT_FOUND);
249        }
250
251        *Address = Gbl_Rsdp.RsdtPhysicalAddress;
252        *Table = (ACPI_TABLE_HEADER *) Gbl_Rsdt;
253        return (AE_OK);
254    }
255
256    if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_FADT))
257    {
258        *Address = Gbl_FadtAddress;
259        *Table = (ACPI_TABLE_HEADER *) Gbl_Fadt;
260        return (AE_OK);
261    }
262
263    /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
264
265    Status = OslGetTableViaRoot (Signature, Instance, Table, Address);
266    if (ACPI_FAILURE (Status))
267    {
268        return (Status);
269    }
270
271    return (AE_OK);
272}
273
274
275/******************************************************************************
276 *
277 * FUNCTION:    AcpiOsGetTableByIndex
278 *
279 * PARAMETERS:  Index           - Which table to get
280 *              Table           - Where a pointer to the table is returned
281 *              Instance        - Where a pointer to the table instance no. is
282 *                                returned
283 *              Address         - Where the table physical address is returned
284 *
285 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
286 *              AE_LIMIT: Index is beyond valid limit
287 *
288 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
289 *              AE_LIMIT when an invalid index is reached. Index is not
290 *              necessarily an index into the RSDT/XSDT.
291 *
292 *****************************************************************************/
293
294ACPI_STATUS
295AcpiOsGetTableByIndex (
296    UINT32                  Index,
297    ACPI_TABLE_HEADER       **Table,
298    UINT32                  *Instance,
299    ACPI_PHYSICAL_ADDRESS   *Address)
300{
301    OSL_TABLE_INFO          *Info;
302    ACPI_STATUS             Status;
303    UINT32                  i;
304
305
306    /* Initialize main tables */
307
308    Status = OslTableInitialize ();
309    if (ACPI_FAILURE (Status))
310    {
311        return (Status);
312    }
313
314    /* Add all tables to list */
315
316    Status = OslAddTablesToList ();
317    if (ACPI_FAILURE (Status))
318    {
319        return (Status);
320    }
321
322    /* Validate Index */
323
324    if (Index >= Gbl_TableListHead->Instance)
325    {
326        return (AE_LIMIT);
327    }
328
329    /* Point to the table list entry specified by the Index argument */
330
331    Info = Gbl_TableListHead;
332    for (i = 0; i <= Index; i++)
333    {
334        Info = Info->Next;
335    }
336
337    /* Now we can just get the table via the address or name */
338
339    if (Info->Address)
340    {
341        Status = AcpiOsGetTableByAddress (Info->Address, Table);
342        if (ACPI_SUCCESS (Status))
343        {
344            *Address = Info->Address;
345        }
346    }
347    else
348    {
349        Status = AcpiOsGetTableByName (Info->Signature, Info->Instance,
350            Table, Address);
351    }
352
353    if (ACPI_SUCCESS (Status))
354    {
355        *Instance = Info->Instance;
356    }
357    return (Status);
358}
359
360
361/******************************************************************************
362 *
363 * FUNCTION:    OslTableInitialize
364 *
365 * PARAMETERS:  None
366 *
367 * RETURN:      Status
368 *
369 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
370 *              local variables. Main ACPI tables include RSDP, FADT, RSDT,
371 *              and/or XSDT.
372 *
373 *****************************************************************************/
374
375static ACPI_STATUS
376OslTableInitialize (
377    void)
378{
379#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
380    char                    Buffer[32];
381#endif
382    ACPI_TABLE_HEADER       *MappedTable;
383    UINT8                   *TableAddress;
384    UINT8                   *RsdpAddress;
385    ACPI_PHYSICAL_ADDRESS   RsdpBase;
386    ACPI_SIZE               RsdpSize;
387    ACPI_STATUS             Status;
388    u_long                  Address = 0;
389#if defined(SYSTEM_SYSCTL)
390    size_t                  Length = sizeof (Address);
391#endif
392
393
394    /* Get main ACPI tables from memory on first invocation of this function */
395
396    if (Gbl_MainTableObtained)
397    {
398        return (AE_OK);
399    }
400
401    /* Attempt to use kenv or sysctl to find RSD PTR record. */
402
403    if (Gbl_RsdpBase)
404    {
405        Address = Gbl_RsdpBase;
406    }
407#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__DragonFly__)
408    else if (kenv (KENV_GET, SYSTEM_KENV, Buffer, sizeof (Buffer)) > 0)
409    {
410        Address = strtoul (Buffer, NULL, 0);
411    }
412#endif
413#if defined(SYSTEM_SYSCTL)
414    if (!Address)
415    {
416        if (sysctlbyname (SYSTEM_SYSCTL, &Address, &Length, NULL, 0) != 0)
417        {
418            Address = 0;
419        }
420    }
421#endif
422    if (Address)
423    {
424        RsdpBase = Address;
425        RsdpSize = sizeof (Gbl_Rsdp);
426    }
427    else
428    {
429        RsdpBase = ACPI_HI_RSDP_WINDOW_BASE;
430        RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE;
431    }
432
433    /* Get RSDP from memory */
434
435    RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize);
436    if (!RsdpAddress)
437    {
438        return (AE_BAD_ADDRESS);
439    }
440
441    /* Search low memory for the RSDP */
442
443    TableAddress = AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize);
444    if (!TableAddress)
445    {
446        AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
447        return (AE_ERROR);
448    }
449
450    memcpy (&Gbl_Rsdp, TableAddress, sizeof (Gbl_Rsdp));
451    AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
452
453    /* Get XSDT from memory */
454
455    if (Gbl_Rsdp.Revision)
456    {
457        Status = OslMapTable (Gbl_Rsdp.XsdtPhysicalAddress,
458            ACPI_SIG_XSDT, &MappedTable);
459        if (ACPI_FAILURE (Status))
460        {
461            return (Status);
462        }
463
464        Gbl_Revision = 2;
465        Gbl_Xsdt = calloc (1, MappedTable->Length);
466        if (!Gbl_Xsdt)
467        {
468            fprintf (stderr,
469                "XSDT: Could not allocate buffer for table of length %X\n",
470                MappedTable->Length);
471            AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
472            return (AE_NO_MEMORY);
473        }
474
475        memcpy (Gbl_Xsdt, MappedTable, MappedTable->Length);
476        AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
477    }
478
479    /* Get RSDT from memory */
480
481    if (Gbl_Rsdp.RsdtPhysicalAddress)
482    {
483        Status = OslMapTable (Gbl_Rsdp.RsdtPhysicalAddress,
484            ACPI_SIG_RSDT, &MappedTable);
485        if (ACPI_FAILURE (Status))
486        {
487            return (Status);
488        }
489
490        Gbl_Rsdt = calloc (1, MappedTable->Length);
491        if (!Gbl_Rsdt)
492        {
493            fprintf (stderr,
494                "RSDT: Could not allocate buffer for table of length %X\n",
495                MappedTable->Length);
496            AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
497            return (AE_NO_MEMORY);
498        }
499
500        memcpy (Gbl_Rsdt, MappedTable, MappedTable->Length);
501        AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
502    }
503
504    /* Get FADT from memory */
505
506    if (Gbl_Revision)
507    {
508        Gbl_FadtAddress = Gbl_Xsdt->TableOffsetEntry[0];
509    }
510    else
511    {
512        Gbl_FadtAddress = Gbl_Rsdt->TableOffsetEntry[0];
513    }
514
515    if (!Gbl_FadtAddress)
516    {
517        fprintf(stderr, "FADT: Table could not be found\n");
518        return (AE_ERROR);
519    }
520
521    Status = OslMapTable (Gbl_FadtAddress, ACPI_SIG_FADT, &MappedTable);
522    if (ACPI_FAILURE (Status))
523    {
524        return (Status);
525    }
526
527    Gbl_Fadt = calloc (1, MappedTable->Length);
528    if (!Gbl_Fadt)
529    {
530        fprintf (stderr,
531            "FADT: Could not allocate buffer for table of length %X\n",
532            MappedTable->Length);
533        AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
534        return (AE_NO_MEMORY);
535    }
536
537    memcpy (Gbl_Fadt, MappedTable, MappedTable->Length);
538    AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
539    Gbl_MainTableObtained = TRUE;
540    return (AE_OK);
541}
542
543
544/******************************************************************************
545 *
546 * FUNCTION:    OslGetTableViaRoot
547 *
548 * PARAMETERS:  Signature       - ACPI Signature for common table. Must be
549 *                                a null terminated 4-character string.
550 *              Instance        - Multiple table support for SSDT/UEFI (0...n)
551 *                                Must be 0 for other tables.
552 *              Table           - Where a pointer to the table is returned
553 *              Address         - Where the table physical address is returned
554 *
555 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
556 *              AE_LIMIT: Instance is beyond valid limit
557 *              AE_NOT_FOUND: A table with the signature was not found
558 *
559 * DESCRIPTION: Get an ACPI table via the root table (RSDT/XSDT)
560 *
561 * NOTE:        Assumes the input signature is uppercase.
562 *
563 *****************************************************************************/
564
565static ACPI_STATUS
566OslGetTableViaRoot (
567    char                    *Signature,
568    UINT32                  Instance,
569    ACPI_TABLE_HEADER       **Table,
570    ACPI_PHYSICAL_ADDRESS   *Address)
571{
572    ACPI_TABLE_HEADER       *LocalTable = NULL;
573    ACPI_TABLE_HEADER       *MappedTable = NULL;
574    UINT8                   NumberOfTables;
575    UINT32                  CurrentInstance = 0;
576    ACPI_PHYSICAL_ADDRESS   TableAddress = 0;
577    ACPI_STATUS             Status;
578    UINT32                  i;
579
580
581    /* DSDT and FACS address must be extracted from the FADT */
582
583    if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_DSDT) ||
584        ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_FACS))
585    {
586        /*
587         * Get the appropriate address, either 32-bit or 64-bit. Be very
588         * careful about the FADT length and validate table addresses.
589         * Note: The 64-bit addresses have priority.
590         */
591        if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_DSDT))
592        {
593            if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
594                Gbl_Fadt->XDsdt)
595            {
596                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
597            }
598            else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) &&
599                Gbl_Fadt->Dsdt)
600            {
601                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
602            }
603        }
604        else /* FACS */
605        {
606            if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
607                Gbl_Fadt->XFacs)
608            {
609                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
610            }
611            else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) &&
612                Gbl_Fadt->Facs)
613            {
614                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
615            }
616        }
617    }
618    else /* Case for a normal ACPI table */
619    {
620        if (Gbl_Revision)
621        {
622            NumberOfTables =
623                (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header))
624                / sizeof (Gbl_Xsdt->TableOffsetEntry[0]);
625        }
626        else /* Use RSDT if XSDT is not available */
627        {
628            NumberOfTables =
629                (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header))
630                / sizeof (Gbl_Rsdt->TableOffsetEntry[0]);
631        }
632
633        /* Search RSDT/XSDT for the requested table */
634
635        for (i = 0; i < NumberOfTables; i++)
636        {
637            if (Gbl_Revision)
638            {
639                TableAddress = Gbl_Xsdt->TableOffsetEntry[i];
640            }
641            else
642            {
643                TableAddress = Gbl_Rsdt->TableOffsetEntry[i];
644            }
645
646            MappedTable = AcpiOsMapMemory (TableAddress, sizeof (*MappedTable));
647            if (!MappedTable)
648            {
649                return (AE_BAD_ADDRESS);
650            }
651
652            /* Does this table match the requested signature? */
653
654            if (ACPI_COMPARE_NAMESEG (MappedTable->Signature, Signature))
655            {
656
657                /* Match table instance (for SSDT/UEFI tables) */
658
659                if (CurrentInstance == Instance)
660                {
661                    AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
662                    break;
663                }
664
665                CurrentInstance++;
666            }
667
668            AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
669            TableAddress = 0;
670        }
671    }
672
673    if (!TableAddress)
674    {
675        if (CurrentInstance)
676        {
677            return (AE_LIMIT);
678        }
679        return (AE_NOT_FOUND);
680    }
681
682    /* Now we can get the requested table */
683
684    Status = OslMapTable (TableAddress, Signature, &MappedTable);
685    if (ACPI_FAILURE (Status))
686    {
687        return (Status);
688    }
689
690    /* Copy table to local buffer and return it */
691
692    LocalTable = calloc (1, MappedTable->Length);
693    if (!LocalTable)
694    {
695        AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
696        return (AE_NO_MEMORY);
697    }
698
699    memcpy (LocalTable, MappedTable, MappedTable->Length);
700    AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
701    *Table = LocalTable;
702    *Address = TableAddress;
703    return (AE_OK);
704}
705
706
707/******************************************************************************
708 *
709 * FUNCTION:    OslAddTablesToList
710 *
711 * PARAMETERS:  None
712 *
713 * RETURN:      Status; Table list is initialized if AE_OK.
714 *
715 * DESCRIPTION: Add ACPI tables to the table list.
716 *
717 *****************************************************************************/
718
719static ACPI_STATUS
720OslAddTablesToList(
721    void)
722{
723    ACPI_PHYSICAL_ADDRESS   TableAddress;
724    OSL_TABLE_INFO          *Info = NULL;
725    OSL_TABLE_INFO          *NewInfo;
726    ACPI_TABLE_HEADER       *Table;
727    UINT8                   Instance;
728    UINT8                   NumberOfTables;
729    int                     i;
730
731
732    /* Initialize the table list on first invocation */
733
734    if (Gbl_TableListInitialized)
735    {
736        return (AE_OK);
737    }
738
739    /* Add mandatory tables to global table list first */
740
741    for (i = 0; i < 4; i++)
742    {
743        NewInfo = calloc (1, sizeof (*NewInfo));
744        if (!NewInfo)
745        {
746            return (AE_NO_MEMORY);
747        }
748
749        switch (i) {
750        case 0:
751
752            Gbl_TableListHead = Info = NewInfo;
753            continue;
754
755        case 1:
756
757            ACPI_COPY_NAMESEG (NewInfo->Signature,
758                Gbl_Revision ? ACPI_SIG_XSDT : ACPI_SIG_RSDT);
759            break;
760
761        case 2:
762
763            ACPI_COPY_NAMESEG (NewInfo->Signature, ACPI_SIG_FACS);
764            break;
765
766        default:
767
768            ACPI_COPY_NAMESEG (NewInfo->Signature, ACPI_SIG_DSDT);
769
770        }
771
772        Info->Next = NewInfo;
773        Info = NewInfo;
774        Gbl_TableListHead->Instance++;
775    }
776
777    /* Add normal tables from RSDT/XSDT to global list */
778
779    if (Gbl_Revision)
780    {
781        NumberOfTables =
782            (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header))
783            / sizeof (Gbl_Xsdt->TableOffsetEntry[0]);
784    }
785    else
786    {
787        NumberOfTables =
788            (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header))
789            / sizeof (Gbl_Rsdt->TableOffsetEntry[0]);
790    }
791
792    for (i = 0; i < NumberOfTables; i++)
793    {
794        if (Gbl_Revision)
795        {
796            TableAddress = Gbl_Xsdt->TableOffsetEntry[i];
797        }
798        else
799        {
800            TableAddress = Gbl_Rsdt->TableOffsetEntry[i];
801        }
802
803        Table = AcpiOsMapMemory (TableAddress, sizeof (*Table));
804        if (!Table)
805        {
806            return (AE_BAD_ADDRESS);
807        }
808
809        Instance = 0;
810        NewInfo = Gbl_TableListHead;
811        while (NewInfo->Next != NULL)
812        {
813            NewInfo = NewInfo->Next;
814            if (ACPI_COMPARE_NAMESEG (Table->Signature, NewInfo->Signature))
815            {
816                Instance++;
817            }
818        }
819
820        NewInfo = calloc (1, sizeof (*NewInfo));
821        if (!NewInfo)
822        {
823            AcpiOsUnmapMemory (Table, sizeof (*Table));
824            return (AE_NO_MEMORY);
825        }
826
827        ACPI_COPY_NAMESEG (NewInfo->Signature, Table->Signature);
828
829        AcpiOsUnmapMemory (Table, sizeof (*Table));
830
831        NewInfo->Instance = Instance;
832        NewInfo->Address = TableAddress;
833        Info->Next = NewInfo;
834        Info = NewInfo;
835        Gbl_TableListHead->Instance++;
836    }
837
838    Gbl_TableListInitialized = TRUE;
839    return (AE_OK);
840}
841
842
843/******************************************************************************
844 *
845 * FUNCTION:    OslMapTable
846 *
847 * PARAMETERS:  Address             - Address of the table in memory
848 *              Signature           - Optional ACPI Signature for desired table.
849 *                                    Null terminated 4-character string.
850 *              Table               - Where a pointer to the mapped table is
851 *                                    returned
852 *
853 * RETURN:      Status; Mapped table is returned if AE_OK.
854 *
855 * DESCRIPTION: Map entire ACPI table into caller's address space. Also
856 *              validates the table and checksum.
857 *
858 *****************************************************************************/
859
860static ACPI_STATUS
861OslMapTable (
862    ACPI_SIZE               Address,
863    char                    *Signature,
864    ACPI_TABLE_HEADER       **Table)
865{
866    ACPI_TABLE_HEADER       *MappedTable;
867    UINT32                  Length;
868
869
870    /* Map the header so we can get the table length */
871
872    MappedTable = AcpiOsMapMemory (Address, sizeof (*MappedTable));
873    if (!MappedTable)
874    {
875        return (AE_BAD_ADDRESS);
876    }
877
878    /* Check if table is valid */
879
880    if (!ApIsValidHeader (MappedTable))
881    {
882        AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
883        return (AE_BAD_HEADER);
884    }
885
886    /* If specified, signature must match */
887
888    if (Signature &&
889        !ACPI_COMPARE_NAMESEG (Signature, MappedTable->Signature))
890    {
891        AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
892        return (AE_NOT_EXIST);
893    }
894
895    /* Map the entire table */
896
897    Length = MappedTable->Length;
898    AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
899
900    MappedTable = AcpiOsMapMemory (Address, Length);
901    if (!MappedTable)
902    {
903        return (AE_BAD_ADDRESS);
904    }
905
906    (void) ApIsValidChecksum (MappedTable);
907
908    *Table = MappedTable;
909
910    return (AE_OK);
911}
912