diff options
Diffstat (limited to 'usr/src/cmd/acpi/acpidump/osillumostbl.c')
-rw-r--r-- | usr/src/cmd/acpi/acpidump/osillumostbl.c | 1057 |
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); +} |