1 /******************************************************************************
3 * Module Name: osbsdtbl - BSD OSL for obtaining ACPI tables
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2016, 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.
46 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
50 #include <sys/param.h>
51 #include <sys/sysctl.h>
54 #define _COMPONENT ACPI_OS_SERVICES
55 ACPI_MODULE_NAME ("osbsdtbl")
58 /* Local prototypes */
68 ACPI_TABLE_HEADER **Table);
78 ACPI_TABLE_HEADER **Table,
79 ACPI_PHYSICAL_ADDRESS *Address);
83 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
84 #define SYSTEM_KENV "hint.acpi.0.rsdp"
85 #define SYSTEM_SYSCTL "machdep.acpi_root"
86 #elif defined(__NetBSD__)
87 #define SYSTEM_SYSCTL "hw.acpi.root"
90 /* Initialization flags */
92 UINT8 Gbl_TableListInitialized = FALSE;
93 UINT8 Gbl_MainTableObtained = FALSE;
95 /* Local copies of main ACPI tables */
97 ACPI_TABLE_RSDP Gbl_Rsdp;
98 ACPI_TABLE_FADT *Gbl_Fadt;
99 ACPI_TABLE_RSDT *Gbl_Rsdt;
100 ACPI_TABLE_XSDT *Gbl_Xsdt;
104 ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress;
106 /* Revision of RSD PTR */
110 /* List of information about obtained ACPI tables */
112 typedef struct table_info
114 struct table_info *Next;
117 ACPI_PHYSICAL_ADDRESS Address;
121 OSL_TABLE_INFO *Gbl_TableListHead = NULL;
124 /******************************************************************************
126 * FUNCTION: AcpiOsGetTableByAddress
128 * PARAMETERS: Address - Physical address of the ACPI table
129 * Table - Where a pointer to the table is returned
131 * RETURN: Status; Table buffer is returned if AE_OK.
132 * AE_NOT_FOUND: A valid table was not found at the address
134 * DESCRIPTION: Get an ACPI table via a physical memory address.
136 *****************************************************************************/
139 AcpiOsGetTableByAddress (
140 ACPI_PHYSICAL_ADDRESS Address,
141 ACPI_TABLE_HEADER **Table)
143 ACPI_TABLE_HEADER *MappedTable;
144 ACPI_TABLE_HEADER *LocalTable;
148 /* Validate the input physical address to avoid program crash */
150 if (Address < ACPI_HI_RSDP_WINDOW_BASE)
152 fprintf (stderr, "Invalid table address: 0x%8.8X%8.8X\n",
153 ACPI_FORMAT_UINT64 (Address));
154 return (AE_BAD_ADDRESS);
157 /* Map the table and validate it */
159 Status = OslMapTable (Address, NULL, &MappedTable);
160 if (ACPI_FAILURE (Status))
165 /* Copy table to local buffer and return it */
167 LocalTable = calloc (1, MappedTable->Length);
170 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
171 return (AE_NO_MEMORY);
174 memcpy (LocalTable, MappedTable, MappedTable->Length);
175 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
182 /******************************************************************************
184 * FUNCTION: AcpiOsGetTableByName
186 * PARAMETERS: Signature - ACPI Signature for desired table. Must be
187 * a null terminated 4-character string.
188 * Instance - Multiple table support for SSDT/UEFI (0...n)
189 * Must be 0 for other tables.
190 * Table - Where a pointer to the table is returned
191 * Address - Where the table physical address is returned
193 * RETURN: Status; Table buffer and physical address returned if AE_OK.
194 * AE_LIMIT: Instance is beyond valid limit
195 * AE_NOT_FOUND: A table with the signature was not found
197 * NOTE: Assumes the input signature is uppercase.
199 *****************************************************************************/
202 AcpiOsGetTableByName (
205 ACPI_TABLE_HEADER **Table,
206 ACPI_PHYSICAL_ADDRESS *Address)
211 /* Instance is only valid for SSDT/UEFI tables */
214 !ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT) &&
215 !ACPI_COMPARE_NAME (Signature, ACPI_SIG_UEFI))
220 /* Initialize main tables */
222 Status = OslTableInitialize ();
223 if (ACPI_FAILURE (Status))
229 * If one of the main ACPI tables was requested (RSDT/XSDT/FADT),
230 * simply return it immediately.
232 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT))
236 return (AE_NOT_FOUND);
239 *Address = Gbl_Rsdp.XsdtPhysicalAddress;
240 *Table = (ACPI_TABLE_HEADER *) Gbl_Xsdt;
244 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT))
246 if (!Gbl_Rsdp.RsdtPhysicalAddress)
248 return (AE_NOT_FOUND);
251 *Address = Gbl_Rsdp.RsdtPhysicalAddress;
252 *Table = (ACPI_TABLE_HEADER *) Gbl_Rsdt;
256 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FADT))
258 *Address = Gbl_FadtAddress;
259 *Table = (ACPI_TABLE_HEADER *) Gbl_Fadt;
263 /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
265 Status = OslGetTableViaRoot (Signature, Instance, Table, Address);
266 if (ACPI_FAILURE (Status))
275 /******************************************************************************
277 * FUNCTION: AcpiOsGetTableByIndex
279 * PARAMETERS: Index - Which table to get
280 * Table - Where a pointer to the table is returned
281 * Instance - Where a pointer to the table instance no. is
283 * Address - Where the table physical address is returned
285 * RETURN: Status; Table buffer and physical address returned if AE_OK.
286 * AE_LIMIT: Index is beyond valid limit
288 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
289 * AE_LIMIT when an invalid index is reached. Index is not
290 * necessarily an index into the RSDT/XSDT.
292 *****************************************************************************/
295 AcpiOsGetTableByIndex (
297 ACPI_TABLE_HEADER **Table,
299 ACPI_PHYSICAL_ADDRESS *Address)
301 OSL_TABLE_INFO *Info;
306 /* Initialize main tables */
308 Status = OslTableInitialize ();
309 if (ACPI_FAILURE (Status))
314 /* Add all tables to list */
316 Status = OslAddTablesToList ();
317 if (ACPI_FAILURE (Status))
324 if (Index >= Gbl_TableListHead->Instance)
329 /* Point to the table list entry specified by the Index argument */
331 Info = Gbl_TableListHead;
332 for (i = 0; i <= Index; i++)
337 /* Now we can just get the table via the address or name */
341 Status = AcpiOsGetTableByAddress (Info->Address, Table);
342 if (ACPI_SUCCESS (Status))
344 *Address = Info->Address;
349 Status = AcpiOsGetTableByName (Info->Signature, Info->Instance,
353 if (ACPI_SUCCESS (Status))
355 *Instance = Info->Instance;
361 /******************************************************************************
363 * FUNCTION: OslTableInitialize
369 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
370 * local variables. Main ACPI tables include RSDP, FADT, RSDT,
373 *****************************************************************************/
379 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
382 ACPI_TABLE_HEADER *MappedTable;
385 ACPI_PHYSICAL_ADDRESS RsdpBase;
389 size_t Length = sizeof (Address);
392 /* Get main ACPI tables from memory on first invocation of this function */
394 if (Gbl_MainTableObtained)
399 /* Attempt to use kenv or sysctl to find RSD PTR record. */
403 Address = Gbl_RsdpBase;
405 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
406 else if (kenv (KENV_GET, SYSTEM_KENV, Buffer, sizeof (Buffer)) > 0)
408 Address = strtoul (Buffer, NULL, 0);
413 if (sysctlbyname (SYSTEM_SYSCTL, &Address, &Length, NULL, 0) != 0)
421 RsdpSize = sizeof (Gbl_Rsdp);
425 RsdpBase = ACPI_HI_RSDP_WINDOW_BASE;
426 RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE;
429 /* Get RSDP from memory */
431 RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize);
434 return (AE_BAD_ADDRESS);
437 /* Search low memory for the RSDP */
439 TableAddress = AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize);
442 AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
446 memcpy (&Gbl_Rsdp, TableAddress, sizeof (Gbl_Rsdp));
447 AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
449 /* Get XSDT from memory */
451 if (Gbl_Rsdp.Revision)
453 Status = OslMapTable (Gbl_Rsdp.XsdtPhysicalAddress,
454 ACPI_SIG_XSDT, &MappedTable);
455 if (ACPI_FAILURE (Status))
461 Gbl_Xsdt = calloc (1, MappedTable->Length);
465 "XSDT: Could not allocate buffer for table of length %X\n",
466 MappedTable->Length);
467 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
468 return (AE_NO_MEMORY);
471 memcpy (Gbl_Xsdt, MappedTable, MappedTable->Length);
472 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
475 /* Get RSDT from memory */
477 if (Gbl_Rsdp.RsdtPhysicalAddress)
479 Status = OslMapTable (Gbl_Rsdp.RsdtPhysicalAddress,
480 ACPI_SIG_RSDT, &MappedTable);
481 if (ACPI_FAILURE (Status))
486 Gbl_Rsdt = calloc (1, MappedTable->Length);
490 "RSDT: Could not allocate buffer for table of length %X\n",
491 MappedTable->Length);
492 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
493 return (AE_NO_MEMORY);
496 memcpy (Gbl_Rsdt, MappedTable, MappedTable->Length);
497 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
500 /* Get FADT from memory */
504 Gbl_FadtAddress = Gbl_Xsdt->TableOffsetEntry[0];
508 Gbl_FadtAddress = Gbl_Rsdt->TableOffsetEntry[0];
511 if (!Gbl_FadtAddress)
513 fprintf(stderr, "FADT: Table could not be found\n");
517 Status = OslMapTable (Gbl_FadtAddress, ACPI_SIG_FADT, &MappedTable);
518 if (ACPI_FAILURE (Status))
523 Gbl_Fadt = calloc (1, MappedTable->Length);
527 "FADT: Could not allocate buffer for table of length %X\n",
528 MappedTable->Length);
529 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
530 return (AE_NO_MEMORY);
533 memcpy (Gbl_Fadt, MappedTable, MappedTable->Length);
534 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
535 Gbl_MainTableObtained = TRUE;
540 /******************************************************************************
542 * FUNCTION: OslGetTableViaRoot
544 * PARAMETERS: Signature - ACPI Signature for common table. Must be
545 * a null terminated 4-character string.
546 * Instance - Multiple table support for SSDT/UEFI (0...n)
547 * Must be 0 for other tables.
548 * Table - Where a pointer to the table is returned
549 * Address - Where the table physical address is returned
551 * RETURN: Status; Table buffer and physical address returned if AE_OK.
552 * AE_LIMIT: Instance is beyond valid limit
553 * AE_NOT_FOUND: A table with the signature was not found
555 * DESCRIPTION: Get an ACPI table via the root table (RSDT/XSDT)
557 * NOTE: Assumes the input signature is uppercase.
559 *****************************************************************************/
565 ACPI_TABLE_HEADER **Table,
566 ACPI_PHYSICAL_ADDRESS *Address)
568 ACPI_TABLE_HEADER *LocalTable = NULL;
569 ACPI_TABLE_HEADER *MappedTable = NULL;
570 UINT8 NumberOfTables;
571 UINT32 CurrentInstance = 0;
572 ACPI_PHYSICAL_ADDRESS TableAddress = 0;
577 /* DSDT and FACS address must be extracted from the FADT */
579 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) ||
580 ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
583 * Get the appropriate address, either 32-bit or 64-bit. Be very
584 * careful about the FADT length and validate table addresses.
585 * Note: The 64-bit addresses have priority.
587 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT))
589 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
592 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
594 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) &&
597 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
602 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
605 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
607 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) &&
610 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
614 else /* Case for a normal ACPI table */
619 (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header))
620 / sizeof (Gbl_Xsdt->TableOffsetEntry[0]);
622 else /* Use RSDT if XSDT is not available */
625 (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header))
626 / sizeof (Gbl_Rsdt->TableOffsetEntry[0]);
629 /* Search RSDT/XSDT for the requested table */
631 for (i = 0; i < NumberOfTables; i++)
635 TableAddress = Gbl_Xsdt->TableOffsetEntry[i];
639 TableAddress = Gbl_Rsdt->TableOffsetEntry[i];
642 MappedTable = AcpiOsMapMemory (TableAddress, sizeof (*MappedTable));
645 return (AE_BAD_ADDRESS);
648 /* Does this table match the requested signature? */
650 if (ACPI_COMPARE_NAME (MappedTable->Signature, Signature))
653 /* Match table instance (for SSDT/UEFI tables) */
655 if (CurrentInstance == Instance)
657 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
664 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
675 return (AE_NOT_FOUND);
678 /* Now we can get the requested table */
680 Status = OslMapTable (TableAddress, Signature, &MappedTable);
681 if (ACPI_FAILURE (Status))
686 /* Copy table to local buffer and return it */
688 LocalTable = calloc (1, MappedTable->Length);
691 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
692 return (AE_NO_MEMORY);
695 memcpy (LocalTable, MappedTable, MappedTable->Length);
696 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
698 *Address = TableAddress;
703 /******************************************************************************
705 * FUNCTION: OslAddTablesToList
709 * RETURN: Status; Table list is initialized if AE_OK.
711 * DESCRIPTION: Add ACPI tables to the table list.
713 *****************************************************************************/
719 ACPI_PHYSICAL_ADDRESS TableAddress;
720 OSL_TABLE_INFO *Info = NULL;
721 OSL_TABLE_INFO *NewInfo;
722 ACPI_TABLE_HEADER *Table;
724 UINT8 NumberOfTables;
728 /* Initialize the table list on first invocation */
730 if (Gbl_TableListInitialized)
735 /* Add mandatory tables to global table list first */
737 for (i = 0; i < 4; i++)
739 NewInfo = calloc (1, sizeof (*NewInfo));
742 return (AE_NO_MEMORY);
748 Gbl_TableListHead = Info = NewInfo;
753 ACPI_MOVE_NAME (NewInfo->Signature,
754 Gbl_Revision ? ACPI_SIG_XSDT : ACPI_SIG_RSDT);
759 ACPI_MOVE_NAME (NewInfo->Signature, ACPI_SIG_FACS);
764 ACPI_MOVE_NAME (NewInfo->Signature, ACPI_SIG_DSDT);
768 Info->Next = NewInfo;
770 Gbl_TableListHead->Instance++;
773 /* Add normal tables from RSDT/XSDT to global list */
778 (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header))
779 / sizeof (Gbl_Xsdt->TableOffsetEntry[0]);
784 (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header))
785 / sizeof (Gbl_Rsdt->TableOffsetEntry[0]);
788 for (i = 0; i < NumberOfTables; i++)
792 TableAddress = Gbl_Xsdt->TableOffsetEntry[i];
796 TableAddress = Gbl_Rsdt->TableOffsetEntry[i];
799 Table = AcpiOsMapMemory (TableAddress, sizeof (*Table));
802 return (AE_BAD_ADDRESS);
806 NewInfo = Gbl_TableListHead;
807 while (NewInfo->Next != NULL)
809 NewInfo = NewInfo->Next;
810 if (ACPI_COMPARE_NAME (Table->Signature, NewInfo->Signature))
816 NewInfo = calloc (1, sizeof (*NewInfo));
819 AcpiOsUnmapMemory (Table, sizeof (*Table));
820 return (AE_NO_MEMORY);
823 ACPI_MOVE_NAME (NewInfo->Signature, Table->Signature);
825 AcpiOsUnmapMemory (Table, sizeof (*Table));
827 NewInfo->Instance = Instance;
828 NewInfo->Address = TableAddress;
829 Info->Next = NewInfo;
831 Gbl_TableListHead->Instance++;
834 Gbl_TableListInitialized = TRUE;
839 /******************************************************************************
841 * FUNCTION: OslMapTable
843 * PARAMETERS: Address - Address of the table in memory
844 * Signature - Optional ACPI Signature for desired table.
845 * Null terminated 4-character string.
846 * Table - Where a pointer to the mapped table is
849 * RETURN: Status; Mapped table is returned if AE_OK.
851 * DESCRIPTION: Map entire ACPI table into caller's address space. Also
852 * validates the table and checksum.
854 *****************************************************************************/
860 ACPI_TABLE_HEADER **Table)
862 ACPI_TABLE_HEADER *MappedTable;
866 /* Map the header so we can get the table length */
868 MappedTable = AcpiOsMapMemory (Address, sizeof (*MappedTable));
871 return (AE_BAD_ADDRESS);
874 /* Check if table is valid */
876 if (!ApIsValidHeader (MappedTable))
878 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
879 return (AE_BAD_HEADER);
882 /* If specified, signature must match */
885 !ACPI_COMPARE_NAME (Signature, MappedTable->Signature))
887 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
888 return (AE_NOT_EXIST);
891 /* Map the entire table */
893 Length = MappedTable->Length;
894 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
896 MappedTable = AcpiOsMapMemory (Address, Length);
899 return (AE_BAD_ADDRESS);
902 (void) ApIsValidChecksum (MappedTable);
904 *Table = MappedTable;