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