1 /******************************************************************************
3 * Module Name: osfreebsdtbl - FreeBSD OSL for obtaining ACPI tables
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
48 #include <sys/param.h>
49 #include <sys/sysctl.h>
52 #define _COMPONENT ACPI_OS_SERVICES
53 ACPI_MODULE_NAME ("osfreebsdtbl")
56 /* Local prototypes */
66 ACPI_TABLE_HEADER
**Table
);
76 ACPI_TABLE_HEADER
**Table
,
77 ACPI_PHYSICAL_ADDRESS
*Address
);
82 #define SYSTEM_KENV "hint.acpi.0.rsdp"
83 #define SYSTEM_SYSCTL "machdep.acpi_root"
85 /* Initialization flags */
87 UINT8 Gbl_TableListInitialized
= FALSE
;
88 UINT8 Gbl_MainTableObtained
= FALSE
;
90 /* Local copies of main ACPI tables */
92 ACPI_TABLE_RSDP Gbl_Rsdp
;
93 ACPI_TABLE_FADT
*Gbl_Fadt
;
94 ACPI_TABLE_RSDT
*Gbl_Rsdt
;
95 ACPI_TABLE_XSDT
*Gbl_Xsdt
;
99 ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress
;
101 /* Revision of RSD PTR */
105 /* List of information about obtained ACPI tables */
107 typedef struct table_info
109 struct table_info
*Next
;
112 ACPI_PHYSICAL_ADDRESS Address
;
116 OSL_TABLE_INFO
*Gbl_TableListHead
= NULL
;
119 /******************************************************************************
121 * FUNCTION: AcpiOsGetTableByAddress
123 * PARAMETERS: Address - Physical address of the ACPI table
124 * Table - Where a pointer to the table is returned
126 * RETURN: Status; Table buffer is returned if AE_OK.
127 * AE_NOT_FOUND: A valid table was not found at the address
129 * DESCRIPTION: Get an ACPI table via a physical memory address.
131 *****************************************************************************/
134 AcpiOsGetTableByAddress (
135 ACPI_PHYSICAL_ADDRESS Address
,
136 ACPI_TABLE_HEADER
**Table
)
138 ACPI_TABLE_HEADER
*MappedTable
;
139 ACPI_TABLE_HEADER
*LocalTable
;
143 /* Validate the input physical address to avoid program crash */
145 if (Address
< ACPI_HI_RSDP_WINDOW_BASE
)
147 fprintf (stderr
, "Invalid table address: 0x%8.8X%8.8X\n",
148 ACPI_FORMAT_UINT64 (Address
));
149 return (AE_BAD_ADDRESS
);
152 /* Map the table and validate it */
154 Status
= OslMapTable (Address
, NULL
, &MappedTable
);
155 if (ACPI_FAILURE (Status
))
160 /* Copy table to local buffer and return it */
162 LocalTable
= calloc (1, MappedTable
->Length
);
165 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
166 return (AE_NO_MEMORY
);
169 ACPI_MEMCPY (LocalTable
, MappedTable
, MappedTable
->Length
);
170 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
177 /******************************************************************************
179 * FUNCTION: AcpiOsGetTableByName
181 * PARAMETERS: Signature - ACPI Signature for desired table. Must be
182 * a null terminated 4-character string.
183 * Instance - Multiple table support for SSDT/UEFI (0...n)
184 * Must be 0 for other tables.
185 * Table - Where a pointer to the table is returned
186 * Address - Where the table physical address is returned
188 * RETURN: Status; Table buffer and physical address returned if AE_OK.
189 * AE_LIMIT: Instance is beyond valid limit
190 * AE_NOT_FOUND: A table with the signature was not found
192 * NOTE: Assumes the input signature is uppercase.
194 *****************************************************************************/
197 AcpiOsGetTableByName (
200 ACPI_TABLE_HEADER
**Table
,
201 ACPI_PHYSICAL_ADDRESS
*Address
)
206 /* Instance is only valid for SSDT/UEFI tables */
209 !ACPI_COMPARE_NAME (Signature
, ACPI_SIG_SSDT
) &&
210 !ACPI_COMPARE_NAME (Signature
, ACPI_SIG_UEFI
))
215 /* Initialize main tables */
217 Status
= OslTableInitialize ();
218 if (ACPI_FAILURE (Status
))
224 * If one of the main ACPI tables was requested (RSDT/XSDT/FADT),
225 * simply return it immediately.
227 if (ACPI_COMPARE_NAME (Signature
, ACPI_SIG_XSDT
))
231 return (AE_NOT_FOUND
);
234 *Address
= Gbl_Rsdp
.XsdtPhysicalAddress
;
235 *Table
= (ACPI_TABLE_HEADER
*) Gbl_Xsdt
;
239 if (ACPI_COMPARE_NAME (Signature
, ACPI_SIG_RSDT
))
241 if (!Gbl_Rsdp
.RsdtPhysicalAddress
)
243 return (AE_NOT_FOUND
);
246 *Address
= Gbl_Rsdp
.RsdtPhysicalAddress
;
247 *Table
= (ACPI_TABLE_HEADER
*) Gbl_Rsdt
;
251 if (ACPI_COMPARE_NAME (Signature
, ACPI_SIG_FADT
))
253 *Address
= Gbl_FadtAddress
;
254 *Table
= (ACPI_TABLE_HEADER
*) Gbl_Fadt
;
258 /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
260 Status
= OslGetTableViaRoot (Signature
, Instance
, Table
, Address
);
261 if (ACPI_FAILURE (Status
))
270 /******************************************************************************
272 * FUNCTION: AcpiOsGetTableByIndex
274 * PARAMETERS: Index - Which table to get
275 * Table - Where a pointer to the table is returned
276 * Instance - Where a pointer to the table instance no. is
278 * Address - Where the table physical address is returned
280 * RETURN: Status; Table buffer and physical address returned if AE_OK.
281 * AE_LIMIT: Index is beyond valid limit
283 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
284 * AE_LIMIT when an invalid index is reached. Index is not
285 * necessarily an index into the RSDT/XSDT.
287 *****************************************************************************/
290 AcpiOsGetTableByIndex (
292 ACPI_TABLE_HEADER
**Table
,
294 ACPI_PHYSICAL_ADDRESS
*Address
)
296 OSL_TABLE_INFO
*Info
;
301 /* Initialize main tables */
303 Status
= OslTableInitialize ();
304 if (ACPI_FAILURE (Status
))
309 /* Add all tables to list */
311 Status
= OslAddTablesToList ();
312 if (ACPI_FAILURE (Status
))
319 if (Index
>= Gbl_TableListHead
->Instance
)
324 /* Point to the table list entry specified by the Index argument */
326 Info
= Gbl_TableListHead
;
327 for (i
= 0; i
<= Index
; i
++)
332 /* Now we can just get the table via the address or name */
336 Status
= AcpiOsGetTableByAddress (Info
->Address
, Table
);
337 if (ACPI_SUCCESS (Status
))
339 *Address
= Info
->Address
;
344 Status
= AcpiOsGetTableByName (Info
->Signature
, Info
->Instance
,
348 if (ACPI_SUCCESS (Status
))
350 *Instance
= Info
->Instance
;
356 /******************************************************************************
358 * FUNCTION: OslTableInitialize
364 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
365 * local variables. Main ACPI tables include RSDP, FADT, RSDT,
368 *****************************************************************************/
375 ACPI_TABLE_HEADER
*MappedTable
;
378 ACPI_PHYSICAL_ADDRESS RsdpBase
;
382 size_t Length
= sizeof (Address
);
385 /* Get main ACPI tables from memory on first invocation of this function */
387 if (Gbl_MainTableObtained
)
392 /* Attempt to use kenv or sysctl to find RSD PTR record. */
396 Address
= Gbl_RsdpBase
;
398 else if (kenv (KENV_GET
, SYSTEM_KENV
, Buffer
, sizeof (Buffer
)) > 0)
400 Address
= ACPI_STRTOUL (Buffer
, NULL
, 0);
404 if (sysctlbyname (SYSTEM_SYSCTL
, &Address
, &Length
, NULL
, 0) != 0)
412 RsdpSize
= sizeof (Gbl_Rsdp
);
416 RsdpBase
= ACPI_HI_RSDP_WINDOW_BASE
;
417 RsdpSize
= ACPI_HI_RSDP_WINDOW_SIZE
;
420 /* Get RSDP from memory */
422 RsdpAddress
= AcpiOsMapMemory (RsdpBase
, RsdpSize
);
425 return (AE_BAD_ADDRESS
);
428 /* Search low memory for the RSDP */
430 TableAddress
= AcpiTbScanMemoryForRsdp (RsdpAddress
, RsdpSize
);
433 AcpiOsUnmapMemory (RsdpAddress
, RsdpSize
);
437 ACPI_MEMCPY (&Gbl_Rsdp
, TableAddress
, sizeof (Gbl_Rsdp
));
438 AcpiOsUnmapMemory (RsdpAddress
, RsdpSize
);
440 /* Get XSDT from memory */
442 if (Gbl_Rsdp
.Revision
)
444 Status
= OslMapTable (Gbl_Rsdp
.XsdtPhysicalAddress
,
445 ACPI_SIG_XSDT
, &MappedTable
);
446 if (ACPI_FAILURE (Status
))
452 Gbl_Xsdt
= calloc (1, MappedTable
->Length
);
456 "XSDT: Could not allocate buffer for table of length %X\n",
457 MappedTable
->Length
);
458 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
459 return (AE_NO_MEMORY
);
462 ACPI_MEMCPY (Gbl_Xsdt
, MappedTable
, MappedTable
->Length
);
463 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
466 /* Get RSDT from memory */
468 if (Gbl_Rsdp
.RsdtPhysicalAddress
)
470 Status
= OslMapTable (Gbl_Rsdp
.RsdtPhysicalAddress
,
471 ACPI_SIG_RSDT
, &MappedTable
);
472 if (ACPI_FAILURE (Status
))
477 Gbl_Rsdt
= calloc (1, MappedTable
->Length
);
481 "RSDT: Could not allocate buffer for table of length %X\n",
482 MappedTable
->Length
);
483 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
484 return (AE_NO_MEMORY
);
487 ACPI_MEMCPY (Gbl_Rsdt
, MappedTable
, MappedTable
->Length
);
488 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
491 /* Get FADT from memory */
495 Gbl_FadtAddress
= Gbl_Xsdt
->TableOffsetEntry
[0];
499 Gbl_FadtAddress
= Gbl_Rsdt
->TableOffsetEntry
[0];
502 if (!Gbl_FadtAddress
)
504 fprintf(stderr
, "FADT: Table could not be found\n");
508 Status
= OslMapTable (Gbl_FadtAddress
, ACPI_SIG_FADT
, &MappedTable
);
509 if (ACPI_FAILURE (Status
))
514 Gbl_Fadt
= calloc (1, MappedTable
->Length
);
518 "FADT: Could not allocate buffer for table of length %X\n",
519 MappedTable
->Length
);
520 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
521 return (AE_NO_MEMORY
);
524 ACPI_MEMCPY (Gbl_Fadt
, MappedTable
, MappedTable
->Length
);
525 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
526 Gbl_MainTableObtained
= TRUE
;
531 /******************************************************************************
533 * FUNCTION: OslGetTableViaRoot
535 * PARAMETERS: Signature - ACPI Signature for common table. Must be
536 * a null terminated 4-character string.
537 * Instance - Multiple table support for SSDT/UEFI (0...n)
538 * Must be 0 for other tables.
539 * Table - Where a pointer to the table is returned
540 * Address - Where the table physical address is returned
542 * RETURN: Status; Table buffer and physical address returned if AE_OK.
543 * AE_LIMIT: Instance is beyond valid limit
544 * AE_NOT_FOUND: A table with the signature was not found
546 * DESCRIPTION: Get an ACPI table via the root table (RSDT/XSDT)
548 * NOTE: Assumes the input signature is uppercase.
550 *****************************************************************************/
556 ACPI_TABLE_HEADER
**Table
,
557 ACPI_PHYSICAL_ADDRESS
*Address
)
559 ACPI_TABLE_HEADER
*LocalTable
= NULL
;
560 ACPI_TABLE_HEADER
*MappedTable
= NULL
;
561 UINT8 NumberOfTables
;
562 UINT32 CurrentInstance
= 0;
563 ACPI_PHYSICAL_ADDRESS TableAddress
= 0;
568 /* DSDT and FACS address must be extracted from the FADT */
570 if (ACPI_COMPARE_NAME (Signature
, ACPI_SIG_DSDT
) ||
571 ACPI_COMPARE_NAME (Signature
, ACPI_SIG_FACS
))
574 * Get the appropriate address, either 32-bit or 64-bit. Be very
575 * careful about the FADT length and validate table addresses.
576 * Note: The 64-bit addresses have priority.
578 if (ACPI_COMPARE_NAME (Signature
, ACPI_SIG_DSDT
))
580 if ((Gbl_Fadt
->Header
.Length
>= MIN_FADT_FOR_XDSDT
) &&
583 TableAddress
= (ACPI_PHYSICAL_ADDRESS
) Gbl_Fadt
->XDsdt
;
585 else if ((Gbl_Fadt
->Header
.Length
>= MIN_FADT_FOR_DSDT
) &&
588 TableAddress
= (ACPI_PHYSICAL_ADDRESS
) Gbl_Fadt
->Dsdt
;
593 if ((Gbl_Fadt
->Header
.Length
>= MIN_FADT_FOR_XFACS
) &&
596 TableAddress
= (ACPI_PHYSICAL_ADDRESS
) Gbl_Fadt
->XFacs
;
598 else if ((Gbl_Fadt
->Header
.Length
>= MIN_FADT_FOR_FACS
) &&
601 TableAddress
= (ACPI_PHYSICAL_ADDRESS
) Gbl_Fadt
->Facs
;
605 else /* Case for a normal ACPI table */
610 (Gbl_Xsdt
->Header
.Length
- sizeof (Gbl_Xsdt
->Header
))
611 / sizeof (Gbl_Xsdt
->TableOffsetEntry
[0]);
613 else /* Use RSDT if XSDT is not available */
616 (Gbl_Rsdt
->Header
.Length
- sizeof (Gbl_Rsdt
->Header
))
617 / sizeof (Gbl_Rsdt
->TableOffsetEntry
[0]);
620 /* Search RSDT/XSDT for the requested table */
622 for (i
= 0; i
< NumberOfTables
; i
++)
626 TableAddress
= Gbl_Xsdt
->TableOffsetEntry
[i
];
630 TableAddress
= Gbl_Rsdt
->TableOffsetEntry
[i
];
633 MappedTable
= AcpiOsMapMemory (TableAddress
, sizeof (*MappedTable
));
636 return (AE_BAD_ADDRESS
);
639 /* Does this table match the requested signature? */
641 if (ACPI_COMPARE_NAME (MappedTable
->Signature
, Signature
))
644 /* Match table instance (for SSDT/UEFI tables) */
646 if (CurrentInstance
== Instance
)
648 AcpiOsUnmapMemory (MappedTable
, sizeof (*MappedTable
));
655 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
666 return (AE_NOT_FOUND
);
669 /* Now we can get the requested table */
671 Status
= OslMapTable (TableAddress
, Signature
, &MappedTable
);
672 if (ACPI_FAILURE (Status
))
677 /* Copy table to local buffer and return it */
679 LocalTable
= calloc (1, MappedTable
->Length
);
682 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
683 return (AE_NO_MEMORY
);
686 ACPI_MEMCPY (LocalTable
, MappedTable
, MappedTable
->Length
);
687 AcpiOsUnmapMemory (MappedTable
, MappedTable
->Length
);
689 *Address
= TableAddress
;
694 /******************************************************************************
696 * FUNCTION: OslAddTablesToList
700 * RETURN: Status; Table list is initialized if AE_OK.
702 * DESCRIPTION: Add ACPI tables to the table list.
704 *****************************************************************************/
710 ACPI_PHYSICAL_ADDRESS TableAddress
;
711 OSL_TABLE_INFO
*Info
= NULL
;
712 OSL_TABLE_INFO
*NewInfo
;
713 ACPI_TABLE_HEADER
*Table
;
715 UINT8 NumberOfTables
;
719 /* Initialize the table list on first invocation */
721 if (Gbl_TableListInitialized
)
726 /* Add mandatory tables to global table list first */
728 for (i
= 0; i
< 4; i
++)
730 NewInfo
= calloc (1, sizeof (*NewInfo
));
733 return (AE_NO_MEMORY
);
739 Gbl_TableListHead
= Info
= NewInfo
;
744 ACPI_MOVE_NAME (NewInfo
->Signature
,
745 Gbl_Revision
? ACPI_SIG_XSDT
: ACPI_SIG_RSDT
);
750 ACPI_MOVE_NAME (NewInfo
->Signature
, ACPI_SIG_FACS
);
755 ACPI_MOVE_NAME (NewInfo
->Signature
, ACPI_SIG_DSDT
);
759 Info
->Next
= NewInfo
;
761 Gbl_TableListHead
->Instance
++;
764 /* Add normal tables from RSDT/XSDT to global list */
769 (Gbl_Xsdt
->Header
.Length
- sizeof (Gbl_Xsdt
->Header
))
770 / sizeof (Gbl_Xsdt
->TableOffsetEntry
[0]);
775 (Gbl_Rsdt
->Header
.Length
- sizeof (Gbl_Rsdt
->Header
))
776 / sizeof (Gbl_Rsdt
->TableOffsetEntry
[0]);
779 for (i
= 0; i
< NumberOfTables
; i
++)
783 TableAddress
= Gbl_Xsdt
->TableOffsetEntry
[i
];
787 TableAddress
= Gbl_Rsdt
->TableOffsetEntry
[i
];
790 Table
= AcpiOsMapMemory (TableAddress
, sizeof (*Table
));
793 return (AE_BAD_ADDRESS
);
797 NewInfo
= Gbl_TableListHead
;
798 while (NewInfo
->Next
!= NULL
)
800 NewInfo
= NewInfo
->Next
;
801 if (ACPI_COMPARE_NAME (Table
->Signature
, NewInfo
->Signature
))
807 NewInfo
= calloc (1, sizeof (*NewInfo
));
810 AcpiOsUnmapMemory (Table
, sizeof (*Table
));
811 return (AE_NO_MEMORY
);
814 ACPI_MOVE_NAME (NewInfo
->Signature
, Table
->Signature
);
816 AcpiOsUnmapMemory (Table
, sizeof (*Table
));
818 NewInfo
->Instance
= Instance
;
819 NewInfo
->Address
= TableAddress
;
820 Info
->Next
= NewInfo
;
822 Gbl_TableListHead
->Instance
++;
825 Gbl_TableListInitialized
= TRUE
;
830 /******************************************************************************
832 * FUNCTION: OslMapTable
834 * PARAMETERS: Address - Address of the table in memory
835 * Signature - Optional ACPI Signature for desired table.
836 * Null terminated 4-character string.
837 * Table - Where a pointer to the mapped table is
840 * RETURN: Status; Mapped table is returned if AE_OK.
842 * DESCRIPTION: Map entire ACPI table into caller's address space. Also
843 * validates the table and checksum.
845 *****************************************************************************/
851 ACPI_TABLE_HEADER
**Table
)
853 ACPI_TABLE_HEADER
*MappedTable
;
857 /* Map the header so we can get the table length */
859 MappedTable
= AcpiOsMapMemory (Address
, sizeof (*MappedTable
));
862 return (AE_BAD_ADDRESS
);
865 /* Check if table is valid */
867 if (!ApIsValidHeader (MappedTable
))
869 AcpiOsUnmapMemory (MappedTable
, sizeof (*MappedTable
));
870 return (AE_BAD_HEADER
);
873 /* If specified, signature must match */
876 !ACPI_COMPARE_NAME (Signature
, MappedTable
->Signature
))
878 AcpiOsUnmapMemory (MappedTable
, sizeof (*MappedTable
));
879 return (AE_NOT_EXIST
);
882 /* Map the entire table */
884 Length
= MappedTable
->Length
;
885 AcpiOsUnmapMemory (MappedTable
, sizeof (*MappedTable
));
887 MappedTable
= AcpiOsMapMemory (Address
, Length
);
890 return (AE_BAD_ADDRESS
);
893 (void) ApIsValidChecksum (MappedTable
);
895 *Table
= MappedTable
;