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