diff options
Diffstat (limited to 'source/os_specific/service_layers/oslinuxtbl.c')
-rw-r--r-- | source/os_specific/service_layers/oslinuxtbl.c | 1221 |
1 files changed, 1205 insertions, 16 deletions
diff --git a/source/os_specific/service_layers/oslinuxtbl.c b/source/os_specific/service_layers/oslinuxtbl.c index 2d1be3f..67a5e02 100644 --- a/source/os_specific/service_layers/oslinuxtbl.c +++ b/source/os_specific/service_layers/oslinuxtbl.c @@ -41,15 +41,112 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include "acpi.h" +#include "acpidump.h" + +#include <dirent.h> +#include <sys/mman.h> -#include <stdio.h> -#include <stdlib.h> #define _COMPONENT ACPI_OS_SERVICES ACPI_MODULE_NAME ("oslinuxtbl") +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + + +/* Local prototypes */ + +static ACPI_STATUS +OslTableInitialize ( + void); + +static ACPI_STATUS +OslReadTableFromFile ( + FILE *TableFile, + ACPI_SIZE FileOffset, + char *Signature, + ACPI_TABLE_HEADER **Table); + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table); + +static ACPI_STATUS +OslGetOverrideTable ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); + +static ACPI_STATUS +OslGetDynamicSsdt ( + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); + +static ACPI_STATUS +OslAddTablesToList ( + char *Directory); + +static ACPI_STATUS +OslGetTableViaRoot ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); + + +/* File locations */ + +#define DYNAMIC_SSDT_DIR "/sys/firmware/acpi/tables/dynamic" +#define OVERRIDE_TABLE_DIR "/sys/firmware/acpi/tables" +#define SYSTEM_MEMORY "/dev/mem" + +/* Should we get dynamically loaded SSDTs from DYNAMIC_SSDT_DIR? */ + +UINT8 Gbl_DumpDynamicSsdts = TRUE; + +/* Initialization flags */ + +UINT8 Gbl_TableListInitialized = FALSE; +UINT8 Gbl_MainTableObtained = FALSE; + +/* Local copies of main ACPI tables */ + +ACPI_TABLE_RSDP Gbl_Rsdp; +ACPI_TABLE_FADT *Gbl_Fadt; +ACPI_TABLE_RSDT *Gbl_Rsdt; +ACPI_TABLE_XSDT *Gbl_Xsdt; + +/* Fadt address */ + +ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress; + +/* Revision of RSD PTR */ + +UINT8 Gbl_Revision; + +/* List of information about obtained ACPI tables */ + +typedef struct table_info +{ + struct table_info *Next; + UINT32 Instance; + char Signature[4]; + +} OSL_TABLE_INFO; + +OSL_TABLE_INFO *Gbl_TableListHead = NULL; + + /****************************************************************************** * * FUNCTION: AcpiOsGetTableByAddress @@ -69,9 +166,150 @@ AcpiOsGetTableByAddress ( ACPI_PHYSICAL_ADDRESS Address, ACPI_TABLE_HEADER **Table) { + ACPI_TABLE_HEADER *MappedTable; + ACPI_TABLE_HEADER *LocalTable; + ACPI_STATUS Status; + + + /* Validate the input physical address to avoid program crash */ + + if (Address < ACPI_HI_RSDP_WINDOW_BASE) + { + fprintf (stderr, "Invalid table address: 0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Address)); + return (AE_BAD_ADDRESS); + } + + /* 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 */ + + LocalTable = calloc (1, MappedTable->Length); + if (!LocalTable) + { + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY (LocalTable, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + + *Table = LocalTable; + return (AE_OK); +} + + +/****************************************************************************** + * + * 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; + + + /* Instance is only valid for SSDTs */ + + if (Instance && + !ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT) && + !ACPI_COMPARE_NAME (Signature, ACPI_SIG_UEFI)) + { + return (AE_LIMIT); + } + + /* Get main ACPI tables from memory on first invocation of this function */ + + if (!Gbl_MainTableObtained) + { + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_MainTableObtained = TRUE; + } - fprintf (stderr, "Linux version not implemented yet\n"); - return (AE_SUPPORT); + /* + * If one of the main ACPI tables was requested (RSDT/XSDT/FADT), + * simply return it immediately. + */ + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT)) + { + if (!Gbl_Revision) + { + return (AE_NOT_FOUND); + } + + *Address = Gbl_Rsdp.XsdtPhysicalAddress; + *Table = (ACPI_TABLE_HEADER *) Gbl_Xsdt; + return (AE_OK); + } + + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT)) + { + if (!Gbl_Rsdp.RsdtPhysicalAddress) + { + return (AE_NOT_FOUND); + } + + *Address = Gbl_Rsdp.RsdtPhysicalAddress; + *Table = (ACPI_TABLE_HEADER *) Gbl_Rsdt; + return (AE_OK); + } + + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FADT)) + { + *Address = Gbl_FadtAddress; + *Table = (ACPI_TABLE_HEADER *) Gbl_Fadt; + return (AE_OK); + } + + /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ + + Status = OslGetTableViaRoot (Signature, Instance, Table, Address); + if (ACPI_FAILURE (Status)) + { + /* Attempt to get the table from the override directory */ + + Status = OslGetOverrideTable (Signature, Instance, Table, Address); + if ((Status == AE_LIMIT) && Gbl_DumpDynamicSsdts) + { + /* Attempt to get a dynamic SSDT */ + + Status = OslGetDynamicSsdt (Instance, Table, Address); + } + + return (Status); + } + + return (AE_OK); } @@ -98,40 +336,991 @@ AcpiOsGetTableByIndex ( ACPI_TABLE_HEADER **Table, ACPI_PHYSICAL_ADDRESS *Address) { + OSL_TABLE_INFO *Info; + ACPI_STATUS Status; + UINT32 i; + - fprintf (stderr, "Linux version not implemented yet\n"); - return (AE_SUPPORT); + /* Initialize the table list on first invocation */ + + if (!Gbl_TableListInitialized) + { + Gbl_TableListHead = calloc (1, sizeof (OSL_TABLE_INFO)); + + /* List head records the length of the list */ + + Gbl_TableListHead->Instance = 0; + + /* Add all tables found in the override directory */ + + Status = OslAddTablesToList (OVERRIDE_TABLE_DIR); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Add all dynamically loaded SSDTs in the dynamic directory */ + + OslAddTablesToList (DYNAMIC_SSDT_DIR); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_TableListInitialized = TRUE; + } + + /* Validate Index */ + + if (Index >= Gbl_TableListHead->Instance) + { + 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); + return (Status); } /****************************************************************************** * - * FUNCTION: AcpiOsGetTableByName + * FUNCTION: AcpiOsMapMemory * - * PARAMETERS: Signature - ACPI Signature for desired table. Must be + * PARAMETERS: Where - Physical address of memory to be mapped + * Length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into local address space. + * + *****************************************************************************/ + +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS Where, + ACPI_SIZE Length) +{ + UINT8 *MappedMemory; + ACPI_PHYSICAL_ADDRESS Offset; + ACPI_SIZE PageSize; + int fd; + + + fd = open (SYSTEM_MEMORY, O_RDONLY | O_BINARY); + if (fd < 0) + { + fprintf (stderr, "Cannot open %s\n", SYSTEM_MEMORY); + return (NULL); + } + + /* Align the offset to use mmap */ + + PageSize = sysconf (_SC_PAGESIZE); + Offset = Where % PageSize; + + /* Map the table header to get the length of the full table */ + + MappedMemory = mmap (NULL, (Length + Offset), PROT_READ, MAP_PRIVATE, + fd, (Where - Offset)); + close (fd); + + if (MappedMemory == MAP_FAILED) + { + return (NULL); + } + + return (ACPI_CAST8 (MappedMemory + Offset)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsUnmapMemory + * + * PARAMETERS: Where - Logical address of memory to be unmapped + * Length - How much memory to unmap + * + * RETURN: None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void +AcpiOsUnmapMemory ( + void *Where, + ACPI_SIZE Length) +{ + ACPI_PHYSICAL_ADDRESS Offset; + ACPI_SIZE PageSize; + + + PageSize = sysconf (_SC_PAGESIZE); + Offset = (ACPI_PHYSICAL_ADDRESS) Where % PageSize; + munmap ((UINT8 *) Where - Offset, (Length + Offset)); +} + + +/****************************************************************************** + * + * 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_TABLE_HEADER *MappedTable; + UINT8 *TableData; + UINT8 *RsdpAddress; + ACPI_PHYSICAL_ADDRESS RsdpBase; + ACPI_SIZE RsdpSize; + ACPI_STATUS Status; + + + /* Get RSDP from memory */ + + 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_ERROR); + } + + ACPI_MEMCPY (&Gbl_Rsdp, MappedTable, sizeof (ACPI_TABLE_RSDP)); + AcpiOsUnmapMemory (RsdpAddress, RsdpSize); + + /* Get XSDT from memory */ + + if (Gbl_Rsdp.Revision) + { + Status = OslMapTable (Gbl_Rsdp.XsdtPhysicalAddress, + ACPI_SIG_XSDT, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_Revision = 2; + Gbl_Xsdt = calloc (1, MappedTable->Length); + if (!Gbl_Xsdt) + { + fprintf (stderr, + "XSDT: Could not allocate buffer for table of length %X\n", + MappedTable->Length); + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY (Gbl_Xsdt, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + } + + /* Get RSDT from memory */ + + if (Gbl_Rsdp.RsdtPhysicalAddress) + { + Status = OslMapTable (Gbl_Rsdp.RsdtPhysicalAddress, + ACPI_SIG_RSDT, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_Rsdt = calloc (1, MappedTable->Length); + if (!Gbl_Rsdt) + { + fprintf (stderr, + "RSDT: Could not allocate buffer for table of length %X\n", + MappedTable->Length); + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY (Gbl_Rsdt, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + } + + /* Get FADT from memory */ + + if (Gbl_Revision) + { + TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); + Gbl_FadtAddress = (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); + } + else + { + TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); + Gbl_FadtAddress = (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); + } + + if (!Gbl_FadtAddress) + { + fprintf(stderr, "FADT: Table could not be found\n"); + return (AE_ERROR); + } + + Status = OslMapTable (Gbl_FadtAddress, ACPI_SIG_FADT, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_Fadt = calloc (1, MappedTable->Length); + if (!Gbl_Fadt) + { + fprintf (stderr, + "FADT: Could not allocate buffer for table of length %X\n", + MappedTable->Length); + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY (Gbl_Fadt, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslGetTableViaRoot + * + * PARAMETERS: Signature - ACPI Signature for common table. Must be * a null terminated 4-character string. - * Instance - For SSDTs (0...n) + * 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. - * - * 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 an ACPI table via the root table (RSDT/XSDT) + * * NOTE: Assumes the input signature is uppercase. * *****************************************************************************/ -ACPI_STATUS -AcpiOsGetTableByName ( +static ACPI_STATUS +OslGetTableViaRoot ( + 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; + ACPI_STATUS Status; + UINT32 i; + + + /* DSDT and FACS address must be extracted from the FADT */ + + if (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 /* 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; + } + } + + if (!TableAddress) + { + fprintf (stderr, + "Could not find a valid address for %4.4s in the FADT\n", + Signature); + + return (AE_NOT_FOUND); + } + + /* Now we can get the requested table (DSDT or FACS) */ + + Status = OslMapTable (TableAddress, Signature, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else /* Case for a normal ACPI table */ + { + if (Gbl_Revision) + { + ItemSize = sizeof (UINT64); + TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (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 = + (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 (Gbl_Revision) + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); + } + else + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); + } + + Status = OslMapTable (TableAddress, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Does this table match the requested signature? */ + + if (!ACPI_COMPARE_NAME (MappedTable->Signature, Signature)) + { + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + MappedTable = NULL; + continue; + } + + /* Match table instance (for SSDT/UEFI tables) */ + + if (CurrentInstance != Instance) + { + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + MappedTable = NULL; + CurrentInstance++; + continue; + } + + break; + } + } + + if (CurrentInstance != Instance) + { + return (AE_LIMIT); + } + + if (!MappedTable) + { + return (AE_NOT_FOUND); + } + + /* Copy table to local buffer and return it */ + + LocalTable = calloc (1, MappedTable->Length); + if (!LocalTable) + { + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY (LocalTable, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + *Address = TableAddress; + + *Table = LocalTable; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslAddTablesToList + * + * PARAMETERS: Directory - Directory that contains the tables + * + * RETURN: Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from a directory. + * + *****************************************************************************/ + +static ACPI_STATUS +OslAddTablesToList( + char *Directory) +{ + struct stat FileInfo; + OSL_TABLE_INFO *NewInfo; + OSL_TABLE_INFO *Info; + struct dirent *DirInfo; + DIR *TableDir; + char TempName[4]; + char Filename[PATH_MAX]; + UINT32 i; + + + /* Open the requested directory */ + + if (stat (Directory, &FileInfo) == -1) + { + return (AE_NOT_FOUND); + } + + if (!(TableDir = opendir (Directory))) + { + return (AE_ERROR); + } + + /* Move pointer to the end of the list */ + + if (!Gbl_TableListHead) + { + return (AE_ERROR); + } + + Info = Gbl_TableListHead; + for (i = 0; i < Gbl_TableListHead->Instance; i++) + { + Info = Info->Next; + } + + /* Examine all entries in this directory */ + + while ((DirInfo = readdir (TableDir)) != 0) + { + /* Ignore meaningless files */ + + if (DirInfo->d_name[0] == '.') + { + continue; + } + + /* Skip any subdirectories and create a new info node */ + + sprintf (Filename, "%s/%s", Directory, DirInfo->d_name); + + if (stat (Filename, &FileInfo) == -1) + { + return (AE_ERROR); + } + + if (!S_ISDIR (FileInfo.st_mode)) + { + NewInfo = calloc (1, sizeof (OSL_TABLE_INFO)); + if (strlen (DirInfo->d_name) > ACPI_NAME_SIZE) + { + sscanf (DirInfo->d_name, "%[^1-9]%d", + TempName, &NewInfo->Instance); + } + + /* Add new info node to global table list */ + + sscanf (DirInfo->d_name, "%4s", NewInfo->Signature); + Info->Next = NewInfo; + Info = NewInfo; + Gbl_TableListHead->Instance++; + } + } + + closedir (TableDir); + return (AE_OK); +} + + +/****************************************************************************** + * + * 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. + * + * DESCRIPTION: Map entire ACPI table into caller's address space. Also + * validates the table and checksum. + * + *****************************************************************************/ + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table) +{ + ACPI_TABLE_HEADER *MappedTable; + UINT32 Length; + + + /* Map the header so we can get the table length */ + + MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); + if (!MappedTable) + { + fprintf (stderr, "Could not map table header at 0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Address)); + return (AE_BAD_ADDRESS); + } + + /* Check if table is valid */ + + if (!ApIsValidHeader (MappedTable)) + { + return (AE_BAD_HEADER); + } + + /* If specified, signature must match */ + + if (Signature && + !ACPI_COMPARE_NAME (Signature, MappedTable->Signature)) + { + return (AE_NOT_EXIST); + } + + /* Map the entire table */ + + Length = MappedTable->Length; + AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); + + MappedTable = AcpiOsMapMemory (Address, Length); + if (!MappedTable) + { + fprintf (stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n", + ACPI_FORMAT_UINT64 (Address), Length); + return (AE_NO_MEMORY); + } + + *Table = MappedTable; + + /* + * Checksum for RSDP. + * Note: Other checksums are computed during the table dump. + */ + if (!ACPI_STRNCMP (MappedTable->Signature, ACPI_SIG_RSDP, + sizeof (ACPI_SIG_RSDP) - 1)) + { + /* Check the standard checksum */ + + if (AcpiTbChecksum ((UINT8 *) MappedTable, ACPI_RSDP_CHECKSUM_LENGTH)) + { + fprintf (stderr, "Warning: wrong checksum for RSDP\n"); + } + + /* Check extended checksum if table version >= 2 */ + + if (MappedTable->Revision) + { + if (AcpiTbChecksum ((UINT8 *) MappedTable, + ACPI_RSDP_XCHECKSUM_LENGTH)) + { + fprintf (stderr, "Warning: wrong checksum for RSDP\n"); + } + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslReadTableFromFile + * + * PARAMETERS: TableFile - File that contains the desired table + * FileOffset - Offset of the table in file + * Signature - Optional ACPI Signature for desired table. + * A null terminated 4-character string. + * Table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * + * DESCRIPTION: Read a ACPI table from a file. + * + *****************************************************************************/ + +static ACPI_STATUS +OslReadTableFromFile ( + FILE *TableFile, + ACPI_SIZE FileOffset, + char *Signature, + ACPI_TABLE_HEADER **Table) +{ + ACPI_TABLE_HEADER Header; + ACPI_TABLE_RSDP Rsdp; + ACPI_TABLE_HEADER *LocalTable; + UINT32 TableLength; + UINT32 Count; + + + /* Read the table header */ + + fseek (TableFile, FileOffset, SEEK_SET); + + Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile); + if (Count != sizeof (ACPI_TABLE_HEADER)) + { + fprintf (stderr, "Could not read ACPI table header from file\n"); + return (AE_BAD_HEADER); + } + + /* Check if table is valid */ + + if (!ApIsValidHeader (&Header)) + { + return (AE_BAD_HEADER); + } + + /* If signature is specified, it must match the table */ + + if (Signature && + !ACPI_COMPARE_NAME (Signature, Header.Signature)) + { + fprintf (stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n", + Signature, Header.Signature); + return (AE_NOT_FOUND); + } + + /* + * For RSDP, we must read the entire table, because the length field + * is in a non-standard place, beyond the normal ACPI header. + */ + if (ACPI_COMPARE_NAME (Header.Signature, ACPI_SIG_RSDP)) + { + fseek (TableFile, FileOffset, SEEK_SET); + + Count = fread (&Rsdp, 1, sizeof (ACPI_TABLE_RSDP), TableFile); + if (Count != sizeof (ACPI_TABLE_RSDP)) + { + fprintf (stderr, "Error while reading RSDP\n"); + return (AE_NOT_FOUND); + } + + TableLength = Rsdp.Length; + } + else + { + TableLength = Header.Length; + } + + /* Read the entire table into a local buffer */ + + LocalTable = calloc (1, TableLength); + if (!LocalTable) + { + fprintf (stderr, + "%4.4s: Could not allocate buffer for table of length %X\n", + Header.Signature, TableLength); + return (AE_NO_MEMORY); + } + + fseek (TableFile, FileOffset, SEEK_SET); + + Count = fread (LocalTable, 1, TableLength, TableFile); + if (Count != TableLength) + { + fprintf (stderr, "%4.4s: Error while reading table content\n", + Header.Signature); + return (AE_NOT_FOUND); + } + + /* Validate checksum, except for special tables */ + + if (!ACPI_COMPARE_NAME (Header.Signature, ACPI_SIG_S3PT) && + !ACPI_COMPARE_NAME (Header.Signature, ACPI_SIG_FACS)) + { + if (AcpiTbChecksum ((UINT8 *) LocalTable, TableLength)) + { + fprintf (stderr, "%4.4s: Warning: wrong checksum\n", + Header.Signature); + } + } + + *Table = LocalTable; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslGetOverrideTable + * + * 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 is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Get a table that was overridden and appears under the + * directory OVERRIDE_TABLE_DIR. + * + *****************************************************************************/ + +static ACPI_STATUS +OslGetOverrideTable ( char *Signature, UINT32 Instance, ACPI_TABLE_HEADER **Table, ACPI_PHYSICAL_ADDRESS *Address) { + ACPI_TABLE_HEADER Header; + struct stat FileInfo; + struct dirent *DirInfo; + DIR *TableDir; + FILE *TableFile = NULL; + UINT32 CurrentInstance = 0; + UINT32 Count; + char TempName[4]; + char TableFilename[PATH_MAX]; + ACPI_STATUS Status; + + + /* Open the directory for override tables */ + + if (stat (OVERRIDE_TABLE_DIR, &FileInfo) == -1) + { + return (AE_NOT_FOUND); + } + + if (!(TableDir = opendir (OVERRIDE_TABLE_DIR))) + { + return (AE_ERROR); + } + + /* Attempt to find the table in the directory */ + + while ((DirInfo = readdir (TableDir)) != 0) + { + /* Ignore meaningless files */ + + if (DirInfo->d_name[0] == '.') + { + continue; + } + + if (!ACPI_COMPARE_NAME (DirInfo->d_name, Signature)) + { + continue; + } + + if (strlen (DirInfo->d_name) > 4) + { + sscanf (DirInfo->d_name, "%[^1-9]%d", TempName, &CurrentInstance); + if (CurrentInstance != Instance) + { + continue; + } + } + + /* Create the table pathname and open the file */ + + sprintf (TableFilename, "%s/%s", OVERRIDE_TABLE_DIR, DirInfo->d_name); + + TableFile = fopen (TableFilename, "rb"); + if (TableFile == NULL) + { + perror (TableFilename); + return (AE_ERROR); + } + + /* Read the Table header to get the table length */ + + Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile); + if (Count != sizeof (ACPI_TABLE_HEADER)) + { + fclose (TableFile); + return (AE_ERROR); + } + + break; + } + + closedir (TableDir); + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT) && !TableFile) + { + return (AE_LIMIT); + } + + if (!TableFile) + { + return (AE_NOT_FOUND); + } + + /* There is no physical address saved for override tables, use zero */ + + *Address = 0; + Status = OslReadTableFromFile (TableFile, 0, NULL, Table); + + fclose (TableFile); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslGetDynamicSsdt + * + * PARAMETERS: Instance - For SSDTs (0...n) + * Table - Where a pointer to the table is returned + * Address - Where the table physical address 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 SSDT table under directory DYNAMIC_SSDT_DIR. + * + *****************************************************************************/ + +static ACPI_STATUS +OslGetDynamicSsdt ( + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_TABLE_HEADER Header; + struct stat FileInfo; + struct dirent *DirInfo; + DIR *TableDir; + FILE *TableFile = NULL; + UINT32 Count; + UINT32 CurrentInstance = 0; + char TempName[4]; + char TableFilename[PATH_MAX]; + ACPI_STATUS Status; + + + /* Open the directory for dynamically loaded SSDTs */ + + if (stat (DYNAMIC_SSDT_DIR, &FileInfo) == -1) + { + return (AE_NOT_FOUND); + } + + if (!(TableDir = opendir (DYNAMIC_SSDT_DIR))) + { + return (AE_ERROR); + } + + /* Search directory for correct SSDT instance */ + + while ((DirInfo = readdir (TableDir)) != 0) + { + /* Ignore meaningless files */ + + if (DirInfo->d_name[0] == '.') + { + continue; + } + + /* Check if this table is what we need */ + + sscanf (DirInfo->d_name, "%[^1-9]%d", TempName, &CurrentInstance); + if (CurrentInstance != Instance) + { + continue; + } + + /* Get the SSDT filename and open the file */ + + sprintf (TableFilename, "%s/%s", DYNAMIC_SSDT_DIR, DirInfo->d_name); + + TableFile = fopen (TableFilename, "rb"); + if (TableFile == NULL) + { + perror (TableFilename); + return (AE_ERROR); + } + + /* Read the Table header to get the table length */ + + Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile); + if (Count != sizeof (ACPI_TABLE_HEADER)) + { + fclose (TableFile); + return (AE_ERROR); + } + + break; + } + + closedir (TableDir); + if (CurrentInstance != Instance) + { + return (AE_LIMIT); + } + + /* There is no physical address saved for dynamic SSDTs, use zero */ + + *Address = 0; + Status = OslReadTableFromFile (TableFile, Header.Length, NULL, Table); - fprintf (stderr, "Linux version not implemented yet\n"); - return (AE_SUPPORT); + fclose (TableFile); + return (Status); } |