kernel: Sync ACPICA with Intel's version 20140114.
[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          table_info
59 {
60     struct 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 ErrorExit;
257     }
258
259     LocalTable = calloc (1, TableLength);
260     if (!LocalTable)
261     {
262         Status = AE_NO_MEMORY;
263         goto ErrorExit;
264     }
265
266     ACPI_MEMCPY (LocalTable, MappedTable, TableLength);
267
268 ErrorExit:
269     OslUnmapTable (MappedTable);
270     *Table = LocalTable;
271     return (AE_OK);
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:    OslTableInitialize
597  *
598  * PARAMETERS:  None
599  *
600  * RETURN:      Status
601  *
602  * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
603  *              local variables. Main ACPI tables include RSDT, FADT, RSDT,
604  *              and/or XSDT.
605  *
606  *****************************************************************************/
607
608 static ACPI_STATUS
609 OslTableInitialize (
610     void)
611 {
612     ACPI_STATUS             Status;
613     ACPI_PHYSICAL_ADDRESS   Address;
614
615
616     if (Gbl_TableListInitialized)
617     {
618         return (AE_OK);
619     }
620
621     /* Get RSDP from memory */
622
623     Status = OslLoadRsdp ();
624     if (ACPI_FAILURE (Status))
625     {
626         return (Status);
627     }
628
629     /* Get XSDT from memory */
630
631     if (Gbl_Rsdp.Revision)
632     {
633         if (Gbl_Xsdt)
634         {
635             free (Gbl_Xsdt);
636             Gbl_Xsdt = NULL;
637         }
638
639         Gbl_Revision = 2;
640         Status = OslGetBiosTable (ACPI_SIG_XSDT, 0,
641             ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address);
642         if (ACPI_FAILURE (Status))
643         {
644             return (Status);
645         }
646     }
647
648     /* Get RSDT from memory */
649
650     if (Gbl_Rsdp.RsdtPhysicalAddress)
651     {
652         if (Gbl_Rsdt)
653         {
654             free (Gbl_Rsdt);
655             Gbl_Rsdt = NULL;
656         }
657
658         Status = OslGetBiosTable (ACPI_SIG_RSDT, 0,
659             ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address);
660         if (ACPI_FAILURE (Status))
661         {
662             return (Status);
663         }
664     }
665
666     /* Get FADT from memory */
667
668     if (Gbl_Fadt)
669     {
670         free (Gbl_Fadt);
671         Gbl_Fadt = NULL;
672     }
673
674     Status = OslGetBiosTable (ACPI_SIG_FADT, 0,
675         ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress);
676     if (ACPI_FAILURE (Status))
677     {
678         return (Status);
679     }
680
681     if (!Gbl_DumpCustomizedTables)
682     {
683         /* Add mandatory tables to global table list first */
684
685         Status = OslAddTableToList (ACPI_RSDP_NAME, 0);
686         if (ACPI_FAILURE (Status))
687         {
688             return (Status);
689         }
690
691         Status = OslAddTableToList (ACPI_SIG_RSDT, 0);
692         if (ACPI_FAILURE (Status))
693         {
694             return (Status);
695         }
696
697         if (Gbl_Revision == 2)
698         {
699             Status = OslAddTableToList (ACPI_SIG_XSDT, 0);
700             if (ACPI_FAILURE (Status))
701             {
702                 return (Status);
703             }
704         }
705
706         Status = OslAddTableToList (ACPI_SIG_DSDT, 0);
707         if (ACPI_FAILURE (Status))
708         {
709             return (Status);
710         }
711
712         Status = OslAddTableToList (ACPI_SIG_FACS, 0);
713         if (ACPI_FAILURE (Status))
714         {
715             return (Status);
716         }
717
718         /* Add all tables found in the memory */
719
720         Status = OslListBiosTables ();
721         if (ACPI_FAILURE (Status))
722         {
723             return (Status);
724         }
725     }
726     else
727     {
728         /* Add all tables found in the static directory */
729
730         Status = OslListCustomizedTables (STATIC_TABLE_DIR);
731         if (ACPI_FAILURE (Status))
732         {
733             return (Status);
734         }
735     }
736
737     if (Gbl_DumpDynamicTables)
738     {
739         /* Add all dynamically loaded tables in the dynamic directory */
740
741         Status = OslListCustomizedTables (DYNAMIC_TABLE_DIR);
742         if (ACPI_FAILURE (Status))
743         {
744             return (Status);
745         }
746     }
747
748     Gbl_TableListInitialized = TRUE;
749     return (AE_OK);
750 }
751
752
753 /******************************************************************************
754  *
755  * FUNCTION:    OslListBiosTables
756  *
757  * PARAMETERS:  None
758  *
759  * RETURN:      Status; Table list is initialized if AE_OK.
760  *
761  * DESCRIPTION: Add ACPI tables to the table list from memory.
762  *
763  * NOTE:        This works on Linux as table customization does not modify the
764  *              addresses stored in RSDP/RSDT/XSDT/FADT.
765  *
766  *****************************************************************************/
767
768 static ACPI_STATUS
769 OslListBiosTables (
770     void)
771 {
772     ACPI_TABLE_HEADER       *MappedTable = NULL;
773     UINT8                   *TableData;
774     UINT8                   NumberOfTables;
775     UINT8                   ItemSize;
776     ACPI_PHYSICAL_ADDRESS   TableAddress = 0;
777     ACPI_STATUS             Status = AE_OK;
778     UINT32                  i;
779
780
781     if (Gbl_Revision)
782     {
783         ItemSize = sizeof (UINT64);
784         TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
785         NumberOfTables =
786             (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
787             / ItemSize);
788     }
789     else /* Use RSDT if XSDT is not available */
790     {
791         ItemSize = sizeof (UINT32);
792         TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
793         NumberOfTables =
794             (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
795             / ItemSize);
796     }
797
798     /* Search RSDT/XSDT for the requested table */
799
800     for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize)
801     {
802         if (Gbl_Revision)
803         {
804             TableAddress =
805                 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData));
806         }
807         else
808         {
809             TableAddress =
810                 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData));
811         }
812
813         Status = OslMapTable (TableAddress, NULL, &MappedTable);
814         if (ACPI_FAILURE (Status))
815         {
816             return (Status);
817         }
818
819         OslAddTableToList (MappedTable->Signature, 0);
820         OslUnmapTable (MappedTable);
821     }
822
823     return (AE_OK);
824 }
825
826
827 /******************************************************************************
828  *
829  * FUNCTION:    OslGetBiosTable
830  *
831  * PARAMETERS:  Signature       - ACPI Signature for common table. Must be
832  *                                a null terminated 4-character string.
833  *              Instance        - Multiple table support for SSDT/UEFI (0...n)
834  *                                Must be 0 for other tables.
835  *              Table           - Where a pointer to the table is returned
836  *              Address         - Where the table physical address is returned
837  *
838  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
839  *              AE_LIMIT: Instance is beyond valid limit
840  *              AE_NOT_FOUND: A table with the signature was not found
841  *
842  * DESCRIPTION: Get a BIOS provided ACPI table
843  *
844  * NOTE:        Assumes the input signature is uppercase.
845  *
846  *****************************************************************************/
847
848 static ACPI_STATUS
849 OslGetBiosTable (
850     char                    *Signature,
851     UINT32                  Instance,
852     ACPI_TABLE_HEADER       **Table,
853     ACPI_PHYSICAL_ADDRESS   *Address)
854 {
855     ACPI_TABLE_HEADER       *LocalTable = NULL;
856     ACPI_TABLE_HEADER       *MappedTable = NULL;
857     UINT8                   *TableData;
858     UINT8                   NumberOfTables;
859     UINT8                   ItemSize;
860     UINT32                  CurrentInstance = 0;
861     ACPI_PHYSICAL_ADDRESS   TableAddress = 0;
862     UINT32                  TableLength = 0;
863     ACPI_STATUS             Status = AE_OK;
864     UINT32                  i;
865
866
867     /* Handle special tables whose addresses are not in RSDT/XSDT */
868
869     if (ACPI_COMPARE_NAME (Signature, ACPI_RSDP_NAME) ||
870         ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT) ||
871         ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT) ||
872         ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) ||
873         ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
874     {
875         /*
876          * Get the appropriate address, either 32-bit or 64-bit. Be very
877          * careful about the FADT length and validate table addresses.
878          * Note: The 64-bit addresses have priority.
879          */
880         if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT))
881         {
882             if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
883                 Gbl_Fadt->XDsdt)
884             {
885                 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
886             }
887             else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) &&
888                 Gbl_Fadt->Dsdt)
889             {
890                 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
891             }
892         }
893         else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
894         {
895             if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
896                 Gbl_Fadt->XFacs)
897             {
898                 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
899             }
900             else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) &&
901                 Gbl_Fadt->Facs)
902             {
903                 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
904             }
905         }
906         else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT))
907         {
908             if (!Gbl_Revision)
909             {
910                 return (AE_BAD_SIGNATURE);
911             }
912             TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.XsdtPhysicalAddress;
913         }
914         else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT))
915         {
916             TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.RsdtPhysicalAddress;
917         }
918         else
919         {
920             TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress;
921             Signature = ACPI_SIG_RSDP;
922         }
923
924         /* Now we can get the requested special table */
925
926         Status = OslMapTable (TableAddress, Signature, &MappedTable);
927         if (ACPI_FAILURE (Status))
928         {
929             return (Status);
930         }
931
932         TableLength = ApGetTableLength (MappedTable);
933     }
934     else /* Case for a normal ACPI table */
935     {
936         if (Gbl_Revision)
937         {
938             ItemSize = sizeof (UINT64);
939             TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
940             NumberOfTables =
941                 (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
942                 / ItemSize);
943         }
944         else /* Use RSDT if XSDT is not available */
945         {
946             ItemSize = sizeof (UINT32);
947             TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
948             NumberOfTables =
949                 (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
950                 / ItemSize);
951         }
952
953         /* Search RSDT/XSDT for the requested table */
954
955         for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize)
956         {
957             if (Gbl_Revision)
958             {
959                 TableAddress =
960                     (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData));
961             }
962             else
963             {
964                 TableAddress =
965                     (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData));
966             }
967
968             Status = OslMapTable (TableAddress, NULL, &MappedTable);
969             if (ACPI_FAILURE (Status))
970             {
971                 return (Status);
972             }
973             TableLength = MappedTable->Length;
974
975             /* Does this table match the requested signature? */
976
977             if (!ACPI_COMPARE_NAME (MappedTable->Signature, Signature))
978             {
979                 OslUnmapTable (MappedTable);
980                 MappedTable = NULL;
981                 continue;
982             }
983
984             /* Match table instance (for SSDT/UEFI tables) */
985
986             if (CurrentInstance != Instance)
987             {
988                 OslUnmapTable (MappedTable);
989                 MappedTable = NULL;
990                 CurrentInstance++;
991                 continue;
992             }
993
994             break;
995         }
996     }
997
998     if (!MappedTable)
999     {
1000         return (AE_LIMIT);
1001     }
1002
1003     if (TableLength == 0)
1004     {
1005         Status = AE_BAD_HEADER;
1006         goto ErrorExit;
1007     }
1008
1009     /* Copy table to local buffer and return it */
1010
1011     LocalTable = calloc (1, TableLength);
1012     if (!LocalTable)
1013     {
1014         Status = AE_NO_MEMORY;
1015         goto ErrorExit;
1016     }
1017
1018     ACPI_MEMCPY (LocalTable, MappedTable, TableLength);
1019     *Address = TableAddress;
1020     *Table = LocalTable;
1021
1022 ErrorExit:
1023     OslUnmapTable (MappedTable);
1024     return (AE_OK);
1025 }
1026
1027
1028 /******************************************************************************
1029  *
1030  * FUNCTION:    OslListCustomizedTables
1031  *
1032  * PARAMETERS:  Directory           - Directory that contains the tables
1033  *
1034  * RETURN:      Status; Table list is initialized if AE_OK.
1035  *
1036  * DESCRIPTION: Add ACPI tables to the table list from a directory.
1037  *
1038  *****************************************************************************/
1039
1040 static ACPI_STATUS
1041 OslListCustomizedTables (
1042     char                    *Directory)
1043 {
1044     void                    *TableDir;
1045     UINT32                  Instance;
1046     char                    TempName[ACPI_NAME_SIZE];
1047     char                    *Filename;
1048     ACPI_STATUS             Status = AE_OK;
1049
1050
1051     /* Open the requested directory */
1052
1053     TableDir = AcpiOsOpenDirectory (Directory, "*", REQUEST_FILE_ONLY);
1054     if (!TableDir)
1055     {
1056         return (OslGetLastStatus (AE_NOT_FOUND));
1057     }
1058
1059     /* Examine all entries in this directory */
1060
1061     while ((Filename = AcpiOsGetNextFilename (TableDir)))
1062     {
1063         /* Extract table name and instance number */
1064
1065         Status = OslTableNameFromFile (Filename, TempName, &Instance);
1066
1067         /* Ignore meaningless files */
1068
1069         if (ACPI_FAILURE (Status))
1070         {
1071             continue;
1072         }
1073
1074         /* Add new info node to global table list */
1075
1076         Status = OslAddTableToList (TempName, Instance);
1077         if (ACPI_FAILURE (Status))
1078         {
1079             break;
1080         }
1081     }
1082
1083     AcpiOsCloseDirectory (TableDir);
1084     return (Status);
1085 }
1086
1087
1088 /******************************************************************************
1089  *
1090  * FUNCTION:    OslMapTable
1091  *
1092  * PARAMETERS:  Address             - Address of the table in memory
1093  *              Signature           - Optional ACPI Signature for desired table.
1094  *                                    Null terminated 4-character string.
1095  *              Table               - Where a pointer to the mapped table is
1096  *                                    returned
1097  *
1098  * RETURN:      Status; Mapped table is returned if AE_OK.
1099  *              AE_NOT_FOUND: A valid table was not found at the address
1100  *
1101  * DESCRIPTION: Map entire ACPI table into caller's address space.
1102  *
1103  *****************************************************************************/
1104
1105 static ACPI_STATUS
1106 OslMapTable (
1107     ACPI_SIZE               Address,
1108     char                    *Signature,
1109     ACPI_TABLE_HEADER       **Table)
1110 {
1111     ACPI_TABLE_HEADER       *MappedTable;
1112     UINT32                  Length;
1113
1114
1115     if (!Address)
1116     {
1117         return (AE_BAD_ADDRESS);
1118     }
1119
1120     /*
1121      * Map the header so we can get the table length.
1122      * Use sizeof (ACPI_TABLE_HEADER) as:
1123      * 1. it is bigger than 24 to include RSDP->Length
1124      * 2. it is smaller than sizeof (ACPI_TABLE_RSDP)
1125      */
1126     MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER));
1127     if (!MappedTable)
1128     {
1129         fprintf (stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1130             ACPI_FORMAT_UINT64 (Address));
1131         return (OslGetLastStatus (AE_BAD_ADDRESS));
1132     }
1133
1134     /* If specified, signature must match */
1135
1136     if (Signature &&
1137         !ACPI_COMPARE_NAME (Signature, MappedTable->Signature))
1138     {
1139         AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
1140         return (AE_BAD_SIGNATURE);
1141     }
1142
1143     /* Map the entire table */
1144
1145     Length = ApGetTableLength (MappedTable);
1146     AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER));
1147     if (Length == 0)
1148     {
1149         return (AE_BAD_HEADER);
1150     }
1151
1152     MappedTable = AcpiOsMapMemory (Address, Length);
1153     if (!MappedTable)
1154     {
1155         fprintf (stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1156             ACPI_FORMAT_UINT64 (Address), Length);
1157         return (OslGetLastStatus (AE_INVALID_TABLE_LENGTH));
1158     }
1159
1160     (void) ApIsValidChecksum (MappedTable);
1161
1162     *Table = MappedTable;
1163     return (AE_OK);
1164 }
1165
1166
1167 /******************************************************************************
1168  *
1169  * FUNCTION:    OslUnmapTable
1170  *
1171  * PARAMETERS:  Table               - A pointer to the mapped table
1172  *
1173  * RETURN:      None
1174  *
1175  * DESCRIPTION: Unmap entire ACPI table.
1176  *
1177  *****************************************************************************/
1178
1179 static void
1180 OslUnmapTable (
1181     ACPI_TABLE_HEADER       *Table)
1182 {
1183     if (Table)
1184     {
1185         AcpiOsUnmapMemory (Table, ApGetTableLength (Table));
1186     }
1187 }
1188
1189
1190 /******************************************************************************
1191  *
1192  * FUNCTION:    OslTableNameFromFile
1193  *
1194  * PARAMETERS:  Filename            - File that contains the desired table
1195  *              Signature           - Pointer to 4-character buffer to store
1196  *                                    extracted table signature.
1197  *              Instance            - Pointer to integer to store extracted
1198  *                                    table instance number.
1199  *
1200  * RETURN:      Status; Table name is extracted if AE_OK.
1201  *
1202  * DESCRIPTION: Extract table signature and instance number from a table file
1203  *              name.
1204  *
1205  *****************************************************************************/
1206
1207 static ACPI_STATUS
1208 OslTableNameFromFile (
1209     char                    *Filename,
1210     char                    *Signature,
1211     UINT32                  *Instance)
1212 {
1213
1214     /* Ignore meaningless files */
1215
1216     if (strlen (Filename) < ACPI_NAME_SIZE)
1217     {
1218         return (AE_BAD_SIGNATURE);
1219     }
1220
1221     /* Extract instance number */
1222
1223     if (isdigit ((int) Filename[ACPI_NAME_SIZE]))
1224     {
1225         sscanf (&Filename[ACPI_NAME_SIZE], "%d", Instance);
1226     }
1227     else if (strlen (Filename) != ACPI_NAME_SIZE)
1228     {
1229         return (AE_BAD_SIGNATURE);
1230     }
1231     else
1232     {
1233         *Instance = 0;
1234     }
1235
1236     /* Extract signature */
1237
1238     ACPI_MOVE_NAME (Signature, Filename);
1239     return (AE_OK);
1240 }
1241
1242
1243 /******************************************************************************
1244  *
1245  * FUNCTION:    OslReadTableFromFile
1246  *
1247  * PARAMETERS:  Filename            - File that contains the desired table
1248  *              FileOffset          - Offset of the table in file
1249  *              Signature           - Optional ACPI Signature for desired table.
1250  *                                    A null terminated 4-character string.
1251  *              Table               - Where a pointer to the table is returned
1252  *
1253  * RETURN:      Status; Table buffer is returned if AE_OK.
1254  *
1255  * DESCRIPTION: Read a ACPI table from a file.
1256  *
1257  *****************************************************************************/
1258
1259 static ACPI_STATUS
1260 OslReadTableFromFile (
1261     char                    *Filename,
1262     ACPI_SIZE               FileOffset,
1263     char                    *Signature,
1264     ACPI_TABLE_HEADER       **Table)
1265 {
1266     FILE                    *TableFile;
1267     ACPI_TABLE_HEADER       Header;
1268     ACPI_TABLE_HEADER       *LocalTable = NULL;
1269     UINT32                  TableLength;
1270     INT32                   Count;
1271     UINT32                  Total = 0;
1272     ACPI_STATUS             Status = AE_OK;
1273
1274
1275     /* Open the file */
1276
1277     TableFile = fopen (Filename, "rb");
1278     if (TableFile == NULL)
1279     {
1280         fprintf (stderr, "Could not open table file: %s\n", Filename);
1281         return (OslGetLastStatus (AE_NOT_FOUND));
1282     }
1283
1284     fseek (TableFile, FileOffset, SEEK_SET);
1285
1286     /* Read the Table header to get the table length */
1287
1288     Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile);
1289     if (Count != sizeof (ACPI_TABLE_HEADER))
1290     {
1291         fprintf (stderr, "Could not read table header: %s\n", Filename);
1292         Status = AE_BAD_HEADER;
1293         goto ErrorExit;
1294     }
1295
1296     /* If signature is specified, it must match the table */
1297
1298     if (Signature &&
1299         !ACPI_COMPARE_NAME (Signature, Header.Signature))
1300     {
1301         fprintf (stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1302             Signature, Header.Signature);
1303         Status = AE_BAD_SIGNATURE;
1304         goto ErrorExit;
1305     }
1306
1307     TableLength = ApGetTableLength (&Header);
1308     if (TableLength == 0)
1309     {
1310         Status = AE_BAD_HEADER;
1311         goto ErrorExit;
1312     }
1313
1314     /* Read the entire table into a local buffer */
1315
1316     LocalTable = calloc (1, TableLength);
1317     if (!LocalTable)
1318     {
1319         fprintf (stderr,
1320             "%4.4s: Could not allocate buffer for table of length %X\n",
1321             Header.Signature, TableLength);
1322         Status = AE_NO_MEMORY;
1323         goto ErrorExit;
1324     }
1325
1326     fseek (TableFile, FileOffset, SEEK_SET);
1327
1328     while (!feof (TableFile) && Total < TableLength)
1329     {
1330         Count = fread (LocalTable, 1, TableLength-Total, TableFile);
1331         if (Count < 0)
1332         {
1333             fprintf (stderr, "%4.4s: Could not read table content\n",
1334                 Header.Signature);
1335             Status = AE_INVALID_TABLE_LENGTH;
1336             goto ErrorExit;
1337         }
1338
1339         Total += Count;
1340     }
1341
1342     /* Validate checksum */
1343
1344     (void) ApIsValidChecksum (LocalTable);
1345
1346 ErrorExit:
1347     fclose (TableFile);
1348     *Table = LocalTable;
1349     return (Status);
1350 }
1351
1352
1353 /******************************************************************************
1354  *
1355  * FUNCTION:    OslGetCustomizedTable
1356  *
1357  * PARAMETERS:  Pathname        - Directory to find Linux customized table
1358  *              Signature       - ACPI Signature for desired table. Must be
1359  *                                a null terminated 4-character string.
1360  *              Instance        - Multiple table support for SSDT/UEFI (0...n)
1361  *                                Must be 0 for other tables.
1362  *              Table           - Where a pointer to the table is returned
1363  *              Address         - Where the table physical address is returned
1364  *
1365  * RETURN:      Status; Table buffer is returned if AE_OK.
1366  *              AE_LIMIT: Instance is beyond valid limit
1367  *              AE_NOT_FOUND: A table with the signature was not found
1368  *
1369  * DESCRIPTION: Get an OS customized table.
1370  *
1371  *****************************************************************************/
1372
1373 static ACPI_STATUS
1374 OslGetCustomizedTable (
1375     char                    *Pathname,
1376     char                    *Signature,
1377     UINT32                  Instance,
1378     ACPI_TABLE_HEADER       **Table,
1379     ACPI_PHYSICAL_ADDRESS   *Address)
1380 {
1381     void                    *TableDir;
1382     UINT32                  CurrentInstance = 0;
1383     char                    TempName[ACPI_NAME_SIZE];
1384     char                    TableFilename[PATH_MAX];
1385     char                    *Filename;
1386     ACPI_STATUS             Status;
1387
1388
1389     /* Open the directory for customized tables */
1390
1391     TableDir = AcpiOsOpenDirectory (Pathname, "*", REQUEST_FILE_ONLY);
1392     if (!TableDir)
1393     {
1394         return (OslGetLastStatus (AE_NOT_FOUND));
1395     }
1396
1397     /* Attempt to find the table in the directory */
1398
1399     while ((Filename = AcpiOsGetNextFilename (TableDir)))
1400     {
1401         /* Ignore meaningless files */
1402
1403         if (!ACPI_COMPARE_NAME (Filename, Signature))
1404         {
1405             continue;
1406         }
1407
1408         /* Extract table name and instance number */
1409
1410         Status = OslTableNameFromFile (Filename, TempName, &CurrentInstance);
1411
1412         /* Ignore meaningless files */
1413
1414         if (ACPI_FAILURE (Status) || CurrentInstance != Instance)
1415         {
1416             continue;
1417         }
1418
1419         /* Create the table pathname */
1420
1421         if (Instance != 0)
1422         {
1423             sprintf (TableFilename, "%s/%4.4s%d", Pathname, TempName, Instance);
1424         }
1425         else
1426         {
1427             sprintf (TableFilename, "%s/%4.4s", Pathname, TempName);
1428         }
1429         break;
1430     }
1431
1432     AcpiOsCloseDirectory (TableDir);
1433
1434     if (!Filename)
1435     {
1436         return (AE_LIMIT);
1437     }
1438
1439     /* There is no physical address saved for customized tables, use zero */
1440
1441     *Address = 0;
1442     Status = OslReadTableFromFile (TableFilename, 0, NULL, Table);
1443
1444     return (Status);
1445 }