1 /******************************************************************************
3 * Module Name: osfreebsdtbl - FreeBSD OSL for obtaining ACPI tables
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2014, 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;