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__) || defined (__DragonFly__)
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__) || defined(__DragonFly__)
382 ACPI_TABLE_HEADER *MappedTable;
385 ACPI_PHYSICAL_ADDRESS RsdpBase;
389 #if defined(SYSTEM_SYSCTL)
390 size_t Length = sizeof (Address);
394 /* Get main ACPI tables from memory on first invocation of this function */
396 if (Gbl_MainTableObtained)
401 /* Attempt to use kenv or sysctl to find RSD PTR record. */
405 Address = Gbl_RsdpBase;
407 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__DragonFly__)
408 else if (kenv (KENV_GET, SYSTEM_KENV, Buffer, sizeof (Buffer)) > 0)
410 Address = strtoul (Buffer, NULL, 0);
413 #if defined(SYSTEM_SYSCTL)
416 if (sysctlbyname (SYSTEM_SYSCTL, &Address, &Length, NULL, 0) != 0)
425 RsdpSize = sizeof (Gbl_Rsdp);
429 RsdpBase = ACPI_HI_RSDP_WINDOW_BASE;
430 RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE;
433 /* Get RSDP from memory */
435 RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize);
438 return (AE_BAD_ADDRESS);
441 /* Search low memory for the RSDP */
443 TableAddress = AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize);
446 AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
450 memcpy (&Gbl_Rsdp, TableAddress, sizeof (Gbl_Rsdp));
451 AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
453 /* Get XSDT from memory */
455 if (Gbl_Rsdp.Revision)
457 Status = OslMapTable (Gbl_Rsdp.XsdtPhysicalAddress,
458 ACPI_SIG_XSDT, &MappedTable);
459 if (ACPI_FAILURE (Status))
465 Gbl_Xsdt = calloc (1, MappedTable->Length);
469 "XSDT: Could not allocate buffer for table of length %X\n",
470 MappedTable->Length);
471 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
472 return (AE_NO_MEMORY);
475 memcpy (Gbl_Xsdt, MappedTable, MappedTable->Length);
476 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
479 /* Get RSDT from memory */
481 if (Gbl_Rsdp.RsdtPhysicalAddress)
483 Status = OslMapTable (Gbl_Rsdp.RsdtPhysicalAddress,
484 ACPI_SIG_RSDT, &MappedTable);
485 if (ACPI_FAILURE (Status))
490 Gbl_Rsdt = calloc (1, MappedTable->Length);
494 "RSDT: Could not allocate buffer for table of length %X\n",
495 MappedTable->Length);
496 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
497 return (AE_NO_MEMORY);
500 memcpy (Gbl_Rsdt, MappedTable, MappedTable->Length);
501 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
504 /* Get FADT from memory */
508 Gbl_FadtAddress = Gbl_Xsdt->TableOffsetEntry[0];
512 Gbl_FadtAddress = Gbl_Rsdt->TableOffsetEntry[0];
515 if (!Gbl_FadtAddress)
517 fprintf(stderr, "FADT: Table could not be found\n");
521 Status = OslMapTable (Gbl_FadtAddress, ACPI_SIG_FADT, &MappedTable);
522 if (ACPI_FAILURE (Status))
527 Gbl_Fadt = calloc (1, MappedTable->Length);
531 "FADT: Could not allocate buffer for table of length %X\n",
532 MappedTable->Length);
533 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
534 return (AE_NO_MEMORY);
537 memcpy (Gbl_Fadt, MappedTable, MappedTable->Length);
538 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
539 Gbl_MainTableObtained = TRUE;
544 /******************************************************************************
546 * FUNCTION: OslGetTableViaRoot
548 * PARAMETERS: Signature - ACPI Signature for common table. Must be
549 * a null terminated 4-character string.
550 * Instance - Multiple table support for SSDT/UEFI (0...n)
551 * Must be 0 for other tables.
552 * Table - Where a pointer to the table is returned
553 * Address - Where the table physical address is returned
555 * RETURN: Status; Table buffer and physical address returned if AE_OK.
556 * AE_LIMIT: Instance is beyond valid limit
557 * AE_NOT_FOUND: A table with the signature was not found
559 * DESCRIPTION: Get an ACPI table via the root table (RSDT/XSDT)
561 * NOTE: Assumes the input signature is uppercase.
563 *****************************************************************************/
569 ACPI_TABLE_HEADER **Table,
570 ACPI_PHYSICAL_ADDRESS *Address)
572 ACPI_TABLE_HEADER *LocalTable = NULL;
573 ACPI_TABLE_HEADER *MappedTable = NULL;
574 UINT8 NumberOfTables;
575 UINT32 CurrentInstance = 0;
576 ACPI_PHYSICAL_ADDRESS TableAddress = 0;
581 /* DSDT and FACS address must be extracted from the FADT */
583 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) ||
584 ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
587 * Get the appropriate address, either 32-bit or 64-bit. Be very
588 * careful about the FADT length and validate table addresses.
589 * Note: The 64-bit addresses have priority.
591 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT))
593 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
596 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
598 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) &&
601 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
606 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
609 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
611 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) &&
614 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
618 else /* Case for a normal ACPI table */
623 (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header))
624 / sizeof (Gbl_Xsdt->TableOffsetEntry[0]);
626 else /* Use RSDT if XSDT is not available */
629 (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header))
630 / sizeof (Gbl_Rsdt->TableOffsetEntry[0]);
633 /* Search RSDT/XSDT for the requested table */
635 for (i = 0; i < NumberOfTables; i++)
639 TableAddress = Gbl_Xsdt->TableOffsetEntry[i];
643 TableAddress = Gbl_Rsdt->TableOffsetEntry[i];
646 MappedTable = AcpiOsMapMemory (TableAddress, sizeof (*MappedTable));
649 return (AE_BAD_ADDRESS);
652 /* Does this table match the requested signature? */
654 if (ACPI_COMPARE_NAME (MappedTable->Signature, Signature))
657 /* Match table instance (for SSDT/UEFI tables) */
659 if (CurrentInstance == Instance)
661 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
668 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
679 return (AE_NOT_FOUND);
682 /* Now we can get the requested table */
684 Status = OslMapTable (TableAddress, Signature, &MappedTable);
685 if (ACPI_FAILURE (Status))
690 /* Copy table to local buffer and return it */
692 LocalTable = calloc (1, MappedTable->Length);
695 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
696 return (AE_NO_MEMORY);
699 memcpy (LocalTable, MappedTable, MappedTable->Length);
700 AcpiOsUnmapMemory (MappedTable, MappedTable->Length);
702 *Address = TableAddress;
707 /******************************************************************************
709 * FUNCTION: OslAddTablesToList
713 * RETURN: Status; Table list is initialized if AE_OK.
715 * DESCRIPTION: Add ACPI tables to the table list.
717 *****************************************************************************/
723 ACPI_PHYSICAL_ADDRESS TableAddress;
724 OSL_TABLE_INFO *Info = NULL;
725 OSL_TABLE_INFO *NewInfo;
726 ACPI_TABLE_HEADER *Table;
728 UINT8 NumberOfTables;
732 /* Initialize the table list on first invocation */
734 if (Gbl_TableListInitialized)
739 /* Add mandatory tables to global table list first */
741 for (i = 0; i < 4; i++)
743 NewInfo = calloc (1, sizeof (*NewInfo));
746 return (AE_NO_MEMORY);
752 Gbl_TableListHead = Info = NewInfo;
757 ACPI_MOVE_NAME (NewInfo->Signature,
758 Gbl_Revision ? ACPI_SIG_XSDT : ACPI_SIG_RSDT);
763 ACPI_MOVE_NAME (NewInfo->Signature, ACPI_SIG_FACS);
768 ACPI_MOVE_NAME (NewInfo->Signature, ACPI_SIG_DSDT);
772 Info->Next = NewInfo;
774 Gbl_TableListHead->Instance++;
777 /* Add normal tables from RSDT/XSDT to global list */
782 (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header))
783 / sizeof (Gbl_Xsdt->TableOffsetEntry[0]);
788 (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header))
789 / sizeof (Gbl_Rsdt->TableOffsetEntry[0]);
792 for (i = 0; i < NumberOfTables; i++)
796 TableAddress = Gbl_Xsdt->TableOffsetEntry[i];
800 TableAddress = Gbl_Rsdt->TableOffsetEntry[i];
803 Table = AcpiOsMapMemory (TableAddress, sizeof (*Table));
806 return (AE_BAD_ADDRESS);
810 NewInfo = Gbl_TableListHead;
811 while (NewInfo->Next != NULL)
813 NewInfo = NewInfo->Next;
814 if (ACPI_COMPARE_NAME (Table->Signature, NewInfo->Signature))
820 NewInfo = calloc (1, sizeof (*NewInfo));
823 AcpiOsUnmapMemory (Table, sizeof (*Table));
824 return (AE_NO_MEMORY);
827 ACPI_MOVE_NAME (NewInfo->Signature, Table->Signature);
829 AcpiOsUnmapMemory (Table, sizeof (*Table));
831 NewInfo->Instance = Instance;
832 NewInfo->Address = TableAddress;
833 Info->Next = NewInfo;
835 Gbl_TableListHead->Instance++;
838 Gbl_TableListInitialized = TRUE;
843 /******************************************************************************
845 * FUNCTION: OslMapTable
847 * PARAMETERS: Address - Address of the table in memory
848 * Signature - Optional ACPI Signature for desired table.
849 * Null terminated 4-character string.
850 * Table - Where a pointer to the mapped table is
853 * RETURN: Status; Mapped table is returned if AE_OK.
855 * DESCRIPTION: Map entire ACPI table into caller's address space. Also
856 * validates the table and checksum.
858 *****************************************************************************/
864 ACPI_TABLE_HEADER **Table)
866 ACPI_TABLE_HEADER *MappedTable;
870 /* Map the header so we can get the table length */
872 MappedTable = AcpiOsMapMemory (Address, sizeof (*MappedTable));
875 return (AE_BAD_ADDRESS);
878 /* Check if table is valid */
880 if (!ApIsValidHeader (MappedTable))
882 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
883 return (AE_BAD_HEADER);
886 /* If specified, signature must match */
889 !ACPI_COMPARE_NAME (Signature, MappedTable->Signature))
891 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
892 return (AE_NOT_EXIST);
895 /* Map the entire table */
897 Length = MappedTable->Length;
898 AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable));
900 MappedTable = AcpiOsMapMemory (Address, Length);
903 return (AE_BAD_ADDRESS);
906 (void) ApIsValidChecksum (MappedTable);
908 *Table = MappedTable;