1034 lines
27 KiB
C
1034 lines
27 KiB
C
/******************************************************************************
|
|
*
|
|
* Module Name: osefitbl - EFI OSL for obtaining ACPI tables
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "acpidump.h"
|
|
|
|
|
|
#define _COMPONENT ACPI_OS_SERVICES
|
|
ACPI_MODULE_NAME ("osefitbl")
|
|
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 256
|
|
#endif
|
|
|
|
|
|
/* 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
|
|
OslAddTableToList (
|
|
char *Signature,
|
|
UINT32 Instance);
|
|
|
|
static ACPI_STATUS
|
|
OslMapTable (
|
|
ACPI_SIZE Address,
|
|
char *Signature,
|
|
ACPI_TABLE_HEADER **Table);
|
|
|
|
static void
|
|
OslUnmapTable (
|
|
ACPI_TABLE_HEADER *Table);
|
|
|
|
static ACPI_STATUS
|
|
OslLoadRsdp (
|
|
void);
|
|
|
|
static ACPI_STATUS
|
|
OslListTables (
|
|
void);
|
|
|
|
static ACPI_STATUS
|
|
OslGetTable (
|
|
char *Signature,
|
|
UINT32 Instance,
|
|
ACPI_TABLE_HEADER **Table,
|
|
ACPI_PHYSICAL_ADDRESS *Address);
|
|
|
|
|
|
/* File locations */
|
|
|
|
#define EFI_SYSTAB "/sys/firmware/efi/systab"
|
|
|
|
/* 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: 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 = ACPI_ALLOCATE_ZEROED (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);
|
|
}
|
|
|
|
/* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
|
|
|
|
if (!Gbl_DumpCustomizedTables)
|
|
{
|
|
/* Attempt to get the table from the memory */
|
|
|
|
Status = OslGetTable (Signature, Instance, Table, Address);
|
|
}
|
|
else
|
|
{
|
|
/* Attempt to get the table from the static directory */
|
|
|
|
Status = AE_SUPPORT;
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION: OslAddTableToList
|
|
*
|
|
* PARAMETERS: Signature - Table signature
|
|
* Instance - Table instance
|
|
*
|
|
* 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,
|
|
UINT32 Instance)
|
|
{
|
|
OSL_TABLE_INFO *NewInfo;
|
|
OSL_TABLE_INFO *Next;
|
|
UINT32 NextInstance = 0;
|
|
BOOLEAN Found = FALSE;
|
|
|
|
|
|
NewInfo = ACPI_ALLOCATE_ZEROED (sizeof (OSL_TABLE_INFO));
|
|
if (!NewInfo)
|
|
{
|
|
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 == Instance)
|
|
{
|
|
Found = TRUE;
|
|
}
|
|
if (Next->Instance >= NextInstance)
|
|
{
|
|
NextInstance = Next->Instance + 1;
|
|
}
|
|
}
|
|
|
|
if (!Next->Next)
|
|
{
|
|
break;
|
|
}
|
|
Next = Next->Next;
|
|
}
|
|
Next->Next = NewInfo;
|
|
}
|
|
|
|
if (Found)
|
|
{
|
|
if (Instance)
|
|
{
|
|
AcpiLogError (
|
|
"%4.4s: Warning unmatched table instance %d, expected %d\n",
|
|
Signature, Instance, NextInstance);
|
|
}
|
|
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.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
OslLoadRsdp (
|
|
void)
|
|
{
|
|
ACPI_TABLE_HEADER *MappedTable;
|
|
UINT8 *RsdpAddress;
|
|
ACPI_PHYSICAL_ADDRESS RsdpBase;
|
|
ACPI_SIZE RsdpSize;
|
|
|
|
|
|
/* Get RSDP from memory */
|
|
|
|
RsdpSize = sizeof (ACPI_TABLE_RSDP);
|
|
if (Gbl_RsdpBase)
|
|
{
|
|
RsdpBase = Gbl_RsdpBase;
|
|
}
|
|
else
|
|
{
|
|
RsdpBase = AcpiOsGetRootPointer ();
|
|
}
|
|
|
|
if (!RsdpBase)
|
|
{
|
|
RsdpBase = ACPI_HI_RSDP_WINDOW_BASE;
|
|
RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE;
|
|
}
|
|
|
|
RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize);
|
|
if (!RsdpAddress)
|
|
{
|
|
return (AE_BAD_ADDRESS);
|
|
}
|
|
|
|
/* Search low memory for the RSDP */
|
|
|
|
MappedTable = ACPI_CAST_PTR (ACPI_TABLE_HEADER,
|
|
AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize));
|
|
if (!MappedTable)
|
|
{
|
|
AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
|
|
return (AE_NOT_FOUND);
|
|
}
|
|
|
|
Gbl_RsdpAddress = RsdpBase + (ACPI_CAST8 (MappedTable) - RsdpAddress);
|
|
|
|
memcpy (&Gbl_Rsdp, MappedTable, sizeof (ACPI_TABLE_RSDP));
|
|
AcpiOsUnmapMemory (RsdpAddress, RsdpSize);
|
|
|
|
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)
|
|
{
|
|
ACPI_FREE (Gbl_Xsdt);
|
|
Gbl_Xsdt = NULL;
|
|
}
|
|
|
|
Gbl_Revision = 2;
|
|
Status = OslGetTable (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)
|
|
{
|
|
ACPI_FREE (Gbl_Rsdt);
|
|
Gbl_Rsdt = NULL;
|
|
}
|
|
|
|
Status = OslGetTable (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)
|
|
{
|
|
ACPI_FREE (Gbl_Fadt);
|
|
Gbl_Fadt = NULL;
|
|
}
|
|
|
|
Status = OslGetTable (ACPI_SIG_FADT, 0,
|
|
ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
if (!Gbl_DumpCustomizedTables)
|
|
{
|
|
/* Add mandatory tables to global table list first */
|
|
|
|
Status = OslAddTableToList (ACPI_RSDP_NAME, 0);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
Status = OslAddTableToList (ACPI_SIG_RSDT, 0);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
if (Gbl_Revision == 2)
|
|
{
|
|
Status = OslAddTableToList (ACPI_SIG_XSDT, 0);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
}
|
|
|
|
Status = OslAddTableToList (ACPI_SIG_DSDT, 0);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
Status = OslAddTableToList (ACPI_SIG_FACS, 0);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
/* Add all tables found in the memory */
|
|
|
|
Status = OslListTables ();
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Add all tables found in the static directory */
|
|
|
|
Status = AE_SUPPORT;
|
|
}
|
|
|
|
Gbl_TableListInitialized = TRUE;
|
|
return (AE_OK);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION: OslListTables
|
|
*
|
|
* PARAMETERS: None
|
|
*
|
|
* RETURN: Status; Table list is initialized if AE_OK.
|
|
*
|
|
* DESCRIPTION: Add ACPI tables to the table list from memory.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
OslListTables (
|
|
void)
|
|
{
|
|
ACPI_TABLE_HEADER *MappedTable = NULL;
|
|
UINT8 *TableData;
|
|
UINT8 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 =
|
|
(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)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Status = OslMapTable (TableAddress, NULL, &MappedTable);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
OslAddTableToList (MappedTable->Signature, 0);
|
|
OslUnmapTable (MappedTable);
|
|
}
|
|
|
|
return (AE_OK);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION: OslGetTable
|
|
*
|
|
* 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
|
|
OslGetTable (
|
|
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))
|
|
{
|
|
/*
|
|
* 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)
|
|
{
|
|
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)
|
|
{
|
|
return (AE_LIMIT);
|
|
}
|
|
|
|
if (TableLength == 0)
|
|
{
|
|
Status = AE_BAD_HEADER;
|
|
goto Exit;
|
|
}
|
|
|
|
/* Copy table to local buffer and return it */
|
|
|
|
LocalTable = ACPI_ALLOCATE_ZEROED (TableLength);
|
|
if (!LocalTable)
|
|
{
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
AcpiLogError ("Could not map table header at 0x%8.8X%8.8X\n",
|
|
ACPI_FORMAT_UINT64 (Address));
|
|
return (AE_BAD_ADDRESS);
|
|
}
|
|
|
|
/* If specified, signature must match */
|
|
|
|
if (Signature)
|
|
{
|
|
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)
|
|
{
|
|
AcpiLogError ("Could not map table at 0x%8.8X%8.8X length %8.8X\n",
|
|
ACPI_FORMAT_UINT64 (Address), Length);
|
|
return (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)
|
|
{
|
|
AcpiOsUnmapMemory (Table, ApGetTableLength (Table));
|
|
}
|
|
}
|