xref: /netbsd-src/sys/external/bsd/acpica/dist/os_specific/service_layers/oslinuxtbl.c (revision 796c32c94f6e154afc9de0f63da35c91bb739b45)
1 /******************************************************************************
2  *
3  * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2017, 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 
58 typedef struct osl_table_info
59 {
60     struct osl_table_info   *Next;
61     UINT32                  Instance;
62     char                    Signature[ACPI_NAME_SIZE];
63 
64 } OSL_TABLE_INFO;
65 
66 /* Local prototypes */
67 
68 static ACPI_STATUS
69 OslTableInitialize (
70     void);
71 
72 static ACPI_STATUS
73 OslTableNameFromFile (
74     char                    *Filename,
75     char                    *Signature,
76     UINT32                  *Instance);
77 
78 static ACPI_STATUS
79 OslAddTableToList (
80     char                    *Signature,
81     UINT32                  Instance);
82 
83 static ACPI_STATUS
84 OslReadTableFromFile (
85     char                    *Filename,
86     ACPI_SIZE               FileOffset,
87     char                    *Signature,
88     ACPI_TABLE_HEADER       **Table);
89 
90 static ACPI_STATUS
91 OslMapTable (
92     ACPI_SIZE               Address,
93     char                    *Signature,
94     ACPI_TABLE_HEADER       **Table);
95 
96 static void
97 OslUnmapTable (
98     ACPI_TABLE_HEADER       *Table);
99 
100 static ACPI_PHYSICAL_ADDRESS
101 OslFindRsdpViaEfiByKeyword (
102     FILE                    *File,
103     const char              *Keyword);
104 
105 static ACPI_PHYSICAL_ADDRESS
106 OslFindRsdpViaEfi (
107     void);
108 
109 static ACPI_STATUS
110 OslLoadRsdp (
111     void);
112 
113 static ACPI_STATUS
114 OslListCustomizedTables (
115     char                    *Directory);
116 
117 static ACPI_STATUS
118 OslGetCustomizedTable (
119     char                    *Pathname,
120     char                    *Signature,
121     UINT32                  Instance,
122     ACPI_TABLE_HEADER       **Table,
123     ACPI_PHYSICAL_ADDRESS   *Address);
124 
125 static ACPI_STATUS
126 OslListBiosTables (
127     void);
128 
129 static ACPI_STATUS
130 OslGetBiosTable (
131     char                    *Signature,
132     UINT32                  Instance,
133     ACPI_TABLE_HEADER       **Table,
134     ACPI_PHYSICAL_ADDRESS   *Address);
135 
136 static ACPI_STATUS
137 OslGetLastStatus (
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 
149 UINT8                   Gbl_DumpDynamicTables = TRUE;
150 
151 /* Initialization flags */
152 
153 UINT8                   Gbl_TableListInitialized = FALSE;
154 
155 /* Local copies of main ACPI tables */
156 
157 ACPI_TABLE_RSDP         Gbl_Rsdp;
158 ACPI_TABLE_FADT         *Gbl_Fadt = NULL;
159 ACPI_TABLE_RSDT         *Gbl_Rsdt = NULL;
160 ACPI_TABLE_XSDT         *Gbl_Xsdt = NULL;
161 
162 /* Table addresses */
163 
164 ACPI_PHYSICAL_ADDRESS   Gbl_FadtAddress = 0;
165 ACPI_PHYSICAL_ADDRESS   Gbl_RsdpAddress = 0;
166 
167 /* Revision of RSD PTR */
168 
169 UINT8                   Gbl_Revision = 0;
170 
171 OSL_TABLE_INFO          *Gbl_TableListHead = NULL;
172 UINT32                  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 
187 static ACPI_STATUS
188 OslGetLastStatus (
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 
228 ACPI_STATUS
229 AcpiOsGetTableByAddress (
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 
273 Exit:
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 
299 ACPI_STATUS
300 AcpiOsGetTableByName (
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 
362 static ACPI_STATUS
363 OslAddTableToList (
364     char                    *Signature,
365     UINT32                  Instance)
366 {
367     OSL_TABLE_INFO          *NewInfo;
368     OSL_TABLE_INFO          *Next;
369     UINT32                  NextInstance = 0;
370     BOOLEAN                 Found = FALSE;
371 
372 
373     NewInfo = calloc (1, sizeof (OSL_TABLE_INFO));
374     if (!NewInfo)
375     {
376         return (AE_NO_MEMORY);
377     }
378 
379     ACPI_MOVE_NAME (NewInfo->Signature, Signature);
380 
381     if (!Gbl_TableListHead)
382     {
383         Gbl_TableListHead = NewInfo;
384     }
385     else
386     {
387         Next = Gbl_TableListHead;
388         while (1)
389         {
390             if (ACPI_COMPARE_NAME (Next->Signature, Signature))
391             {
392                 if (Next->Instance == Instance)
393                 {
394                     Found = TRUE;
395                 }
396                 if (Next->Instance >= NextInstance)
397                 {
398                     NextInstance = Next->Instance + 1;
399                 }
400             }
401 
402             if (!Next->Next)
403             {
404                 break;
405             }
406             Next = Next->Next;
407         }
408         Next->Next = NewInfo;
409     }
410 
411     if (Found)
412     {
413         if (Instance)
414         {
415             fprintf (stderr,
416                 "%4.4s: Warning unmatched table instance %d, expected %d\n",
417                 Signature, Instance, NextInstance);
418         }
419         Instance = NextInstance;
420     }
421 
422     NewInfo->Instance = Instance;
423     Gbl_TableCount++;
424 
425     return (AE_OK);
426 }
427 
428 
429 /******************************************************************************
430  *
431  * FUNCTION:    AcpiOsGetTableByIndex
432  *
433  * PARAMETERS:  Index           - Which table to get
434  *              Table           - Where a pointer to the table is returned
435  *              Instance        - Where a pointer to the table instance no. is
436  *                                returned
437  *              Address         - Where the table physical address is returned
438  *
439  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
440  *              AE_LIMIT: Index is beyond valid limit
441  *
442  * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
443  *              AE_LIMIT when an invalid index is reached. Index is not
444  *              necessarily an index into the RSDT/XSDT.
445  *
446  *****************************************************************************/
447 
448 ACPI_STATUS
449 AcpiOsGetTableByIndex (
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 
510 static ACPI_PHYSICAL_ADDRESS
511 OslFindRsdpViaEfiByKeyword (
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 
546 static ACPI_PHYSICAL_ADDRESS
547 OslFindRsdpViaEfi (
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 
581 static ACPI_STATUS
582 OslLoadRsdp (
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 
647 static BOOLEAN
648 OslCanUseXsdt (
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 
676 static ACPI_STATUS
677 OslTableInitialize (
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 
836 static ACPI_STATUS
837 OslListBiosTables (
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 
923 static ACPI_STATUS
924 OslGetBiosTable (
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_NAME (Signature, ACPI_RSDP_NAME) ||
946         ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT) ||
947         ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT) ||
948         ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) ||
949         ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
950     {
951 
952 FindNextInstance:
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_NAME (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_NAME (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_NAME (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_NAME (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_NAME (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 
1122 ExitFindTable:
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 
1148 Exit:
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 
1166 static ACPI_STATUS
1167 OslListCustomizedTables (
1168     char                    *Directory)
1169 {
1170     void                    *TableDir;
1171     UINT32                  Instance;
1172     char                    TempName[ACPI_NAME_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 
1231 static ACPI_STATUS
1232 OslMapTable (
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_NAME (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 
1315 static void
1316 OslUnmapTable (
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 
1343 static ACPI_STATUS
1344 OslTableNameFromFile (
1345     char                    *Filename,
1346     char                    *Signature,
1347     UINT32                  *Instance)
1348 {
1349 
1350     /* Ignore meaningless files */
1351 
1352     if (strlen (Filename) < ACPI_NAME_SIZE)
1353     {
1354         return (AE_BAD_SIGNATURE);
1355     }
1356 
1357     /* Extract instance number */
1358 
1359     if (isdigit ((int) Filename[ACPI_NAME_SIZE]))
1360     {
1361         sscanf (&Filename[ACPI_NAME_SIZE], "%u", Instance);
1362     }
1363     else if (strlen (Filename) != ACPI_NAME_SIZE)
1364     {
1365         return (AE_BAD_SIGNATURE);
1366     }
1367     else
1368     {
1369         *Instance = 0;
1370     }
1371 
1372     /* Extract signature */
1373 
1374     ACPI_MOVE_NAME (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 
1395 static ACPI_STATUS
1396 OslReadTableFromFile (
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_NAME (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 
1487 Exit:
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 
1514 static ACPI_STATUS
1515 OslGetCustomizedTable (
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_NAME_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_NAME (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