oslinuxtbl.c revision 1.2
1/******************************************************************************
2 *
3 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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 MERCHANTIBILITY 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
47#define _COMPONENT          ACPI_OS_SERVICES
48        ACPI_MODULE_NAME    ("oslinuxtbl")
49
50
51#ifndef PATH_MAX
52#define PATH_MAX 256
53#endif
54
55
56/* List of information about obtained ACPI tables */
57
58typedef struct          table_info
59{
60    struct table_info       *Next;
61    UINT32                  Instance;
62    char                    Signature[ACPI_NAME_SIZE];
63
64} OSL_TABLE_INFO;
65
66/* Local prototypes */
67
68static ACPI_STATUS
69OslTableInitialize (
70    void);
71
72static ACPI_STATUS
73OslTableNameFromFile (
74    char                    *Filename,
75    char                    *Signature,
76    UINT32                  *Instance);
77
78static ACPI_STATUS
79OslAddTableToList (
80    char                    *Signature,
81    UINT32                  Instance);
82
83static ACPI_STATUS
84OslReadTableFromFile (
85    char                    *Filename,
86    ACPI_SIZE               FileOffset,
87    char                    *Signature,
88    ACPI_TABLE_HEADER       **Table);
89
90static ACPI_STATUS
91OslMapTable (
92    ACPI_SIZE               Address,
93    char                    *Signature,
94    ACPI_TABLE_HEADER       **Table);
95
96static void
97OslUnmapTable (
98    ACPI_TABLE_HEADER       *Table);
99
100static ACPI_PHYSICAL_ADDRESS
101OslFindRsdpViaEfi (
102    void);
103
104static ACPI_STATUS
105OslLoadRsdp (
106    void);
107
108static ACPI_STATUS
109OslListCustomizedTables (
110    char                    *Directory);
111
112static ACPI_STATUS
113OslGetCustomizedTable (
114    char                    *Pathname,
115    char                    *Signature,
116    UINT32                  Instance,
117    ACPI_TABLE_HEADER       **Table,
118    ACPI_PHYSICAL_ADDRESS   *Address);
119
120static ACPI_STATUS
121OslListBiosTables (
122    void);
123
124static ACPI_STATUS
125OslGetBiosTable (
126    char                    *Signature,
127    UINT32                  Instance,
128    ACPI_TABLE_HEADER       **Table,
129    ACPI_PHYSICAL_ADDRESS   *Address);
130
131static ACPI_STATUS
132OslGetLastStatus (
133    ACPI_STATUS             DefaultStatus);
134
135
136/* File locations */
137
138#define DYNAMIC_TABLE_DIR   "/sys/firmware/acpi/tables/dynamic"
139#define STATIC_TABLE_DIR    "/sys/firmware/acpi/tables"
140#define EFI_SYSTAB          "/sys/firmware/efi/systab"
141
142/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */
143
144UINT8                   Gbl_DumpDynamicTables = TRUE;
145
146/* Initialization flags */
147
148UINT8                   Gbl_TableListInitialized = FALSE;
149
150/* Local copies of main ACPI tables */
151
152ACPI_TABLE_RSDP         Gbl_Rsdp;
153ACPI_TABLE_FADT         *Gbl_Fadt = NULL;
154ACPI_TABLE_RSDT         *Gbl_Rsdt = NULL;
155ACPI_TABLE_XSDT         *Gbl_Xsdt = NULL;
156
157/* Table addresses */
158
159ACPI_PHYSICAL_ADDRESS   Gbl_FadtAddress = 0;
160ACPI_PHYSICAL_ADDRESS   Gbl_RsdpAddress = 0;
161
162/* Revision of RSD PTR */
163
164UINT8                   Gbl_Revision = 0;
165
166OSL_TABLE_INFO          *Gbl_TableListHead = NULL;
167UINT32                  Gbl_TableCount = 0;
168
169
170/******************************************************************************
171 *
172 * FUNCTION:    OslGetLastStatus
173 *
174 * PARAMETERS:  DefaultStatus   - Default error status to return
175 *
176 * RETURN:      Status; Converted from errno.
177 *
178 * DESCRIPTION: Get last errno and conver it to ACPI_STATUS.
179 *
180 *****************************************************************************/
181
182static ACPI_STATUS
183OslGetLastStatus (
184    ACPI_STATUS             DefaultStatus)
185{
186
187    switch (errno)
188    {
189    case EACCES:
190    case EPERM:
191
192        return (AE_ACCESS);
193
194    case ENOENT:
195
196        return (AE_NOT_FOUND);
197
198    case ENOMEM:
199
200        return (AE_NO_MEMORY);
201
202    default:
203
204        return (DefaultStatus);
205    }
206}
207
208
209/******************************************************************************
210 *
211 * FUNCTION:    AcpiOsGetTableByAddress
212 *
213 * PARAMETERS:  Address         - Physical address of the ACPI table
214 *              Table           - Where a pointer to the table is returned
215 *
216 * RETURN:      Status; Table buffer is returned if AE_OK.
217 *              AE_NOT_FOUND: A valid table was not found at the address
218 *
219 * DESCRIPTION: Get an ACPI table via a physical memory address.
220 *
221 *****************************************************************************/
222
223ACPI_STATUS
224AcpiOsGetTableByAddress (
225    ACPI_PHYSICAL_ADDRESS   Address,
226    ACPI_TABLE_HEADER       **Table)
227{
228    UINT32                  TableLength;
229    ACPI_TABLE_HEADER       *MappedTable;
230    ACPI_TABLE_HEADER       *LocalTable = NULL;
231    ACPI_STATUS             Status = AE_OK;
232
233
234    /* Get main ACPI tables from memory on first invocation of this function */
235
236    Status = OslTableInitialize ();
237    if (ACPI_FAILURE (Status))
238    {
239        return (Status);
240    }
241
242    /* Map the table and validate it */
243
244    Status = OslMapTable (Address, NULL, &MappedTable);
245    if (ACPI_FAILURE (Status))
246    {
247        return (Status);
248    }
249
250    /* Copy table to local buffer and return it */
251
252    TableLength = ApGetTableLength (MappedTable);
253    if (TableLength == 0)
254    {
255        Status = AE_BAD_HEADER;
256        goto ErrorExit;
257    }
258
259    LocalTable = calloc (1, TableLength);
260    if (!LocalTable)
261    {
262        Status = AE_NO_MEMORY;
263        goto ErrorExit;
264    }
265
266    ACPI_MEMCPY (LocalTable, MappedTable, TableLength);
267
268ErrorExit:
269    OslUnmapTable (MappedTable);
270    *Table = LocalTable;
271    return (AE_OK);
272}
273
274
275/******************************************************************************
276 *
277 * FUNCTION:    AcpiOsGetTableByName
278 *
279 * PARAMETERS:  Signature       - ACPI Signature for desired table. Must be
280 *                                a null terminated 4-character string.
281 *              Instance        - Multiple table support for SSDT/UEFI (0...n)
282 *                                Must be 0 for other tables.
283 *              Table           - Where a pointer to the table is returned
284 *              Address         - Where the table physical address is returned
285 *
286 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
287 *              AE_LIMIT: Instance is beyond valid limit
288 *              AE_NOT_FOUND: A table with the signature was not found
289 *
290 * NOTE:        Assumes the input signature is uppercase.
291 *
292 *****************************************************************************/
293
294ACPI_STATUS
295AcpiOsGetTableByName (
296    char                    *Signature,
297    UINT32                  Instance,
298    ACPI_TABLE_HEADER       **Table,
299    ACPI_PHYSICAL_ADDRESS   *Address)
300{
301    ACPI_STATUS             Status;
302
303
304    /* Get main ACPI tables from memory on first invocation of this function */
305
306    Status = OslTableInitialize ();
307    if (ACPI_FAILURE (Status))
308    {
309        return (Status);
310    }
311
312    /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
313
314    if (!Gbl_DumpCustomizedTables)
315    {
316        /* Attempt to get the table from the memory */
317
318        Status = OslGetBiosTable (Signature, Instance, Table, Address);
319    }
320    else
321    {
322        /* Attempt to get the table from the static directory */
323
324        Status = OslGetCustomizedTable (STATIC_TABLE_DIR, Signature,
325            Instance, Table, Address);
326    }
327
328    if (ACPI_FAILURE (Status) && Status == AE_LIMIT)
329    {
330        if (Gbl_DumpDynamicTables)
331        {
332            /* Attempt to get a dynamic table */
333
334            Status = OslGetCustomizedTable (DYNAMIC_TABLE_DIR, Signature,
335                Instance, Table, Address);
336        }
337    }
338
339    return (Status);
340}
341
342
343/******************************************************************************
344 *
345 * FUNCTION:    OslAddTableToList
346 *
347 * PARAMETERS:  Signature       - Table signature
348 *              Instance        - Table instance
349 *
350 * RETURN:      Status; Successfully added if AE_OK.
351 *              AE_NO_MEMORY: Memory allocation error
352 *
353 * DESCRIPTION: Insert a table structure into OSL table list.
354 *
355 *****************************************************************************/
356
357static ACPI_STATUS
358OslAddTableToList (
359    char                    *Signature,
360    UINT32                  Instance)
361{
362    OSL_TABLE_INFO          *NewInfo;
363    OSL_TABLE_INFO          *Next;
364    UINT32                  NextInstance = 0;
365    BOOLEAN                 Found = FALSE;
366
367
368    NewInfo = calloc (1, sizeof (OSL_TABLE_INFO));
369    if (!NewInfo)
370    {
371        return (AE_NO_MEMORY);
372    }
373
374    ACPI_MOVE_NAME (NewInfo->Signature, Signature);
375
376    if (!Gbl_TableListHead)
377    {
378        Gbl_TableListHead = NewInfo;
379    }
380    else
381    {
382        Next = Gbl_TableListHead;
383        while (1)
384        {
385            if (ACPI_COMPARE_NAME (Next->Signature, Signature))
386            {
387                if (Next->Instance == Instance)
388                {
389                    Found = TRUE;
390                }
391                if (Next->Instance >= NextInstance)
392                {
393                    NextInstance = Next->Instance + 1;
394                }
395            }
396
397            if (!Next->Next)
398            {
399                break;
400            }
401            Next = Next->Next;
402        }
403        Next->Next = NewInfo;
404    }
405
406    if (Found)
407    {
408        if (Instance)
409        {
410            fprintf (stderr,
411                "%4.4s: Warning unmatched table instance %d, expected %d\n",
412                Signature, Instance, NextInstance);
413        }
414        Instance = NextInstance;
415    }
416
417    NewInfo->Instance = Instance;
418    Gbl_TableCount++;
419
420    return (AE_OK);
421}
422
423
424/******************************************************************************
425 *
426 * FUNCTION:    AcpiOsGetTableByIndex
427 *
428 * PARAMETERS:  Index           - Which table to get
429 *              Table           - Where a pointer to the table is returned
430 *              Instance        - Where a pointer to the table instance no. is
431 *                                returned
432 *              Address         - Where the table physical address is returned
433 *
434 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
435 *              AE_LIMIT: Index is beyond valid limit
436 *
437 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
438 *              AE_LIMIT when an invalid index is reached. Index is not
439 *              necessarily an index into the RSDT/XSDT.
440 *
441 *****************************************************************************/
442
443ACPI_STATUS
444AcpiOsGetTableByIndex (
445    UINT32                  Index,
446    ACPI_TABLE_HEADER       **Table,
447    UINT32                  *Instance,
448    ACPI_PHYSICAL_ADDRESS   *Address)
449{
450    OSL_TABLE_INFO          *Info;
451    ACPI_STATUS             Status;
452    UINT32                  i;
453
454
455    /* Get main ACPI tables from memory on first invocation of this function */
456
457    Status = OslTableInitialize ();
458    if (ACPI_FAILURE (Status))
459    {
460        return (Status);
461    }
462
463    /* Validate Index */
464
465    if (Index >= Gbl_TableCount)
466    {
467        return (AE_LIMIT);
468    }
469
470    /* Point to the table list entry specified by the Index argument */
471
472    Info = Gbl_TableListHead;
473    for (i = 0; i < Index; i++)
474    {
475        Info = Info->Next;
476    }
477
478    /* Now we can just get the table via the signature */
479
480    Status = AcpiOsGetTableByName (Info->Signature, Info->Instance,
481        Table, Address);
482
483    if (ACPI_SUCCESS (Status))
484    {
485        *Instance = Info->Instance;
486    }
487    return (Status);
488}
489
490
491/******************************************************************************
492 *
493 * FUNCTION:    OslFindRsdpViaEfi
494 *
495 * PARAMETERS:  None
496 *
497 * RETURN:      RSDP address if found
498 *
499 * DESCRIPTION: Find RSDP address via EFI.
500 *
501 *****************************************************************************/
502
503static ACPI_PHYSICAL_ADDRESS
504OslFindRsdpViaEfi (
505    void)
506{
507    FILE                    *File;
508    char                    Buffer[80];
509    unsigned long           Address = 0;
510
511
512    File = fopen (EFI_SYSTAB, "r");
513    if (File)
514    {
515        while (fgets (Buffer, 80, File))
516        {
517            if (sscanf (Buffer, "ACPI20=0x%lx", &Address) == 1)
518            {
519                break;
520            }
521        }
522        fclose (File);
523    }
524
525    return ((ACPI_PHYSICAL_ADDRESS) (Address));
526}
527
528
529/******************************************************************************
530 *
531 * FUNCTION:    OslLoadRsdp
532 *
533 * PARAMETERS:  None
534 *
535 * RETURN:      Status
536 *
537 * DESCRIPTION: Scan and load RSDP.
538 *
539 *****************************************************************************/
540
541static ACPI_STATUS
542OslLoadRsdp (
543    void)
544{
545    ACPI_TABLE_HEADER       *MappedTable;
546    UINT8                   *RsdpAddress;
547    ACPI_PHYSICAL_ADDRESS   RsdpBase;
548    ACPI_SIZE               RsdpSize;
549
550
551    /* Get RSDP from memory */
552
553    RsdpSize = sizeof (ACPI_TABLE_RSDP);
554    if (Gbl_RsdpBase)
555    {
556        RsdpBase = Gbl_RsdpBase;
557    }
558    else
559    {
560        RsdpBase = OslFindRsdpViaEfi ();
561    }
562
563    if (!RsdpBase)
564    {
565        RsdpBase = ACPI_HI_RSDP_WINDOW_BASE;
566        RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE;
567    }
568
569    RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize);
570    if (!RsdpAddress)
571    {
572        return (OslGetLastStatus (AE_BAD_ADDRESS));
573    }
574
575    /* Search low memory for the RSDP */
576
577    MappedTable = ACPI_CAST_PTR (ACPI_TABLE_HEADER,
578        AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize));
579    if (!MappedTable)
580    {
581        AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
582        return (AE_NOT_FOUND);
583    }
584
585    Gbl_RsdpAddress = RsdpBase + (ACPI_CAST8 (MappedTable) - RsdpAddress);
586
587    ACPI_MEMCPY (&Gbl_Rsdp, MappedTable, sizeof (ACPI_TABLE_RSDP));
588    AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
589
590    return (AE_OK);
591}
592
593
594/******************************************************************************
595 *
596 * FUNCTION:    OslTableInitialize
597 *
598 * PARAMETERS:  None
599 *
600 * RETURN:      Status
601 *
602 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
603 *              local variables. Main ACPI tables include RSDT, FADT, RSDT,
604 *              and/or XSDT.
605 *
606 *****************************************************************************/
607
608static ACPI_STATUS
609OslTableInitialize (
610    void)
611{
612    ACPI_STATUS             Status;
613    ACPI_PHYSICAL_ADDRESS   Address;
614
615
616    if (Gbl_TableListInitialized)
617    {
618        return (AE_OK);
619    }
620
621    /* Get RSDP from memory */
622
623    Status = OslLoadRsdp ();
624    if (ACPI_FAILURE (Status))
625    {
626        return (Status);
627    }
628
629    /* Get XSDT from memory */
630
631    if (Gbl_Rsdp.Revision)
632    {
633        if (Gbl_Xsdt)
634        {
635            free (Gbl_Xsdt);
636            Gbl_Xsdt = NULL;
637        }
638
639        Gbl_Revision = 2;
640        Status = OslGetBiosTable (ACPI_SIG_XSDT, 0,
641            ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address);
642        if (ACPI_FAILURE (Status))
643        {
644            return (Status);
645        }
646    }
647
648    /* Get RSDT from memory */
649
650    if (Gbl_Rsdp.RsdtPhysicalAddress)
651    {
652        if (Gbl_Rsdt)
653        {
654            free (Gbl_Rsdt);
655            Gbl_Rsdt = NULL;
656        }
657
658        Status = OslGetBiosTable (ACPI_SIG_RSDT, 0,
659            ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address);
660        if (ACPI_FAILURE (Status))
661        {
662            return (Status);
663        }
664    }
665
666    /* Get FADT from memory */
667
668    if (Gbl_Fadt)
669    {
670        free (Gbl_Fadt);
671        Gbl_Fadt = NULL;
672    }
673
674    Status = OslGetBiosTable (ACPI_SIG_FADT, 0,
675        ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress);
676    if (ACPI_FAILURE (Status))
677    {
678        return (Status);
679    }
680
681    if (!Gbl_DumpCustomizedTables)
682    {
683        /* Add mandatory tables to global table list first */
684
685        Status = OslAddTableToList (AP_DUMP_SIG_RSDP, 0);
686        if (ACPI_FAILURE (Status))
687        {
688            return (Status);
689        }
690
691        Status = OslAddTableToList (ACPI_SIG_RSDT, 0);
692        if (ACPI_FAILURE (Status))
693        {
694            return (Status);
695        }
696
697        if (Gbl_Revision == 2)
698        {
699            Status = OslAddTableToList (ACPI_SIG_XSDT, 0);
700            if (ACPI_FAILURE (Status))
701            {
702                return (Status);
703            }
704        }
705
706        Status = OslAddTableToList (ACPI_SIG_DSDT, 0);
707        if (ACPI_FAILURE (Status))
708        {
709            return (Status);
710        }
711
712        Status = OslAddTableToList (ACPI_SIG_FACS, 0);
713        if (ACPI_FAILURE (Status))
714        {
715            return (Status);
716        }
717
718        /* Add all tables found in the memory */
719
720        Status = OslListBiosTables ();
721        if (ACPI_FAILURE (Status))
722        {
723            return (Status);
724        }
725    }
726    else
727    {
728        /* Add all tables found in the static directory */
729
730        Status = OslListCustomizedTables (STATIC_TABLE_DIR);
731        if (ACPI_FAILURE (Status))
732        {
733            return (Status);
734        }
735    }
736
737    if (Gbl_DumpDynamicTables)
738    {
739        /* Add all dynamically loaded tables in the dynamic directory */
740
741        Status = OslListCustomizedTables (DYNAMIC_TABLE_DIR);
742        if (ACPI_FAILURE (Status))
743        {
744            return (Status);
745        }
746    }
747
748    Gbl_TableListInitialized = TRUE;
749    return (AE_OK);
750}
751
752
753/******************************************************************************
754 *
755 * FUNCTION:    OslListBiosTables
756 *
757 * PARAMETERS:  None
758 *
759 * RETURN:      Status; Table list is initialized if AE_OK.
760 *
761 * DESCRIPTION: Add ACPI tables to the table list from memory.
762 *
763 * NOTE:        This works on Linux as table customization does not modify the
764 *              addresses stored in RSDP/RSDT/XSDT/FADT.
765 *
766 *****************************************************************************/
767
768static ACPI_STATUS
769OslListBiosTables (
770    void)
771{
772    ACPI_TABLE_HEADER       *MappedTable = NULL;
773    UINT8                   *TableData;
774    UINT8                   NumberOfTables;
775    UINT8                   ItemSize;
776    ACPI_PHYSICAL_ADDRESS   TableAddress = 0;
777    ACPI_STATUS             Status = AE_OK;
778    UINT32                  i;
779
780
781    if (Gbl_Revision)
782    {
783        ItemSize = sizeof (UINT64);
784        TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
785        NumberOfTables =
786            (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
787            / ItemSize);
788    }
789    else /* Use RSDT if XSDT is not available */
790    {
791        ItemSize = sizeof (UINT32);
792        TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
793        NumberOfTables =
794            (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
795            / ItemSize);
796    }
797
798    /* Search RSDT/XSDT for the requested table */
799
800    for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize)
801    {
802        if (Gbl_Revision)
803        {
804            TableAddress =
805                (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData));
806        }
807        else
808        {
809            TableAddress =
810                (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData));
811        }
812
813        Status = OslMapTable (TableAddress, NULL, &MappedTable);
814        if (ACPI_FAILURE (Status))
815        {
816            return (Status);
817        }
818
819        OslAddTableToList (MappedTable->Signature, 0);
820        OslUnmapTable (MappedTable);
821    }
822
823    return (AE_OK);
824}
825
826
827/******************************************************************************
828 *
829 * FUNCTION:    OslGetBiosTable
830 *
831 * PARAMETERS:  Signature       - ACPI Signature for common table. Must be
832 *                                a null terminated 4-character string.
833 *              Instance        - Multiple table support for SSDT/UEFI (0...n)
834 *                                Must be 0 for other tables.
835 *              Table           - Where a pointer to the table is returned
836 *              Address         - Where the table physical address is returned
837 *
838 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
839 *              AE_LIMIT: Instance is beyond valid limit
840 *              AE_NOT_FOUND: A table with the signature was not found
841 *
842 * DESCRIPTION: Get a BIOS provided ACPI table
843 *
844 * NOTE:        Assumes the input signature is uppercase.
845 *
846 *****************************************************************************/
847
848static ACPI_STATUS
849OslGetBiosTable (
850    char                    *Signature,
851    UINT32                  Instance,
852    ACPI_TABLE_HEADER       **Table,
853    ACPI_PHYSICAL_ADDRESS   *Address)
854{
855    ACPI_TABLE_HEADER       *LocalTable = NULL;
856    ACPI_TABLE_HEADER       *MappedTable = NULL;
857    UINT8                   *TableData;
858    UINT8                   NumberOfTables;
859    UINT8                   ItemSize;
860    UINT32                  CurrentInstance = 0;
861    ACPI_PHYSICAL_ADDRESS   TableAddress = 0;
862    UINT32                  TableLength = 0;
863    ACPI_STATUS             Status = AE_OK;
864    UINT32                  i;
865
866
867    /* Handle special tables whose addresses are not in RSDT/XSDT */
868
869    if (ACPI_COMPARE_NAME (Signature, AP_DUMP_SIG_RSDP) ||
870        ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT) ||
871        ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT) ||
872        ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) ||
873        ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
874    {
875        /*
876         * Get the appropriate address, either 32-bit or 64-bit. Be very
877         * careful about the FADT length and validate table addresses.
878         * Note: The 64-bit addresses have priority.
879         */
880        if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT))
881        {
882            if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
883                Gbl_Fadt->XDsdt)
884            {
885                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
886            }
887            else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) &&
888                Gbl_Fadt->Dsdt)
889            {
890                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
891            }
892        }
893        else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
894        {
895            if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
896                Gbl_Fadt->XFacs)
897            {
898                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
899            }
900            else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) &&
901                Gbl_Fadt->Facs)
902            {
903                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
904            }
905        }
906        else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT))
907        {
908            if (!Gbl_Revision)
909            {
910                return (AE_BAD_SIGNATURE);
911            }
912            TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.XsdtPhysicalAddress;
913        }
914        else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT))
915        {
916            TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.RsdtPhysicalAddress;
917        }
918        else
919        {
920            TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress;
921            Signature = ACPI_SIG_RSDP;
922        }
923
924        /* Now we can get the requested special table */
925
926        Status = OslMapTable (TableAddress, Signature, &MappedTable);
927        if (ACPI_FAILURE (Status))
928        {
929            return (Status);
930        }
931
932        TableLength = ApGetTableLength (MappedTable);
933    }
934    else /* Case for a normal ACPI table */
935    {
936        if (Gbl_Revision)
937        {
938            ItemSize = sizeof (UINT64);
939            TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
940            NumberOfTables =
941                (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
942                / ItemSize);
943        }
944        else /* Use RSDT if XSDT is not available */
945        {
946            ItemSize = sizeof (UINT32);
947            TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
948            NumberOfTables =
949                (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
950                / ItemSize);
951        }
952
953        /* Search RSDT/XSDT for the requested table */
954
955        for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize)
956        {
957            if (Gbl_Revision)
958            {
959                TableAddress =
960                    (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData));
961            }
962            else
963            {
964                TableAddress =
965                    (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData));
966            }
967
968            Status = OslMapTable (TableAddress, NULL, &MappedTable);
969            if (ACPI_FAILURE (Status))
970            {
971                return (Status);
972            }
973            TableLength = MappedTable->Length;
974
975            /* Does this table match the requested signature? */
976
977            if (!ACPI_COMPARE_NAME (MappedTable->Signature, Signature))
978            {
979                OslUnmapTable (MappedTable);
980                MappedTable = NULL;
981                continue;
982            }
983
984            /* Match table instance (for SSDT/UEFI tables) */
985
986            if (CurrentInstance != Instance)
987            {
988                OslUnmapTable (MappedTable);
989                MappedTable = NULL;
990                CurrentInstance++;
991                continue;
992            }
993
994            break;
995        }
996    }
997
998    if (!MappedTable)
999    {
1000        return (AE_LIMIT);
1001    }
1002
1003    if (TableLength == 0)
1004    {
1005        Status = AE_BAD_HEADER;
1006        goto ErrorExit;
1007    }
1008
1009    /* Copy table to local buffer and return it */
1010
1011    LocalTable = calloc (1, TableLength);
1012    if (!LocalTable)
1013    {
1014        Status = AE_NO_MEMORY;
1015        goto ErrorExit;
1016    }
1017
1018    ACPI_MEMCPY (LocalTable, MappedTable, TableLength);
1019    *Address = TableAddress;
1020    *Table = LocalTable;
1021
1022ErrorExit:
1023    OslUnmapTable (MappedTable);
1024    return (AE_OK);
1025}
1026
1027
1028/******************************************************************************
1029 *
1030 * FUNCTION:    OslListCustomizedTables
1031 *
1032 * PARAMETERS:  Directory           - Directory that contains the tables
1033 *
1034 * RETURN:      Status; Table list is initialized if AE_OK.
1035 *
1036 * DESCRIPTION: Add ACPI tables to the table list from a directory.
1037 *
1038 *****************************************************************************/
1039
1040static ACPI_STATUS
1041OslListCustomizedTables (
1042    char                    *Directory)
1043{
1044    void                    *TableDir;
1045    UINT32                  Instance;
1046    char                    TempName[ACPI_NAME_SIZE];
1047    char                    *Filename;
1048    ACPI_STATUS             Status = AE_OK;
1049
1050
1051    /* Open the requested directory */
1052
1053    TableDir = AcpiOsOpenDirectory (Directory, "*", REQUEST_FILE_ONLY);
1054    if (!TableDir)
1055    {
1056        return (OslGetLastStatus (AE_NOT_FOUND));
1057    }
1058
1059    /* Examine all entries in this directory */
1060
1061    while ((Filename = AcpiOsGetNextFilename (TableDir)))
1062    {
1063        /* Extract table name and instance number */
1064
1065        Status = OslTableNameFromFile (Filename, TempName, &Instance);
1066
1067        /* Ignore meaningless files */
1068
1069        if (ACPI_FAILURE (Status))
1070        {
1071            continue;
1072        }
1073
1074        /* Add new info node to global table list */
1075
1076        Status = OslAddTableToList (TempName, Instance);
1077        if (ACPI_FAILURE (Status))
1078        {
1079            break;
1080        }
1081    }
1082
1083    AcpiOsCloseDirectory (TableDir);
1084    return (Status);
1085}
1086
1087
1088/******************************************************************************
1089 *
1090 * FUNCTION:    OslMapTable
1091 *
1092 * PARAMETERS:  Address             - Address of the table in memory
1093 *              Signature           - Optional ACPI Signature for desired table.
1094 *                                    Null terminated 4-character string.
1095 *              Table               - Where a pointer to the mapped table is
1096 *                                    returned
1097 *
1098 * RETURN:      Status; Mapped table is returned if AE_OK.
1099 *              AE_NOT_FOUND: A valid table was not found at the address
1100 *
1101 * DESCRIPTION: Map entire ACPI table into caller's address space.
1102 *
1103 *****************************************************************************/
1104
1105static ACPI_STATUS
1106OslMapTable (
1107    ACPI_SIZE               Address,
1108    char                    *Signature,
1109    ACPI_TABLE_HEADER       **Table)
1110{
1111    ACPI_TABLE_HEADER       *MappedTable;
1112    UINT32                  Length;
1113
1114
1115    if (!Address)
1116    {
1117        return (AE_BAD_ADDRESS);
1118    }
1119
1120    /*
1121     * Map the header so we can get the table length.
1122     * Use sizeof (ACPI_TABLE_HEADER) as:
1123     * 1. it is bigger than 24 to include RSDP->Length
1124     * 2. it is smaller than sizeof (ACPI_TABLE_RSDP)
1125     */
1126    MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
1127    if (!MappedTable)
1128    {
1129        fprintf (stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1130            ACPI_FORMAT_UINT64 (Address));
1131        return (OslGetLastStatus (AE_BAD_ADDRESS));
1132    }
1133
1134    /* If specified, signature must match */
1135
1136    if (Signature &&
1137        !ACPI_COMPARE_NAME (Signature, MappedTable->Signature))
1138    {
1139        AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
1140        return (AE_BAD_SIGNATURE);
1141    }
1142
1143    /* Map the entire table */
1144
1145    Length = ApGetTableLength (MappedTable);
1146    AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
1147    if (Length == 0)
1148    {
1149        return (AE_BAD_HEADER);
1150    }
1151
1152    MappedTable = AcpiOsMapMemory (Address, Length);
1153    if (!MappedTable)
1154    {
1155        fprintf (stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1156            ACPI_FORMAT_UINT64 (Address), Length);
1157        return (OslGetLastStatus (AE_INVALID_TABLE_LENGTH));
1158    }
1159
1160    (void) ApIsValidChecksum (MappedTable);
1161
1162    *Table = MappedTable;
1163    return (AE_OK);
1164}
1165
1166
1167/******************************************************************************
1168 *
1169 * FUNCTION:    OslUnmapTable
1170 *
1171 * PARAMETERS:  Table               - A pointer to the mapped table
1172 *
1173 * RETURN:      None
1174 *
1175 * DESCRIPTION: Unmap entire ACPI table.
1176 *
1177 *****************************************************************************/
1178
1179static void
1180OslUnmapTable (
1181    ACPI_TABLE_HEADER       *Table)
1182{
1183    if (Table)
1184    {
1185        AcpiOsUnmapMemory (Table, ApGetTableLength (Table));
1186    }
1187}
1188
1189
1190/******************************************************************************
1191 *
1192 * FUNCTION:    OslTableNameFromFile
1193 *
1194 * PARAMETERS:  Filename            - File that contains the desired table
1195 *              Signature           - Pointer to 4-character buffer to store
1196 *                                    extracted table signature.
1197 *              Instance            - Pointer to integer to store extracted
1198 *                                    table instance number.
1199 *
1200 * RETURN:      Status; Table name is extracted if AE_OK.
1201 *
1202 * DESCRIPTION: Extract table signature and instance number from a table file
1203 *              name.
1204 *
1205 *****************************************************************************/
1206
1207static ACPI_STATUS
1208OslTableNameFromFile (
1209    char                    *Filename,
1210    char                    *Signature,
1211    UINT32                  *Instance)
1212{
1213
1214    /* Ignore meaningless files */
1215
1216    if (strlen (Filename) < ACPI_NAME_SIZE)
1217    {
1218        return (AE_BAD_SIGNATURE);
1219    }
1220
1221    /* Extract instance number */
1222
1223    if (isdigit ((int) Filename[ACPI_NAME_SIZE]))
1224    {
1225        sscanf (&Filename[ACPI_NAME_SIZE], "%d", Instance);
1226    }
1227    else if (strlen (Filename) != ACPI_NAME_SIZE)
1228    {
1229        return (AE_BAD_SIGNATURE);
1230    }
1231    else
1232    {
1233        *Instance = 0;
1234    }
1235
1236    /* Extract signature */
1237
1238    ACPI_MOVE_NAME (Signature, Filename);
1239    return (AE_OK);
1240}
1241
1242
1243/******************************************************************************
1244 *
1245 * FUNCTION:    OslReadTableFromFile
1246 *
1247 * PARAMETERS:  Filename            - File that contains the desired table
1248 *              FileOffset          - Offset of the table in file
1249 *              Signature           - Optional ACPI Signature for desired table.
1250 *                                    A null terminated 4-character string.
1251 *              Table               - Where a pointer to the table is returned
1252 *
1253 * RETURN:      Status; Table buffer is returned if AE_OK.
1254 *
1255 * DESCRIPTION: Read a ACPI table from a file.
1256 *
1257 *****************************************************************************/
1258
1259static ACPI_STATUS
1260OslReadTableFromFile (
1261    char                    *Filename,
1262    ACPI_SIZE               FileOffset,
1263    char                    *Signature,
1264    ACPI_TABLE_HEADER       **Table)
1265{
1266    FILE                    *TableFile;
1267    ACPI_TABLE_HEADER       Header;
1268    ACPI_TABLE_HEADER       *LocalTable = NULL;
1269    UINT32                  TableLength;
1270    INT32                   Count;
1271    UINT32                  Total = 0;
1272    ACPI_STATUS             Status = AE_OK;
1273
1274
1275    /* Open the file */
1276
1277    TableFile = fopen (Filename, "rb");
1278    if (TableFile == NULL)
1279    {
1280        fprintf (stderr, "Could not open table file: %s\n", Filename);
1281        return (OslGetLastStatus (AE_NOT_FOUND));
1282    }
1283
1284    fseek (TableFile, FileOffset, SEEK_SET);
1285
1286    /* Read the Table header to get the table length */
1287
1288    Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile);
1289    if (Count != sizeof (ACPI_TABLE_HEADER))
1290    {
1291        fprintf (stderr, "Could not read table header: %s\n", Filename);
1292        Status = AE_BAD_HEADER;
1293        goto ErrorExit;
1294    }
1295
1296    /* If signature is specified, it must match the table */
1297
1298    if (Signature &&
1299        !ACPI_COMPARE_NAME (Signature, Header.Signature))
1300    {
1301        fprintf (stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1302            Signature, Header.Signature);
1303        Status = AE_BAD_SIGNATURE;
1304        goto ErrorExit;
1305    }
1306
1307    TableLength = ApGetTableLength (&Header);
1308    if (TableLength == 0)
1309    {
1310        Status = AE_BAD_HEADER;
1311        goto ErrorExit;
1312    }
1313
1314    /* Read the entire table into a local buffer */
1315
1316    LocalTable = calloc (1, TableLength);
1317    if (!LocalTable)
1318    {
1319        fprintf (stderr,
1320            "%4.4s: Could not allocate buffer for table of length %X\n",
1321            Header.Signature, TableLength);
1322        Status = AE_NO_MEMORY;
1323        goto ErrorExit;
1324    }
1325
1326    fseek (TableFile, FileOffset, SEEK_SET);
1327
1328    while (!feof (TableFile) && Total < TableLength)
1329    {
1330        Count = fread (LocalTable, 1, TableLength-Total, TableFile);
1331        if (Count < 0)
1332        {
1333            fprintf (stderr, "%4.4s: Could not read table content\n",
1334                Header.Signature);
1335            Status = AE_INVALID_TABLE_LENGTH;
1336            goto ErrorExit;
1337        }
1338
1339        Total += Count;
1340    }
1341
1342    /* Validate checksum */
1343
1344    (void) ApIsValidChecksum (LocalTable);
1345
1346ErrorExit:
1347    fclose (TableFile);
1348    *Table = LocalTable;
1349    return (Status);
1350}
1351
1352
1353/******************************************************************************
1354 *
1355 * FUNCTION:    OslGetCustomizedTable
1356 *
1357 * PARAMETERS:  Pathname        - Directory to find Linux customized table
1358 *              Signature       - ACPI Signature for desired table. Must be
1359 *                                a null terminated 4-character string.
1360 *              Instance        - Multiple table support for SSDT/UEFI (0...n)
1361 *                                Must be 0 for other tables.
1362 *              Table           - Where a pointer to the table is returned
1363 *              Address         - Where the table physical address is returned
1364 *
1365 * RETURN:      Status; Table buffer is returned if AE_OK.
1366 *              AE_LIMIT: Instance is beyond valid limit
1367 *              AE_NOT_FOUND: A table with the signature was not found
1368 *
1369 * DESCRIPTION: Get an OS customized table.
1370 *
1371 *****************************************************************************/
1372
1373static ACPI_STATUS
1374OslGetCustomizedTable (
1375    char                    *Pathname,
1376    char                    *Signature,
1377    UINT32                  Instance,
1378    ACPI_TABLE_HEADER       **Table,
1379    ACPI_PHYSICAL_ADDRESS   *Address)
1380{
1381    void                    *TableDir;
1382    UINT32                  CurrentInstance = 0;
1383    char                    TempName[ACPI_NAME_SIZE];
1384    char                    TableFilename[PATH_MAX];
1385    char                    *Filename;
1386    ACPI_STATUS             Status;
1387
1388
1389    /* Open the directory for customized tables */
1390
1391    TableDir = AcpiOsOpenDirectory (Pathname, "*", REQUEST_FILE_ONLY);
1392    if (!TableDir)
1393    {
1394        return (OslGetLastStatus (AE_NOT_FOUND));
1395    }
1396
1397    /* Attempt to find the table in the directory */
1398
1399    while ((Filename = AcpiOsGetNextFilename (TableDir)))
1400    {
1401        /* Ignore meaningless files */
1402
1403        if (!ACPI_COMPARE_NAME (Filename, Signature))
1404        {
1405            continue;
1406        }
1407
1408        /* Extract table name and instance number */
1409
1410        Status = OslTableNameFromFile (Filename, TempName, &CurrentInstance);
1411
1412        /* Ignore meaningless files */
1413
1414        if (ACPI_FAILURE (Status) || CurrentInstance != Instance)
1415        {
1416            continue;
1417        }
1418
1419        /* Create the table pathname */
1420
1421        if (Instance != 0)
1422        {
1423            snprintf (TableFilename, sizeof(TableFilename), "%s/%4.4s%d",
1424		Pathname, TempName, Instance);
1425        }
1426        else
1427        {
1428            snprintf (TableFilename, sizeof(TableFilename), "%s/%4.4s",
1429		Pathname, TempName);
1430        }
1431        break;
1432    }
1433
1434    AcpiOsCloseDirectory (TableDir);
1435
1436    if (!Filename)
1437    {
1438        return (AE_LIMIT);
1439    }
1440
1441    /* There is no physical address saved for customized tables, use zero */
1442
1443    *Address = 0;
1444    Status = OslReadTableFromFile (TableFilename, 0, NULL, Table);
1445
1446    return (Status);
1447}
1448