oslinuxtbl.c revision 1.10
1/******************************************************************************
2 *
3 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2019, 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_NAMESEG_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    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_COPY_NAMESEG (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_NAMESEG (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    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    if (!Gbl_DumpCustomizedTables)
690    {
691        /* Get RSDP from memory */
692
693        Status = OslLoadRsdp ();
694        if (ACPI_FAILURE (Status))
695        {
696            return (Status);
697        }
698
699        /* Get XSDT from memory */
700
701        if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt)
702        {
703            if (Gbl_Xsdt)
704            {
705                free (Gbl_Xsdt);
706                Gbl_Xsdt = NULL;
707            }
708
709            Gbl_Revision = 2;
710            Status = OslGetBiosTable (ACPI_SIG_XSDT, 0,
711                ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address);
712            if (ACPI_FAILURE (Status))
713            {
714                return (Status);
715            }
716        }
717
718        /* Get RSDT from memory */
719
720        if (Gbl_Rsdp.RsdtPhysicalAddress)
721        {
722            if (Gbl_Rsdt)
723            {
724                free (Gbl_Rsdt);
725                Gbl_Rsdt = NULL;
726            }
727
728            Status = OslGetBiosTable (ACPI_SIG_RSDT, 0,
729                ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address);
730            if (ACPI_FAILURE (Status))
731            {
732                return (Status);
733            }
734        }
735
736        /* Get FADT from memory */
737
738        if (Gbl_Fadt)
739        {
740            free (Gbl_Fadt);
741            Gbl_Fadt = NULL;
742        }
743
744        Status = OslGetBiosTable (ACPI_SIG_FADT, 0,
745            ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress);
746        if (ACPI_FAILURE (Status))
747        {
748            return (Status);
749        }
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 == 0)
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;
937    ACPI_PHYSICAL_ADDRESS   FirstTableAddress = 0;
938    UINT32                  TableLength = 0;
939    ACPI_STATUS             Status = AE_OK;
940    UINT32                  i;
941
942
943    /* Handle special tables whose addresses are not in RSDT/XSDT */
944
945    if (ACPI_COMPARE_NAMESEG (Signature, ACPI_RSDP_NAME) ||
946        ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_RSDT) ||
947        ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_XSDT) ||
948        ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_DSDT) ||
949        ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_FACS))
950    {
951
952FindNextInstance:
953
954        TableAddress = 0;
955
956        /*
957         * Get the appropriate address, either 32-bit or 64-bit. Be very
958         * careful about the FADT length and validate table addresses.
959         * Note: The 64-bit addresses have priority.
960         */
961        if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_DSDT))
962        {
963            if (CurrentInstance < 2)
964            {
965                if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
966                    Gbl_Fadt->XDsdt && CurrentInstance == 0)
967                {
968                    TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
969                }
970                else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) &&
971                    Gbl_Fadt->Dsdt != FirstTableAddress)
972                {
973                    TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
974                }
975            }
976        }
977        else if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_FACS))
978        {
979            if (CurrentInstance < 2)
980            {
981                if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
982                    Gbl_Fadt->XFacs && CurrentInstance == 0)
983                {
984                    TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
985                }
986                else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) &&
987                    Gbl_Fadt->Facs != FirstTableAddress)
988                {
989                    TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
990                }
991            }
992        }
993        else if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_XSDT))
994        {
995            if (!Gbl_Revision)
996            {
997                return (AE_BAD_SIGNATURE);
998            }
999            if (CurrentInstance == 0)
1000            {
1001                TableAddress =
1002                    (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.XsdtPhysicalAddress;
1003            }
1004        }
1005        else if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_RSDT))
1006        {
1007            if (CurrentInstance == 0)
1008            {
1009                TableAddress =
1010                    (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.RsdtPhysicalAddress;
1011            }
1012        }
1013        else
1014        {
1015            if (CurrentInstance == 0)
1016            {
1017                TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress;
1018                Signature = ACPI_SIG_RSDP;
1019            }
1020        }
1021
1022        if (TableAddress == 0)
1023        {
1024            goto ExitFindTable;
1025        }
1026
1027        /* Now we can get the requested special table */
1028
1029        Status = OslMapTable (TableAddress, Signature, &MappedTable);
1030        if (ACPI_FAILURE (Status))
1031        {
1032            return (Status);
1033        }
1034
1035        TableLength = ApGetTableLength (MappedTable);
1036        if (FirstTableAddress == 0)
1037        {
1038            FirstTableAddress = TableAddress;
1039        }
1040
1041        /* Match table instance */
1042
1043        if (CurrentInstance != Instance)
1044        {
1045            OslUnmapTable (MappedTable);
1046            MappedTable = NULL;
1047            CurrentInstance++;
1048            goto FindNextInstance;
1049        }
1050    }
1051    else /* Case for a normal ACPI table */
1052    {
1053        if (OslCanUseXsdt ())
1054        {
1055            ItemSize = sizeof (UINT64);
1056            TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
1057            NumberOfTables =
1058                (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
1059                / ItemSize);
1060        }
1061        else /* Use RSDT if XSDT is not available */
1062        {
1063            ItemSize = sizeof (UINT32);
1064            TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
1065            NumberOfTables =
1066                (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
1067                / ItemSize);
1068        }
1069
1070        /* Search RSDT/XSDT for the requested table */
1071
1072        for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize)
1073        {
1074            if (OslCanUseXsdt ())
1075            {
1076                TableAddress =
1077                    (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData));
1078            }
1079            else
1080            {
1081                TableAddress =
1082                    (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData));
1083            }
1084
1085            /* Skip NULL entries in RSDT/XSDT */
1086
1087            if (TableAddress == 0)
1088            {
1089                continue;
1090            }
1091
1092            Status = OslMapTable (TableAddress, NULL, &MappedTable);
1093            if (ACPI_FAILURE (Status))
1094            {
1095                return (Status);
1096            }
1097            TableLength = MappedTable->Length;
1098
1099            /* Does this table match the requested signature? */
1100
1101            if (!ACPI_COMPARE_NAMESEG (MappedTable->Signature, Signature))
1102            {
1103                OslUnmapTable (MappedTable);
1104                MappedTable = NULL;
1105                continue;
1106            }
1107
1108            /* Match table instance (for SSDT/UEFI tables) */
1109
1110            if (CurrentInstance != Instance)
1111            {
1112                OslUnmapTable (MappedTable);
1113                MappedTable = NULL;
1114                CurrentInstance++;
1115                continue;
1116            }
1117
1118            break;
1119        }
1120    }
1121
1122ExitFindTable:
1123
1124    if (!MappedTable)
1125    {
1126        return (AE_LIMIT);
1127    }
1128
1129    if (TableLength == 0)
1130    {
1131        Status = AE_BAD_HEADER;
1132        goto Exit;
1133    }
1134
1135    /* Copy table to local buffer and return it */
1136
1137    LocalTable = calloc (1, TableLength);
1138    if (!LocalTable)
1139    {
1140        Status = AE_NO_MEMORY;
1141        goto Exit;
1142    }
1143
1144    memcpy (LocalTable, MappedTable, TableLength);
1145    *Address = TableAddress;
1146    *Table = LocalTable;
1147
1148Exit:
1149    OslUnmapTable (MappedTable);
1150    return (Status);
1151}
1152
1153
1154/******************************************************************************
1155 *
1156 * FUNCTION:    OslListCustomizedTables
1157 *
1158 * PARAMETERS:  Directory           - Directory that contains the tables
1159 *
1160 * RETURN:      Status; Table list is initialized if AE_OK.
1161 *
1162 * DESCRIPTION: Add ACPI tables to the table list from a directory.
1163 *
1164 *****************************************************************************/
1165
1166static ACPI_STATUS
1167OslListCustomizedTables (
1168    char                    *Directory)
1169{
1170    void                    *TableDir;
1171    UINT32                  Instance;
1172    char                    TempName[ACPI_NAMESEG_SIZE];
1173    char                    *Filename;
1174    ACPI_STATUS             Status = AE_OK;
1175
1176
1177    /* Open the requested directory */
1178
1179    TableDir = AcpiOsOpenDirectory (Directory, "*", REQUEST_FILE_ONLY);
1180    if (!TableDir)
1181    {
1182        return (OslGetLastStatus (AE_NOT_FOUND));
1183    }
1184
1185    /* Examine all entries in this directory */
1186
1187    while ((Filename = AcpiOsGetNextFilename (TableDir)))
1188    {
1189        /* Extract table name and instance number */
1190
1191        Status = OslTableNameFromFile (Filename, TempName, &Instance);
1192
1193        /* Ignore meaningless files */
1194
1195        if (ACPI_FAILURE (Status))
1196        {
1197            continue;
1198        }
1199
1200        /* Add new info node to global table list */
1201
1202        Status = OslAddTableToList (TempName, Instance);
1203        if (ACPI_FAILURE (Status))
1204        {
1205            break;
1206        }
1207    }
1208
1209    AcpiOsCloseDirectory (TableDir);
1210    return (Status);
1211}
1212
1213
1214/******************************************************************************
1215 *
1216 * FUNCTION:    OslMapTable
1217 *
1218 * PARAMETERS:  Address             - Address of the table in memory
1219 *              Signature           - Optional ACPI Signature for desired table.
1220 *                                    Null terminated 4-character string.
1221 *              Table               - Where a pointer to the mapped table is
1222 *                                    returned
1223 *
1224 * RETURN:      Status; Mapped table is returned if AE_OK.
1225 *              AE_NOT_FOUND: A valid table was not found at the address
1226 *
1227 * DESCRIPTION: Map entire ACPI table into caller's address space.
1228 *
1229 *****************************************************************************/
1230
1231static ACPI_STATUS
1232OslMapTable (
1233    ACPI_SIZE               Address,
1234    char                    *Signature,
1235    ACPI_TABLE_HEADER       **Table)
1236{
1237    ACPI_TABLE_HEADER       *MappedTable;
1238    UINT32                  Length;
1239
1240
1241    if (!Address)
1242    {
1243        return (AE_BAD_ADDRESS);
1244    }
1245
1246    /*
1247     * Map the header so we can get the table length.
1248     * Use sizeof (ACPI_TABLE_HEADER) as:
1249     * 1. it is bigger than 24 to include RSDP->Length
1250     * 2. it is smaller than sizeof (ACPI_TABLE_RSDP)
1251     */
1252    MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
1253    if (!MappedTable)
1254    {
1255        fprintf (stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1256            ACPI_FORMAT_UINT64 (Address));
1257        return (OslGetLastStatus (AE_BAD_ADDRESS));
1258    }
1259
1260    /* If specified, signature must match */
1261
1262    if (Signature)
1263    {
1264        if (ACPI_VALIDATE_RSDP_SIG (Signature))
1265        {
1266            if (!ACPI_VALIDATE_RSDP_SIG (MappedTable->Signature))
1267            {
1268                AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
1269                return (AE_BAD_SIGNATURE);
1270            }
1271        }
1272        else if (!ACPI_COMPARE_NAMESEG (Signature, MappedTable->Signature))
1273        {
1274            AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
1275            return (AE_BAD_SIGNATURE);
1276        }
1277    }
1278
1279    /* Map the entire table */
1280
1281    Length = ApGetTableLength (MappedTable);
1282    AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
1283    if (Length == 0)
1284    {
1285        return (AE_BAD_HEADER);
1286    }
1287
1288    MappedTable = AcpiOsMapMemory (Address, Length);
1289    if (!MappedTable)
1290    {
1291        fprintf (stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1292            ACPI_FORMAT_UINT64 (Address), Length);
1293        return (OslGetLastStatus (AE_INVALID_TABLE_LENGTH));
1294    }
1295
1296    (void) ApIsValidChecksum (MappedTable);
1297
1298    *Table = MappedTable;
1299    return (AE_OK);
1300}
1301
1302
1303/******************************************************************************
1304 *
1305 * FUNCTION:    OslUnmapTable
1306 *
1307 * PARAMETERS:  Table               - A pointer to the mapped table
1308 *
1309 * RETURN:      None
1310 *
1311 * DESCRIPTION: Unmap entire ACPI table.
1312 *
1313 *****************************************************************************/
1314
1315static void
1316OslUnmapTable (
1317    ACPI_TABLE_HEADER       *Table)
1318{
1319    if (Table)
1320    {
1321        AcpiOsUnmapMemory (Table, ApGetTableLength (Table));
1322    }
1323}
1324
1325
1326/******************************************************************************
1327 *
1328 * FUNCTION:    OslTableNameFromFile
1329 *
1330 * PARAMETERS:  Filename            - File that contains the desired table
1331 *              Signature           - Pointer to 4-character buffer to store
1332 *                                    extracted table signature.
1333 *              Instance            - Pointer to integer to store extracted
1334 *                                    table instance number.
1335 *
1336 * RETURN:      Status; Table name is extracted if AE_OK.
1337 *
1338 * DESCRIPTION: Extract table signature and instance number from a table file
1339 *              name.
1340 *
1341 *****************************************************************************/
1342
1343static ACPI_STATUS
1344OslTableNameFromFile (
1345    char                    *Filename,
1346    char                    *Signature,
1347    UINT32                  *Instance)
1348{
1349
1350    /* Ignore meaningless files */
1351
1352    if (strlen (Filename) < ACPI_NAMESEG_SIZE)
1353    {
1354        return (AE_BAD_SIGNATURE);
1355    }
1356
1357    /* Extract instance number */
1358
1359    if (isdigit ((int) Filename[ACPI_NAMESEG_SIZE]))
1360    {
1361        sscanf (&Filename[ACPI_NAMESEG_SIZE], "%u", Instance);
1362    }
1363    else if (strlen (Filename) != ACPI_NAMESEG_SIZE)
1364    {
1365        return (AE_BAD_SIGNATURE);
1366    }
1367    else
1368    {
1369        *Instance = 0;
1370    }
1371
1372    /* Extract signature */
1373
1374    ACPI_COPY_NAMESEG (Signature, Filename);
1375    return (AE_OK);
1376}
1377
1378
1379/******************************************************************************
1380 *
1381 * FUNCTION:    OslReadTableFromFile
1382 *
1383 * PARAMETERS:  Filename            - File that contains the desired table
1384 *              FileOffset          - Offset of the table in file
1385 *              Signature           - Optional ACPI Signature for desired table.
1386 *                                    A null terminated 4-character string.
1387 *              Table               - Where a pointer to the table is returned
1388 *
1389 * RETURN:      Status; Table buffer is returned if AE_OK.
1390 *
1391 * DESCRIPTION: Read a ACPI table from a file.
1392 *
1393 *****************************************************************************/
1394
1395static ACPI_STATUS
1396OslReadTableFromFile (
1397    char                    *Filename,
1398    ACPI_SIZE               FileOffset,
1399    char                    *Signature,
1400    ACPI_TABLE_HEADER       **Table)
1401{
1402    FILE                    *TableFile;
1403    ACPI_TABLE_HEADER       Header;
1404    ACPI_TABLE_HEADER       *LocalTable = NULL;
1405    UINT32                  TableLength;
1406    INT32                   Count;
1407    ACPI_STATUS             Status = AE_OK;
1408
1409
1410    /* Open the file */
1411
1412    TableFile = fopen (Filename, "rb");
1413    if (TableFile == NULL)
1414    {
1415        fprintf (stderr, "Could not open table file: %s\n", Filename);
1416        return (OslGetLastStatus (AE_NOT_FOUND));
1417    }
1418
1419    fseek (TableFile, FileOffset, SEEK_SET);
1420
1421    /* Read the Table header to get the table length */
1422
1423    Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile);
1424    if (Count != sizeof (ACPI_TABLE_HEADER))
1425    {
1426        fprintf (stderr, "Could not read table header: %s\n", Filename);
1427        Status = AE_BAD_HEADER;
1428        goto Exit;
1429    }
1430
1431    /* If signature is specified, it must match the table */
1432
1433    if (Signature)
1434    {
1435        if (ACPI_VALIDATE_RSDP_SIG (Signature))
1436        {
1437            if (!ACPI_VALIDATE_RSDP_SIG (Header.Signature)) {
1438                fprintf (stderr, "Incorrect RSDP signature: found %8.8s\n",
1439                    Header.Signature);
1440                Status = AE_BAD_SIGNATURE;
1441                goto Exit;
1442            }
1443        }
1444        else if (!ACPI_COMPARE_NAMESEG (Signature, Header.Signature))
1445        {
1446            fprintf (stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1447                Signature, Header.Signature);
1448            Status = AE_BAD_SIGNATURE;
1449            goto Exit;
1450        }
1451    }
1452
1453    TableLength = ApGetTableLength (&Header);
1454    if (TableLength == 0)
1455    {
1456        Status = AE_BAD_HEADER;
1457        goto Exit;
1458    }
1459
1460    /* Read the entire table into a local buffer */
1461
1462    LocalTable = calloc (1, TableLength);
1463    if (!LocalTable)
1464    {
1465        fprintf (stderr,
1466            "%4.4s: Could not allocate buffer for table of length %X\n",
1467            Header.Signature, TableLength);
1468        Status = AE_NO_MEMORY;
1469        goto Exit;
1470    }
1471
1472    fseek (TableFile, FileOffset, SEEK_SET);
1473
1474    Count = fread (LocalTable, 1, TableLength, TableFile);
1475    if (Count != TableLength)
1476    {
1477        fprintf (stderr, "%4.4s: Could not read table content\n",
1478            Header.Signature);
1479        Status = AE_INVALID_TABLE_LENGTH;
1480        goto Exit;
1481    }
1482
1483    /* Validate checksum */
1484
1485    (void) ApIsValidChecksum (LocalTable);
1486
1487Exit:
1488    fclose (TableFile);
1489    *Table = LocalTable;
1490    return (Status);
1491}
1492
1493
1494/******************************************************************************
1495 *
1496 * FUNCTION:    OslGetCustomizedTable
1497 *
1498 * PARAMETERS:  Pathname        - Directory to find Linux customized table
1499 *              Signature       - ACPI Signature for desired table. Must be
1500 *                                a null terminated 4-character string.
1501 *              Instance        - Multiple table support for SSDT/UEFI (0...n)
1502 *                                Must be 0 for other tables.
1503 *              Table           - Where a pointer to the table is returned
1504 *              Address         - Where the table physical address is returned
1505 *
1506 * RETURN:      Status; Table buffer is returned if AE_OK.
1507 *              AE_LIMIT: Instance is beyond valid limit
1508 *              AE_NOT_FOUND: A table with the signature was not found
1509 *
1510 * DESCRIPTION: Get an OS customized table.
1511 *
1512 *****************************************************************************/
1513
1514static ACPI_STATUS
1515OslGetCustomizedTable (
1516    char                    *Pathname,
1517    char                    *Signature,
1518    UINT32                  Instance,
1519    ACPI_TABLE_HEADER       **Table,
1520    ACPI_PHYSICAL_ADDRESS   *Address)
1521{
1522    void                    *TableDir;
1523    UINT32                  CurrentInstance = 0;
1524    char                    TempName[ACPI_NAMESEG_SIZE];
1525    char                    TableFilename[PATH_MAX];
1526    char                    *Filename;
1527    ACPI_STATUS             Status;
1528
1529
1530    /* Open the directory for customized tables */
1531
1532    TableDir = AcpiOsOpenDirectory (Pathname, "*", REQUEST_FILE_ONLY);
1533    if (!TableDir)
1534    {
1535        return (OslGetLastStatus (AE_NOT_FOUND));
1536    }
1537
1538    /* Attempt to find the table in the directory */
1539
1540    while ((Filename = AcpiOsGetNextFilename (TableDir)))
1541    {
1542        /* Ignore meaningless files */
1543
1544        if (!ACPI_COMPARE_NAMESEG (Filename, Signature))
1545        {
1546            continue;
1547        }
1548
1549        /* Extract table name and instance number */
1550
1551        Status = OslTableNameFromFile (Filename, TempName, &CurrentInstance);
1552
1553        /* Ignore meaningless files */
1554
1555        if (ACPI_FAILURE (Status) || CurrentInstance != Instance)
1556        {
1557            continue;
1558        }
1559
1560        /* Create the table pathname */
1561
1562        if (Instance != 0)
1563        {
1564            snprintf (TableFilename, sizeof(TableFilename), "%s/%4.4s%d",
1565		Pathname, TempName, Instance);
1566        }
1567        else
1568        {
1569            snprintf (TableFilename, sizeof(TableFilename), "%s/%4.4s",
1570		Pathname, TempName);
1571        }
1572        break;
1573    }
1574
1575    AcpiOsCloseDirectory (TableDir);
1576
1577    if (!Filename)
1578    {
1579        return (AE_LIMIT);
1580    }
1581
1582    /* There is no physical address saved for customized tables, use zero */
1583
1584    *Address = 0;
1585    Status = OslReadTableFromFile (TableFilename, 0, NULL, Table);
1586
1587    return (Status);
1588}
1589