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