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