summaryrefslogtreecommitdiff
path: root/usr/src/cmd/acpi/acpidump/osillumostbl.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/acpi/acpidump/osillumostbl.c')
-rw-r--r--usr/src/cmd/acpi/acpidump/osillumostbl.c1057
1 files changed, 1057 insertions, 0 deletions
diff --git a/usr/src/cmd/acpi/acpidump/osillumostbl.c b/usr/src/cmd/acpi/acpidump/osillumostbl.c
new file mode 100644
index 0000000000..8e8375f9a2
--- /dev/null
+++ b/usr/src/cmd/acpi/acpidump/osillumostbl.c
@@ -0,0 +1,1057 @@
+/*
+ *
+ * Module Name: osillumostbl - illumos OSL for obtaining ACPI tables
+ * This file is derived from the Intel oslinuxtbl source file.
+ *
+ */
+
+/*
+ * Copyright (C) 2000 - 2016, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "acpidump.h"
+
+#define _COMPONENT ACPI_OS_SERVICES
+ ACPI_MODULE_NAME("osillumostbl")
+
+/* List of information about obtained ACPI tables */
+
+typedef struct osl_table_info
+{
+ struct osl_table_info *Next;
+ UINT32 Instance;
+ char Signature[ACPI_NAME_SIZE];
+} OSL_TABLE_INFO;
+
+/* Local prototypes */
+static ACPI_STATUS
+OslTableInitialize(void);
+static ACPI_STATUS OslTableNameFromFile(char *, char *, UINT32 *);
+static ACPI_STATUS OslAddTableToList(char *);
+static ACPI_STATUS OslMapTable(ACPI_SIZE, char *, ACPI_TABLE_HEADER **);
+static void OslUnmapTable(ACPI_TABLE_HEADER *);
+static ACPI_STATUS OslLoadRsdp(void);
+static ACPI_STATUS OslListBiosTables(void);
+static ACPI_STATUS OslGetBiosTable(char *, UINT32, ACPI_TABLE_HEADER **,
+ ACPI_PHYSICAL_ADDRESS *);
+static ACPI_STATUS OslGetLastStatus(ACPI_STATUS);
+
+static int pagesize;
+
+/* Initialization flags */
+UINT8 Gbl_TableListInitialized = FALSE;
+
+/* Local copies of main ACPI tables */
+ACPI_TABLE_RSDP Gbl_Rsdp;
+ACPI_TABLE_FADT *Gbl_Fadt = NULL;
+ACPI_TABLE_RSDT *Gbl_Rsdt = NULL;
+ACPI_TABLE_XSDT *Gbl_Xsdt = NULL;
+
+/* Table addresses */
+ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress = 0;
+ACPI_PHYSICAL_ADDRESS Gbl_RsdpAddress = 0;
+
+/* Revision of RSD PTR */
+UINT8 Gbl_Revision = 0;
+
+OSL_TABLE_INFO *Gbl_TableListHead = NULL;
+UINT32 Gbl_TableCount = 0;
+
+/*
+ *
+ * FUNCTION: OslGetLastStatus
+ *
+ * PARAMETERS: DefaultStatus - Default error status to return
+ *
+ * RETURN: Status; Converted from errno.
+ *
+ * DESCRIPTION: Get last errno and conver it to ACPI_STATUS.
+ *
+ */
+static ACPI_STATUS
+OslGetLastStatus(ACPI_STATUS DefaultStatus)
+{
+ switch (errno) {
+ case EACCES:
+ case EPERM:
+ return (AE_ACCESS);
+
+ case ENOENT:
+ return (AE_NOT_FOUND);
+
+ case ENOMEM:
+ return (AE_NO_MEMORY);
+
+ default:
+ return (DefaultStatus);
+ }
+}
+
+/*
+ *
+ * FUNCTION: AcpiOsGetTableByAddress
+ *
+ * PARAMETERS: Address - Physical address of the ACPI table
+ * Table - Where a pointer to the table is returned
+ *
+ * RETURN: Status; Table buffer is returned if AE_OK.
+ * AE_NOT_FOUND: A valid table was not found at the address
+ *
+ * DESCRIPTION: Get an ACPI table via a physical memory address.
+ *
+ */
+ACPI_STATUS
+AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address,
+ ACPI_TABLE_HEADER **Table)
+{
+ UINT32 TableLength;
+ ACPI_TABLE_HEADER *MappedTable;
+ ACPI_TABLE_HEADER *LocalTable = NULL;
+ ACPI_STATUS Status = AE_OK;
+
+ /*
+ * Get main ACPI tables from memory on first invocation of this
+ * function
+ */
+ Status = OslTableInitialize();
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ /* Map the table and validate it */
+
+ Status = OslMapTable(Address, NULL, &MappedTable);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ /* Copy table to local buffer and return it */
+
+ TableLength = ApGetTableLength(MappedTable);
+ if (TableLength == 0) {
+ Status = AE_BAD_HEADER;
+ goto Exit;
+ }
+
+ LocalTable = calloc(1, TableLength);
+ if (!LocalTable) {
+ Status = AE_NO_MEMORY;
+ goto Exit;
+ }
+
+ memcpy(LocalTable, MappedTable, TableLength);
+
+Exit:
+ OslUnmapTable(MappedTable);
+ *Table = LocalTable;
+ return (Status);
+}
+
+/*
+ *
+ * FUNCTION: AcpiOsGetTableByName
+ *
+ * PARAMETERS: Signature - ACPI Signature for desired table. Must be
+ * a null terminated 4-character string.
+ * Instance - Multiple table support for SSDT/UEFI (0...n)
+ * Must be 0 for other tables.
+ * Table - Where a pointer to the table is returned
+ * Address - Where the table physical address is returned
+ *
+ * RETURN: Status; Table buffer and physical address returned if AE_OK.
+ * AE_LIMIT: Instance is beyond valid limit
+ * AE_NOT_FOUND: A table with the signature was not found
+ *
+ * NOTE: Assumes the input signature is uppercase.
+ *
+ */
+ACPI_STATUS
+AcpiOsGetTableByName(char *Signature, UINT32 Instance,
+ ACPI_TABLE_HEADER **Table, ACPI_PHYSICAL_ADDRESS *Address)
+{
+ ACPI_STATUS Status;
+
+ /*
+ * Get main ACPI tables from memory on first invocation of this
+ * function
+ */
+ Status = OslTableInitialize();
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ /* attempt to extract it from the RSDT/XSDT */
+ Status = OslGetBiosTable(Signature, Instance, Table, Address);
+
+ return (Status);
+}
+
+/*
+ *
+ * FUNCTION: OslAddTableToList
+ *
+ * PARAMETERS: Signature - Table signature
+ *
+ * RETURN: Status; Successfully added if AE_OK.
+ * AE_NO_MEMORY: Memory allocation error
+ *
+ * DESCRIPTION: Insert a table structure into OSL table list.
+ *
+ */
+static ACPI_STATUS
+OslAddTableToList(char *Signature)
+{
+ OSL_TABLE_INFO *NewInfo;
+ OSL_TABLE_INFO *Next;
+ UINT32 NextInstance = 0;
+ UINT32 Instance = 0;
+ BOOLEAN Found = FALSE;
+
+ NewInfo = calloc(1, sizeof (OSL_TABLE_INFO));
+ if (NewInfo == NULL) {
+ return (AE_NO_MEMORY);
+ }
+
+ ACPI_MOVE_NAME(NewInfo->Signature, Signature);
+
+ if (!Gbl_TableListHead) {
+ Gbl_TableListHead = NewInfo;
+ } else {
+ Next = Gbl_TableListHead;
+
+ while (1) {
+ if (ACPI_COMPARE_NAME(Next->Signature, Signature)) {
+ if (Next->Instance == 0) {
+ Found = TRUE;
+ }
+ if (Next->Instance >= NextInstance) {
+ NextInstance = Next->Instance + 1;
+ }
+ }
+
+ if (!Next->Next) {
+ break;
+ }
+ Next = Next->Next;
+ }
+ Next->Next = NewInfo;
+ }
+
+ if (Found) {
+ Instance = NextInstance;
+ }
+
+ NewInfo->Instance = Instance;
+ Gbl_TableCount++;
+
+ return (AE_OK);
+}
+
+/*
+ *
+ * FUNCTION: AcpiOsGetTableByIndex
+ *
+ * PARAMETERS: Index - Which table to get
+ * Table - Where a pointer to the table is returned
+ * Instance - Where a pointer to the table instance no. is
+ * returned
+ * Address - Where the table physical address is returned
+ *
+ * RETURN: Status; Table buffer and physical address returned if AE_OK.
+ * AE_LIMIT: Index is beyond valid limit
+ *
+ * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
+ * AE_LIMIT when an invalid index is reached. Index is not
+ * necessarily an index into the RSDT/XSDT.
+ *
+ */
+ACPI_STATUS
+AcpiOsGetTableByIndex(UINT32 Index, ACPI_TABLE_HEADER **Table,
+ UINT32 *Instance, ACPI_PHYSICAL_ADDRESS *Address)
+{
+ OSL_TABLE_INFO *Info;
+ ACPI_STATUS Status;
+ UINT32 i;
+
+ /*
+ * Get main ACPI tables from memory on first invocation of this
+ * function.
+ */
+
+ Status = OslTableInitialize();
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ /* Validate Index */
+
+ if (Index >= Gbl_TableCount) {
+ return (AE_LIMIT);
+ }
+
+ /* Point to the table list entry specified by the Index argument */
+
+ Info = Gbl_TableListHead;
+ for (i = 0; i < Index; i++) {
+ Info = Info->Next;
+ }
+
+ /* Now we can just get the table via the signature */
+
+ Status = AcpiOsGetTableByName(Info->Signature, Info->Instance,
+ Table, Address);
+
+ if (ACPI_SUCCESS(Status)) {
+ *Instance = Info->Instance;
+ }
+ return (Status);
+}
+
+/*
+ *
+ * FUNCTION: OslLoadRsdp
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Scan and load RSDP.
+ * See the find_rsdp() function in usr/src/uts/i86pc/os/fakebop.c, which is how
+ * the kernel finds the RSDP. That algorithm matches AcpiFindRootPointer().
+ * The code here is derived from AcpiFindRootPointer, except that we will try
+ * the BIOS if the EBDA fails, and we will copy the table if found.
+ */
+static ACPI_STATUS
+OslLoadRsdp(void)
+{
+ UINT8 *mapp;
+ ACPI_TABLE_HEADER *tblp;
+ ACPI_SIZE mapsize;
+ ACPI_PHYSICAL_ADDRESS physaddr;
+
+ /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
+ mapp = AcpiOsMapMemory((ACPI_PHYSICAL_ADDRESS)ACPI_EBDA_PTR_LOCATION,
+ ACPI_EBDA_PTR_LENGTH);
+ if (mapp == NULL)
+ goto try_bios;
+
+ ACPI_MOVE_16_TO_32(&physaddr, mapp);
+
+ /* Convert segment part to physical address */
+ physaddr <<= 4;
+ AcpiOsUnmapMemory(mapp, ACPI_EBDA_PTR_LENGTH);
+
+ /* EBDA present? */
+ if (physaddr <= 0x400)
+ goto try_bios;
+
+ /*
+ * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of 1K
+ * length)
+ */
+ mapp = AcpiOsMapMemory(physaddr, ACPI_EBDA_WINDOW_SIZE);
+ if (mapp == NULL) {
+ (void) fprintf(stderr, "EBDA (0x%p) found, but is not "
+ "mappable\n", physaddr);
+ goto try_bios;
+ }
+
+ tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER,
+ AcpiTbScanMemoryForRsdp(mapp, ACPI_EBDA_WINDOW_SIZE));
+ if (tblp != NULL) {
+ physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp);
+ Gbl_RsdpAddress = physaddr;
+ memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP));
+ AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE);
+
+ return (AE_OK);
+ }
+ AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE);
+
+try_bios:
+ /* Try to get RSDP from BIOS memory */
+ if (Gbl_RsdpBase != NULL) {
+ physaddr = Gbl_RsdpBase;
+ mapsize = sizeof (ACPI_TABLE_RSDP);
+ } else {
+ physaddr = ACPI_HI_RSDP_WINDOW_BASE;
+ mapsize = ACPI_HI_RSDP_WINDOW_SIZE;
+ }
+
+ mapp = AcpiOsMapMemory(physaddr, mapsize);
+ if (mapp == NULL)
+ return (OslGetLastStatus(AE_BAD_ADDRESS));
+
+ /* Search low memory for the RSDP */
+ tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER,
+ AcpiTbScanMemoryForRsdp(mapp, mapsize));
+ if (tblp == NULL) {
+ AcpiOsUnmapMemory(mapp, mapsize);
+ return (AE_NOT_FOUND);
+ }
+
+ physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp);
+ Gbl_RsdpAddress = physaddr;
+ memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP));
+ AcpiOsUnmapMemory(mapp, mapsize);
+
+ return (AE_OK);
+}
+
+/*
+ *
+ * FUNCTION: OslCanUseXsdt
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: TRUE if XSDT is allowed to be used.
+ *
+ * DESCRIPTION: This function collects logic that can be used to determine if
+ * XSDT should be used instead of RSDT.
+ *
+ */
+static BOOLEAN
+OslCanUseXsdt(void)
+{
+ if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/*
+ *
+ * FUNCTION: OslTableInitialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
+ * local variables. Main ACPI tables include RSDT, FADT, RSDT,
+ * and/or XSDT.
+ *
+ */
+static ACPI_STATUS
+OslTableInitialize(void)
+{
+ ACPI_STATUS Status;
+ ACPI_PHYSICAL_ADDRESS Address;
+
+ if (Gbl_TableListInitialized) {
+ return (AE_OK);
+ }
+
+ /* Get RSDP from memory */
+
+ Status = OslLoadRsdp();
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ /* Get XSDT from memory */
+
+ if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) {
+ if (Gbl_Xsdt) {
+ free(Gbl_Xsdt);
+ Gbl_Xsdt = NULL;
+ }
+
+ Gbl_Revision = 2;
+ Status = OslGetBiosTable(ACPI_SIG_XSDT, 0,
+ ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+ }
+
+ /* Get RSDT from memory */
+
+ if (Gbl_Rsdp.RsdtPhysicalAddress) {
+ if (Gbl_Rsdt) {
+ free(Gbl_Rsdt);
+ Gbl_Rsdt = NULL;
+ }
+
+ Status = OslGetBiosTable(ACPI_SIG_RSDT, 0,
+ ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+ }
+
+ /* Get FADT from memory */
+
+ if (Gbl_Fadt) {
+ free(Gbl_Fadt);
+ Gbl_Fadt = NULL;
+ }
+
+ Status = OslGetBiosTable(ACPI_SIG_FADT, 0,
+ ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ /* Add mandatory tables to global table list first */
+
+ Status = OslAddTableToList(ACPI_RSDP_NAME);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ Status = OslAddTableToList(ACPI_SIG_RSDT);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ if (Gbl_Revision == 2) {
+ Status = OslAddTableToList(ACPI_SIG_XSDT);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+ }
+
+ Status = OslAddTableToList(ACPI_SIG_DSDT);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ Status = OslAddTableToList(ACPI_SIG_FACS);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ /* Add all tables found in the memory */
+
+ Status = OslListBiosTables();
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ Gbl_TableListInitialized = TRUE;
+ return (AE_OK);
+}
+
+
+/*
+ *
+ * FUNCTION: OslListBiosTables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status; Table list is initialized if AE_OK.
+ *
+ * DESCRIPTION: Add ACPI tables to the table list from memory.
+ */
+static ACPI_STATUS
+OslListBiosTables(void)
+{
+ ACPI_TABLE_HEADER *MappedTable = NULL;
+ UINT8 *TableData;
+ UINT32 NumberOfTables;
+ UINT8 ItemSize;
+ ACPI_PHYSICAL_ADDRESS TableAddress = 0;
+ ACPI_STATUS Status = AE_OK;
+ UINT32 i;
+
+ if (OslCanUseXsdt()) {
+ ItemSize = sizeof (UINT64);
+ TableData = ACPI_CAST8(Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
+ NumberOfTables = (UINT32)
+ ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
+ / ItemSize);
+
+ } else {
+ /* Use RSDT if XSDT is not available */
+ ItemSize = sizeof (UINT32);
+ TableData = ACPI_CAST8(Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
+ NumberOfTables = (UINT32)
+ ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
+ / ItemSize);
+ }
+
+ /* Search RSDT/XSDT for the requested table */
+
+ for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) {
+ if (OslCanUseXsdt()) {
+ TableAddress =
+ (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64(TableData));
+ } else {
+ TableAddress =
+ (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32(TableData));
+ }
+
+ /* Skip NULL entries in RSDT/XSDT */
+ if (TableAddress == NULL) {
+ continue;
+ }
+
+ Status = OslMapTable(TableAddress, NULL, &MappedTable);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ OslAddTableToList(MappedTable->Signature);
+ OslUnmapTable(MappedTable);
+ }
+
+ return (AE_OK);
+}
+
+/*
+ *
+ * FUNCTION: OslGetBiosTable
+ *
+ * PARAMETERS: Signature - ACPI Signature for common table. Must be
+ * a null terminated 4-character string.
+ * Instance - Multiple table support for SSDT/UEFI (0...n)
+ * Must be 0 for other tables.
+ * Table - Where a pointer to the table is returned
+ * Address - Where the table physical address is returned
+ *
+ * RETURN: Status; Table buffer and physical address returned if AE_OK.
+ * AE_LIMIT: Instance is beyond valid limit
+ * AE_NOT_FOUND: A table with the signature was not found
+ *
+ * DESCRIPTION: Get a BIOS provided ACPI table
+ *
+ * NOTE: Assumes the input signature is uppercase.
+ *
+ */
+static ACPI_STATUS
+OslGetBiosTable(char *Signature, UINT32 Instance, ACPI_TABLE_HEADER **Table,
+ ACPI_PHYSICAL_ADDRESS *Address)
+{
+ ACPI_TABLE_HEADER *LocalTable = NULL;
+ ACPI_TABLE_HEADER *MappedTable = NULL;
+ UINT8 *TableData;
+ UINT8 NumberOfTables;
+ UINT8 ItemSize;
+ UINT32 CurrentInstance = 0;
+ ACPI_PHYSICAL_ADDRESS TableAddress = 0;
+ UINT32 TableLength = 0;
+ ACPI_STATUS Status = AE_OK;
+ UINT32 i;
+
+ /* Handle special tables whose addresses are not in RSDT/XSDT */
+
+ if (ACPI_COMPARE_NAME(Signature, ACPI_RSDP_NAME) ||
+ ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT) ||
+ ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT) ||
+ ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT) ||
+ ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) {
+ if (Instance > 0) {
+ return (AE_LIMIT);
+ }
+
+ /*
+ * Get the appropriate address, either 32-bit or 64-bit. Be very
+ * careful about the FADT length and validate table addresses.
+ * Note: The 64-bit addresses have priority.
+ */
+ if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT)) {
+ if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
+ Gbl_Fadt->XDsdt) {
+ TableAddress =
+ (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
+
+ } else if (Gbl_Fadt->Header.Length >=
+ MIN_FADT_FOR_DSDT && Gbl_Fadt->Dsdt) {
+ TableAddress =
+ (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
+ }
+
+ } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) {
+ if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
+ Gbl_Fadt->XFacs) {
+ TableAddress =
+ (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
+
+ } else if (Gbl_Fadt->Header.Length >=
+ MIN_FADT_FOR_FACS && Gbl_Fadt->Facs) {
+ TableAddress =
+ (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
+ }
+
+ } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT)) {
+ if (!Gbl_Revision) {
+ return (AE_BAD_SIGNATURE);
+ }
+ TableAddress = (ACPI_PHYSICAL_ADDRESS)
+ Gbl_Rsdp.XsdtPhysicalAddress;
+
+ } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT)) {
+ TableAddress = (ACPI_PHYSICAL_ADDRESS)
+ Gbl_Rsdp.RsdtPhysicalAddress;
+
+ } else {
+ TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress;
+ Signature = ACPI_SIG_RSDP;
+ }
+
+ /* Now we can get the requested special table */
+
+ Status = OslMapTable(TableAddress, Signature, &MappedTable);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+
+ TableLength = ApGetTableLength(MappedTable);
+
+ } else {
+ /* Case for a normal ACPI table */
+ if (OslCanUseXsdt()) {
+ ItemSize = sizeof (UINT64);
+ TableData = ACPI_CAST8(Gbl_Xsdt) +
+ sizeof (ACPI_TABLE_HEADER);
+ NumberOfTables = (UINT8) ((Gbl_Xsdt->Header.Length -
+ sizeof (ACPI_TABLE_HEADER))
+ / ItemSize);
+
+ } else {
+ /* Use RSDT if XSDT is not available */
+ ItemSize = sizeof (UINT32);
+ TableData = ACPI_CAST8(Gbl_Rsdt) +
+ sizeof (ACPI_TABLE_HEADER);
+ NumberOfTables = (UINT8) ((Gbl_Rsdt->Header.Length -
+ sizeof (ACPI_TABLE_HEADER))
+ / ItemSize);
+ }
+
+ /* Search RSDT/XSDT for the requested table */
+
+ for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) {
+ if (OslCanUseXsdt()) {
+ TableAddress = (ACPI_PHYSICAL_ADDRESS)
+ (*ACPI_CAST64(TableData));
+ } else {
+ TableAddress = (ACPI_PHYSICAL_ADDRESS)
+ (*ACPI_CAST32(TableData));
+ }
+
+ /* Skip NULL entries in RSDT/XSDT */
+
+ if (TableAddress == NULL) {
+ continue;
+ }
+
+ Status = OslMapTable(TableAddress, NULL, &MappedTable);
+ if (ACPI_FAILURE(Status)) {
+ return (Status);
+ }
+ TableLength = MappedTable->Length;
+
+ /* Does this table match the requested signature? */
+
+ if (!ACPI_COMPARE_NAME(MappedTable->Signature,
+ Signature)) {
+ OslUnmapTable(MappedTable);
+ MappedTable = NULL;
+ continue;
+ }
+
+ /* Match table instance (for SSDT/UEFI tables) */
+
+ if (CurrentInstance != Instance) {
+ OslUnmapTable(MappedTable);
+ MappedTable = NULL;
+ CurrentInstance++;
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ if (MappedTable == NULL) {
+ return (AE_LIMIT);
+ }
+
+ if (TableLength == 0) {
+ Status = AE_BAD_HEADER;
+ goto Exit;
+ }
+
+ /* Copy table to local buffer and return it */
+
+ LocalTable = calloc(1, TableLength);
+ if (LocalTable == NULL) {
+ Status = AE_NO_MEMORY;
+ goto Exit;
+ }
+
+ memcpy(LocalTable, MappedTable, TableLength);
+ *Address = TableAddress;
+ *Table = LocalTable;
+
+Exit:
+ OslUnmapTable(MappedTable);
+ return (Status);
+}
+
+/*
+ *
+ * FUNCTION: OslMapTable
+ *
+ * PARAMETERS: Address - Address of the table in memory
+ * Signature - Optional ACPI Signature for desired table.
+ * Null terminated 4-character string.
+ * Table - Where a pointer to the mapped table is
+ * returned
+ *
+ * RETURN: Status; Mapped table is returned if AE_OK.
+ * AE_NOT_FOUND: A valid table was not found at the address
+ *
+ * DESCRIPTION: Map entire ACPI table into caller's address space.
+ *
+ */
+static ACPI_STATUS
+OslMapTable(ACPI_SIZE Address, char *Signature, ACPI_TABLE_HEADER **Table)
+{
+ ACPI_TABLE_HEADER *MappedTable;
+ UINT32 Length;
+
+ if (Address == NULL) {
+ return (AE_BAD_ADDRESS);
+ }
+
+ /*
+ * Map the header so we can get the table length.
+ * Use sizeof (ACPI_TABLE_HEADER) as:
+ * 1. it is bigger than 24 to include RSDP->Length
+ * 2. it is smaller than sizeof (ACPI_TABLE_RSDP)
+ */
+ MappedTable = AcpiOsMapMemory(Address, sizeof (ACPI_TABLE_HEADER));
+ if (MappedTable == NULL) {
+ (void) fprintf(stderr, "Could not map table header at "
+ "0x%8.8X%8.8X\n", ACPI_FORMAT_UINT64(Address));
+ return (OslGetLastStatus(AE_BAD_ADDRESS));
+ }
+
+ /* If specified, signature must match */
+
+ if (Signature != NULL) {
+ if (ACPI_VALIDATE_RSDP_SIG(Signature)) {
+ if (!ACPI_VALIDATE_RSDP_SIG(MappedTable->Signature)) {
+ AcpiOsUnmapMemory(MappedTable,
+ sizeof (ACPI_TABLE_HEADER));
+ return (AE_BAD_SIGNATURE);
+ }
+ } else if (!ACPI_COMPARE_NAME(Signature,
+ MappedTable->Signature)) {
+ AcpiOsUnmapMemory(MappedTable,
+ sizeof (ACPI_TABLE_HEADER));
+ return (AE_BAD_SIGNATURE);
+ }
+ }
+
+ /* Map the entire table */
+
+ Length = ApGetTableLength(MappedTable);
+ AcpiOsUnmapMemory(MappedTable, sizeof (ACPI_TABLE_HEADER));
+ if (Length == 0) {
+ return (AE_BAD_HEADER);
+ }
+
+ MappedTable = AcpiOsMapMemory(Address, Length);
+ if (MappedTable == NULL) {
+ (void) fprintf(stderr, "Could not map table at 0x%8.8X%8.8X "
+ "length %8.8X\n", ACPI_FORMAT_UINT64(Address), Length);
+ return (OslGetLastStatus(AE_INVALID_TABLE_LENGTH));
+ }
+
+ (void) ApIsValidChecksum(MappedTable);
+
+ *Table = MappedTable;
+ return (AE_OK);
+}
+
+
+/*
+ *
+ * FUNCTION: OslUnmapTable
+ *
+ * PARAMETERS: Table - A pointer to the mapped table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Unmap entire ACPI table.
+ *
+ */
+static void
+OslUnmapTable(ACPI_TABLE_HEADER *Table)
+{
+ if (Table != NULL) {
+ AcpiOsUnmapMemory(Table, ApGetTableLength(Table));
+ }
+}
+
+/*
+ *
+ * FUNCTION: OslTableNameFromFile
+ *
+ * PARAMETERS: Filename - File that contains the desired table
+ * Signature - Pointer to 4-character buffer to store
+ * extracted table signature.
+ * Instance - Pointer to integer to store extracted
+ * table instance number.
+ *
+ * RETURN: Status; Table name is extracted if AE_OK.
+ *
+ * DESCRIPTION: Extract table signature and instance number from a table file
+ * name.
+ *
+ */
+static ACPI_STATUS
+OslTableNameFromFile(char *Filename, char *Signature, UINT32 *Instance)
+{
+ /* Ignore meaningless files */
+
+ if (strlen(Filename) < ACPI_NAME_SIZE) {
+ return (AE_BAD_SIGNATURE);
+ }
+
+ /* Extract instance number */
+
+ if (isdigit((int)Filename[ACPI_NAME_SIZE])) {
+ sscanf(&Filename[ACPI_NAME_SIZE], "%u", Instance);
+ } else if (strlen(Filename) != ACPI_NAME_SIZE) {
+ return (AE_BAD_SIGNATURE);
+ } else {
+ *Instance = 0;
+ }
+
+ /* Extract signature */
+
+ ACPI_MOVE_NAME(Signature, Filename);
+ return (AE_OK);
+}
+
+UINT32
+CmGetFileSize(ACPI_FILE File)
+{
+ int fd;
+ struct stat sb;
+
+ fd = fileno(File);
+ if (fstat(fd, &sb) != 0)
+ return (ACPI_UINT32_MAX);
+ return ((UINT32)sb.st_size);
+}
+
+void *
+AcpiOsAllocateZeroed(ACPI_SIZE Size)
+{
+ return (calloc(1, Size));
+}
+
+void
+AcpiOsFree(void *p)
+{
+ free(p);
+}
+
+ACPI_FILE
+AcpiOsOpenFile(const char *Path, UINT8 Modes)
+{
+ char mode[3];
+
+ bzero(mode, sizeof (mode));
+ if ((Modes & ACPI_FILE_READING) != 0)
+ (void) strlcat(mode, "r", sizeof (mode));
+
+ if ((Modes & ACPI_FILE_WRITING) != 0)
+ (void) strlcat(mode, "w", sizeof (mode));
+
+ return (fopen(Path, mode));
+}
+
+void
+AcpiOsCloseFile(ACPI_FILE File)
+{
+ fclose(File);
+}
+
+int
+AcpiOsReadFile(ACPI_FILE File, void *Buffer, ACPI_SIZE Size, ACPI_SIZE Count)
+{
+ return (fread(Buffer, Size, Count, File));
+}
+
+void *
+AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
+{
+ int fd;
+ void *p;
+ ulong_t offset;
+
+ if ((fd = open("/dev/xsvc", O_RDONLY)) < 0)
+ return (NULL);
+
+ if (pagesize == 0) {
+ pagesize = getpagesize();
+ }
+
+ offset = Where % pagesize;
+ p = mmap(NULL, Length + offset, PROT_READ, MAP_SHARED | MAP_NORESERVE,
+ fd, Where - offset);
+
+ (void) close(fd);
+
+ if (p == MAP_FAILED)
+ return (NULL);
+ return (p + offset);
+}
+
+void
+AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Size)
+{
+ ulong_t offset;
+
+ offset = (ulong_t)LogicalAddress % pagesize;
+
+ (void) munmap(LogicalAddress - offset, Size + offset);
+}