diff options
Diffstat (limited to 'drivers/acpi/tables')
-rw-r--r-- | drivers/acpi/tables/Makefile | 8 | ||||
-rw-r--r-- | drivers/acpi/tables/tbconvrt.c | 564 | ||||
-rw-r--r-- | drivers/acpi/tables/tbget.c | 493 | ||||
-rw-r--r-- | drivers/acpi/tables/tbgetall.c | 313 | ||||
-rw-r--r-- | drivers/acpi/tables/tbinstal.c | 553 | ||||
-rw-r--r-- | drivers/acpi/tables/tbrsdt.c | 324 | ||||
-rw-r--r-- | drivers/acpi/tables/tbutils.c | 240 | ||||
-rw-r--r-- | drivers/acpi/tables/tbxface.c | 448 | ||||
-rw-r--r-- | drivers/acpi/tables/tbxfroot.c | 606 |
9 files changed, 3549 insertions, 0 deletions
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile new file mode 100644 index 00000000000..aa4c69594d9 --- /dev/null +++ b/drivers/acpi/tables/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +obj-y := tbconvrt.o tbget.o tbrsdt.o tbxface.o \ + tbgetall.o tbinstal.o tbutils.o tbxfroot.o + +EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c new file mode 100644 index 00000000000..334327c1f66 --- /dev/null +++ b/drivers/acpi/tables/tbconvrt.c @@ -0,0 +1,564 @@ +/****************************************************************************** + * + * Module Name: tbconvrt - ACPI Table conversion utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbconvrt") + + +u8 acpi_fadt_is_v1; +EXPORT_SYMBOL(acpi_fadt_is_v1); + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_table_count + * + * PARAMETERS: RSDP - Pointer to the RSDP + * RSDT - Pointer to the RSDT/XSDT + * + * RETURN: The number of tables pointed to by the RSDT or XSDT. + * + * DESCRIPTION: Calculate the number of tables. Automatically handles either + * an RSDT or XSDT. + * + ******************************************************************************/ + +u32 +acpi_tb_get_table_count ( + struct rsdp_descriptor *RSDP, + struct acpi_table_header *RSDT) +{ + u32 pointer_size; + + + ACPI_FUNCTION_ENTRY (); + + + if (RSDP->revision < 2) { + pointer_size = sizeof (u32); + } + else { + pointer_size = sizeof (u64); + } + + /* + * Determine the number of tables pointed to by the RSDT/XSDT. + * This is defined by the ACPI Specification to be the number of + * pointers contained within the RSDT/XSDT. The size of the pointers + * is architecture-dependent. + */ + return ((RSDT->length - sizeof (struct acpi_table_header)) / pointer_size); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_convert_to_xsdt + * + * PARAMETERS: table_info - Info about the RSDT + * + * RETURN: Status + * + * DESCRIPTION: Convert an RSDT to an XSDT (internal common format) + * + ******************************************************************************/ + +acpi_status +acpi_tb_convert_to_xsdt ( + struct acpi_table_desc *table_info) +{ + acpi_size table_size; + u32 i; + XSDT_DESCRIPTOR *new_table; + + + ACPI_FUNCTION_ENTRY (); + + + /* Compute size of the converted XSDT */ + + table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof (u64)) + + sizeof (struct acpi_table_header); + + /* Allocate an XSDT */ + + new_table = ACPI_MEM_CALLOCATE (table_size); + if (!new_table) { + return (AE_NO_MEMORY); + } + + /* Copy the header and set the length */ + + ACPI_MEMCPY (new_table, table_info->pointer, sizeof (struct acpi_table_header)); + new_table->length = (u32) table_size; + + /* Copy the table pointers */ + + for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { + if (acpi_gbl_RSDP->revision < 2) { + ACPI_STORE_ADDRESS (new_table->table_offset_entry[i], + (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, table_info->pointer))->table_offset_entry[i]); + } + else { + new_table->table_offset_entry[i] = + (ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info->pointer))->table_offset_entry[i]; + } + } + + /* Delete the original table (either mapped or in a buffer) */ + + acpi_tb_delete_single_table (table_info); + + /* Point the table descriptor to the new table */ + + table_info->pointer = ACPI_CAST_PTR (struct acpi_table_header, new_table); + table_info->length = table_size; + table_info->allocation = ACPI_MEM_ALLOCATED; + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: acpi_tb_init_generic_address + * + * PARAMETERS: new_gas_struct - GAS struct to be initialized + * register_bit_width - Width of this register + * Address - Address of the register + * + * RETURN: None + * + * DESCRIPTION: Initialize a GAS structure. + * + ******************************************************************************/ + +static void +acpi_tb_init_generic_address ( + struct acpi_generic_address *new_gas_struct, + u8 register_bit_width, + acpi_physical_address address) +{ + + ACPI_STORE_ADDRESS (new_gas_struct->address, address); + + new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO; + new_gas_struct->register_bit_width = register_bit_width; + new_gas_struct->register_bit_offset = 0; + new_gas_struct->access_width = 0; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_convert_fadt1 + * + * PARAMETERS: local_fadt - Pointer to new FADT + * original_fadt - Pointer to old FADT + * + * RETURN: Populates local_fadt + * + * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format + * + ******************************************************************************/ + +static void +acpi_tb_convert_fadt1 ( + struct fadt_descriptor_rev2 *local_fadt, + struct fadt_descriptor_rev1 *original_fadt) +{ + + + /* ACPI 1.0 FACS */ + /* The BIOS stored FADT should agree with Revision 1.0 */ + acpi_fadt_is_v1 = 1; + + /* + * Copy the table header and the common part of the tables. + * + * The 2.0 table is an extension of the 1.0 table, so the entire 1.0 + * table can be copied first, then expand some fields to 64 bits. + */ + ACPI_MEMCPY (local_fadt, original_fadt, sizeof (struct fadt_descriptor_rev1)); + + /* Convert table pointers to 64-bit fields */ + + ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl); + ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); + + /* + * System Interrupt Model isn't used in ACPI 2.0 (local_fadt->Reserved1 = 0;) + */ + + /* + * This field is set by the OEM to convey the preferred power management + * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't + * know what kind of 32-bit system this is, we will use "unspecified". + */ + local_fadt->prefer_PM_profile = PM_UNSPECIFIED; + + /* + * Processor Performance State Control. This is the value OSPM writes to + * the SMI_CMD register to assume processor performance state control + * responsibility. There isn't any equivalence in 1.0, but as many 1.x + * ACPI tables contain _PCT and _PSS we also keep this value, unless + * acpi_strict is set. + */ + if (acpi_strict) + local_fadt->pstate_cnt = 0; + + /* + * Support for the _CST object and C States change notification. + * This data item hasn't any 1.0 equivalence so leave it zero. + */ + local_fadt->cst_cnt = 0; + + /* + * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0. + * It primarily adds the FADT reset mechanism. + */ + if ((original_fadt->revision == 2) && + (original_fadt->length == sizeof (struct fadt_descriptor_rev2_minus))) { + /* + * Grab the entire generic address struct, plus the 1-byte reset value + * that immediately follows. + */ + ACPI_MEMCPY (&local_fadt->reset_register, + &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, original_fadt))->reset_register, + sizeof (struct acpi_generic_address) + 1); + } + else { + /* + * Since there isn't any equivalence in 1.0 and since it is highly + * likely that a 1.0 system has legacy support. + */ + local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES; + } + + /* + * Convert the V1.0 block addresses to V2.0 GAS structures + */ + acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk, local_fadt->pm1_evt_len, + (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); + acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk, local_fadt->pm1_evt_len, + (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); + acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk, local_fadt->pm1_cnt_len, + (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); + acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk, local_fadt->pm1_cnt_len, + (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); + acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk, local_fadt->pm2_cnt_len, + (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); + acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk, local_fadt->pm_tm_len, + (acpi_physical_address) local_fadt->V1_pm_tmr_blk); + acpi_tb_init_generic_address (&local_fadt->xgpe0_blk, 0, + (acpi_physical_address) local_fadt->V1_gpe0_blk); + acpi_tb_init_generic_address (&local_fadt->xgpe1_blk, 0, + (acpi_physical_address) local_fadt->V1_gpe1_blk); + + /* Create separate GAS structs for the PM1 Enable registers */ + + acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + + /* PM1B is optional; leave null if not present */ + + if (local_fadt->xpm1b_evt_blk.address) { + acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_convert_fadt2 + * + * PARAMETERS: local_fadt - Pointer to new FADT + * original_fadt - Pointer to old FADT + * + * RETURN: Populates local_fadt + * + * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format. + * Handles optional "X" fields. + * + ******************************************************************************/ + +static void +acpi_tb_convert_fadt2 ( + struct fadt_descriptor_rev2 *local_fadt, + struct fadt_descriptor_rev2 *original_fadt) +{ + + /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */ + + ACPI_MEMCPY (local_fadt, original_fadt, sizeof (struct fadt_descriptor_rev2)); + + /* + * "X" fields are optional extensions to the original V1.0 fields, so + * we must selectively expand V1.0 fields if the corresponding X field + * is zero. + */ + if (!(local_fadt->xfirmware_ctrl)) { + ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl); + } + + if (!(local_fadt->Xdsdt)) { + ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); + } + + if (!(local_fadt->xpm1a_evt_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk, + local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); + } + + if (!(local_fadt->xpm1b_evt_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk, + local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); + } + + if (!(local_fadt->xpm1a_cnt_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk, + local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); + } + + if (!(local_fadt->xpm1b_cnt_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk, + local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); + } + + if (!(local_fadt->xpm2_cnt_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk, + local_fadt->pm2_cnt_len, (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); + } + + if (!(local_fadt->xpm_tmr_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk, + local_fadt->pm_tm_len, (acpi_physical_address) local_fadt->V1_pm_tmr_blk); + } + + if (!(local_fadt->xgpe0_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xgpe0_blk, + 0, (acpi_physical_address) local_fadt->V1_gpe0_blk); + } + + if (!(local_fadt->xgpe1_blk.address)) { + acpi_tb_init_generic_address (&local_fadt->xgpe1_blk, + 0, (acpi_physical_address) local_fadt->V1_gpe1_blk); + } + + /* Create separate GAS structs for the PM1 Enable registers */ + + acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + acpi_gbl_xpm1a_enable.address_space_id = local_fadt->xpm1a_evt_blk.address_space_id; + + /* PM1B is optional; leave null if not present */ + + if (local_fadt->xpm1b_evt_blk.address) { + acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id; + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_convert_table_fadt + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local + * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply + * copied to the local FADT. The ACPI CA software uses this + * local FADT. Thus a significant amount of special #ifdef + * type codeing is saved. + * + ******************************************************************************/ + +acpi_status +acpi_tb_convert_table_fadt (void) +{ + struct fadt_descriptor_rev2 *local_fadt; + struct acpi_table_desc *table_desc; + + + ACPI_FUNCTION_TRACE ("tb_convert_table_fadt"); + + + /* + * acpi_gbl_FADT is valid. Validate the FADT length. The table must be + * at least as long as the version 1.0 FADT + */ + if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev1)) { + ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", acpi_gbl_FADT->length)); + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); + } + + /* Allocate buffer for the ACPI 2.0(+) FADT */ + + local_fadt = ACPI_MEM_CALLOCATE (sizeof (struct fadt_descriptor_rev2)); + if (!local_fadt) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) { + if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev2)) { + /* Length is too short to be a V2.0 table */ + + ACPI_REPORT_WARNING (("Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n", + acpi_gbl_FADT->length, acpi_gbl_FADT->revision)); + + acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); + } + else { + /* Valid V2.0 table */ + + acpi_tb_convert_fadt2 (local_fadt, acpi_gbl_FADT); + } + } + else { + /* Valid V1.0 table */ + + acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); + } + + /* + * Global FADT pointer will point to the new common V2.0 FADT + */ + acpi_gbl_FADT = local_fadt; + acpi_gbl_FADT->length = sizeof (FADT_DESCRIPTOR); + + /* Free the original table */ + + table_desc = acpi_gbl_table_lists[ACPI_TABLE_FADT].next; + acpi_tb_delete_single_table (table_desc); + + /* Install the new table */ + + table_desc->pointer = ACPI_CAST_PTR (struct acpi_table_header, acpi_gbl_FADT); + table_desc->allocation = ACPI_MEM_ALLOCATED; + table_desc->length = sizeof (struct fadt_descriptor_rev2); + + /* Dump the entire FADT */ + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, + "Hex dump of common internal FADT, size %d (%X)\n", + acpi_gbl_FADT->length, acpi_gbl_FADT->length)); + ACPI_DUMP_BUFFER ((u8 *) (acpi_gbl_FADT), acpi_gbl_FADT->length); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_convert_table_facs + * + * PARAMETERS: table_info - Info for currently installed FACS + * + * RETURN: Status + * + * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal + * table format. + * + ******************************************************************************/ + +acpi_status +acpi_tb_build_common_facs ( + struct acpi_table_desc *table_info) +{ + + ACPI_FUNCTION_TRACE ("tb_build_common_facs"); + + + /* Absolute minimum length is 24, but the ACPI spec says 64 */ + + if (acpi_gbl_FACS->length < 24) { + ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", acpi_gbl_FACS->length)); + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); + } + + if (acpi_gbl_FACS->length < 64) { + ACPI_REPORT_WARNING (("FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n", + acpi_gbl_FACS->length)); + } + + /* Copy fields to the new FACS */ + + acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock); + + if ((acpi_gbl_RSDP->revision < 2) || + (acpi_gbl_FACS->length < 32) || + (!(acpi_gbl_FACS->xfirmware_waking_vector))) { + /* ACPI 1.0 FACS or short table or optional X_ field is zero */ + + acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, &(acpi_gbl_FACS->firmware_waking_vector)); + acpi_gbl_common_fACS.vector_width = 32; + } + else { + /* ACPI 2.0 FACS with valid X_ field */ + + acpi_gbl_common_fACS.firmware_waking_vector = &acpi_gbl_FACS->xfirmware_waking_vector; + acpi_gbl_common_fACS.vector_width = 64; + } + + return_ACPI_STATUS (AE_OK); +} + + diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c new file mode 100644 index 00000000000..896f3ddda62 --- /dev/null +++ b/drivers/acpi/tables/tbget.c @@ -0,0 +1,493 @@ +/****************************************************************************** + * + * Module Name: tbget - ACPI Table get* routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <acpi/acpi.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbget") + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_table + * + * PARAMETERS: Address - Address of table to retrieve. Can be + * Logical or Physical + * table_info - Where table info is returned + * + * RETURN: None + * + * DESCRIPTION: Get entire table of unknown size. + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_table ( + struct acpi_pointer *address, + struct acpi_table_desc *table_info) +{ + acpi_status status; + struct acpi_table_header header; + + + ACPI_FUNCTION_TRACE ("tb_get_table"); + + + /* + * Get the header in order to get signature and table size + */ + status = acpi_tb_get_table_header (address, &header); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the entire table */ + + status = acpi_tb_get_table_body (address, &header, table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not get ACPI table (size %X), %s\n", + header.length, acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_table_header + * + * PARAMETERS: Address - Address of table to retrieve. Can be + * Logical or Physical + * return_header - Where the table header is returned + * + * RETURN: Status + * + * DESCRIPTION: Get an ACPI table header. Works in both physical or virtual + * addressing mode. Works with both physical or logical pointers. + * Table is either copied or mapped, depending on the pointer + * type and mode of the processor. + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_table_header ( + struct acpi_pointer *address, + struct acpi_table_header *return_header) +{ + acpi_status status = AE_OK; + struct acpi_table_header *header = NULL; + + + ACPI_FUNCTION_TRACE ("tb_get_table_header"); + + + /* + * Flags contains the current processor mode (Virtual or Physical addressing) + * The pointer_type is either Logical or Physical + */ + switch (address->pointer_type) { + case ACPI_PHYSMODE_PHYSPTR: + case ACPI_LOGMODE_LOGPTR: + + /* Pointer matches processor mode, copy the header */ + + ACPI_MEMCPY (return_header, address->pointer.logical, sizeof (struct acpi_table_header)); + break; + + + case ACPI_LOGMODE_PHYSPTR: + + /* Create a logical address for the physical pointer*/ + + status = acpi_os_map_memory (address->pointer.physical, sizeof (struct acpi_table_header), + (void *) &header); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n", + ACPI_FORMAT_UINT64 (address->pointer.physical), + sizeof (struct acpi_table_header))); + return_ACPI_STATUS (status); + } + + /* Copy header and delete mapping */ + + ACPI_MEMCPY (return_header, header, sizeof (struct acpi_table_header)); + acpi_os_unmap_memory (header, sizeof (struct acpi_table_header)); + break; + + + default: + + ACPI_REPORT_ERROR (("Invalid address flags %X\n", + address->pointer_type)); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n", + return_header->signature)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_table_body + * + * PARAMETERS: Address - Address of table to retrieve. Can be + * Logical or Physical + * Header - Header of the table to retrieve + * table_info - Where the table info is returned + * + * RETURN: Status + * + * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to + * replace the table with a newer version (table override.) + * Works in both physical or virtual + * addressing mode. Works with both physical or logical pointers. + * Table is either copied or mapped, depending on the pointer + * type and mode of the processor. + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_table_body ( + struct acpi_pointer *address, + struct acpi_table_header *header, + struct acpi_table_desc *table_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("tb_get_table_body"); + + + if (!table_info || !address) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Attempt table override. + */ + status = acpi_tb_table_override (header, table_info); + if (ACPI_SUCCESS (status)) { + /* Table was overridden by the host OS */ + + return_ACPI_STATUS (status); + } + + /* No override, get the original table */ + + status = acpi_tb_get_this_table (address, header, table_info); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_table_override + * + * PARAMETERS: Header - Pointer to table header + * table_info - Return info if table is overridden + * + * RETURN: None + * + * DESCRIPTION: Attempts override of current table with a new one if provided + * by the host OS. + * + ******************************************************************************/ + +acpi_status +acpi_tb_table_override ( + struct acpi_table_header *header, + struct acpi_table_desc *table_info) +{ + struct acpi_table_header *new_table; + acpi_status status; + struct acpi_pointer address; + + + ACPI_FUNCTION_TRACE ("tb_table_override"); + + + /* + * The OSL will examine the header and decide whether to override this + * table. If it decides to override, a table will be returned in new_table, + * which we will then copy. + */ + status = acpi_os_table_override (header, &new_table); + if (ACPI_FAILURE (status)) { + /* Some severe error from the OSL, but we basically ignore it */ + + ACPI_REPORT_ERROR (("Could not override ACPI table, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + if (!new_table) { + /* No table override */ + + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* + * We have a new table to override the old one. Get a copy of + * the new one. We know that the new table has a logical pointer. + */ + address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING; + address.pointer.logical = new_table; + + status = acpi_tb_get_this_table (&address, new_table, table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not copy override ACPI table, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + /* Copy the table info */ + + ACPI_REPORT_INFO (("Table [%4.4s] replaced by host OS\n", + table_info->pointer->signature)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_this_table + * + * PARAMETERS: Address - Address of table to retrieve. Can be + * Logical or Physical + * Header - Header of the table to retrieve + * table_info - Where the table info is returned + * + * RETURN: Status + * + * DESCRIPTION: Get an entire ACPI table. Works in both physical or virtual + * addressing mode. Works with both physical or logical pointers. + * Table is either copied or mapped, depending on the pointer + * type and mode of the processor. + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_this_table ( + struct acpi_pointer *address, + struct acpi_table_header *header, + struct acpi_table_desc *table_info) +{ + struct acpi_table_header *full_table = NULL; + u8 allocation; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("tb_get_this_table"); + + + /* + * Flags contains the current processor mode (Virtual or Physical addressing) + * The pointer_type is either Logical or Physical + */ + switch (address->pointer_type) { + case ACPI_PHYSMODE_PHYSPTR: + case ACPI_LOGMODE_LOGPTR: + + /* Pointer matches processor mode, copy the table to a new buffer */ + + full_table = ACPI_MEM_ALLOCATE (header->length); + if (!full_table) { + ACPI_REPORT_ERROR (("Could not allocate table memory for [%4.4s] length %X\n", + header->signature, header->length)); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the entire table (including header) to the local buffer */ + + ACPI_MEMCPY (full_table, address->pointer.logical, header->length); + + /* Save allocation type */ + + allocation = ACPI_MEM_ALLOCATED; + break; + + + case ACPI_LOGMODE_PHYSPTR: + + /* + * Just map the table's physical memory + * into our address space. + */ + status = acpi_os_map_memory (address->pointer.physical, (acpi_size) header->length, + (void *) &full_table); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", + header->signature, + ACPI_FORMAT_UINT64 (address->pointer.physical), header->length)); + return (status); + } + + /* Save allocation type */ + + allocation = ACPI_MEM_MAPPED; + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid address flags %X\n", + address->pointer_type)); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Validate checksum for _most_ tables, + * even the ones whose signature we don't recognize + */ + if (table_info->type != ACPI_TABLE_FACS) { + status = acpi_tb_verify_table_checksum (full_table); + +#if (!ACPI_CHECKSUM_ABORT) + if (ACPI_FAILURE (status)) { + /* Ignore the error if configuration says so */ + + status = AE_OK; + } +#endif + } + + /* Return values */ + + table_info->pointer = full_table; + table_info->length = (acpi_size) header->length; + table_info->allocation = allocation; + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n", + full_table->signature, + ACPI_FORMAT_UINT64 (address->pointer.physical), full_table)); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_table_ptr + * + * PARAMETERS: table_type - one of the defined table types + * Instance - Which table of this type + * table_ptr_loc - pointer to location to place the pointer for + * return + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the pointer to an ACPI table. + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_table_ptr ( + acpi_table_type table_type, + u32 instance, + struct acpi_table_header **table_ptr_loc) +{ + struct acpi_table_desc *table_desc; + u32 i; + + + ACPI_FUNCTION_TRACE ("tb_get_table_ptr"); + + + if (!acpi_gbl_DSDT) { + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + if (table_type > ACPI_TABLE_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * For all table types (Single/Multiple), the first + * instance is always in the list head. + */ + if (instance == 1) { + /* Get the first */ + + *table_ptr_loc = NULL; + if (acpi_gbl_table_lists[table_type].next) { + *table_ptr_loc = acpi_gbl_table_lists[table_type].next->pointer; + } + return_ACPI_STATUS (AE_OK); + } + + /* + * Check for instance out of range + */ + if (instance > acpi_gbl_table_lists[table_type].count) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Walk the list to get the desired table + * Since the if (Instance == 1) check above checked for the + * first table, setting table_desc equal to the .Next member + * is actually pointing to the second table. Therefore, we + * need to walk from the 2nd table until we reach the Instance + * that the user is looking for and return its table pointer. + */ + table_desc = acpi_gbl_table_lists[table_type].next; + for (i = 2; i < instance; i++) { + table_desc = table_desc->next; + } + + /* We are now pointing to the requested table's descriptor */ + + *table_ptr_loc = table_desc->pointer; + + return_ACPI_STATUS (AE_OK); +} + diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c new file mode 100644 index 00000000000..adc4270988b --- /dev/null +++ b/drivers/acpi/tables/tbgetall.c @@ -0,0 +1,313 @@ +/****************************************************************************** + * + * Module Name: tbgetall - Get all required ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <acpi/acpi.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbgetall") + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_primary_table + * + * PARAMETERS: Address - Physical address of table to retrieve + * *table_info - Where the table info is returned + * + * RETURN: Status + * + * DESCRIPTION: Maps the physical address of table into a logical address + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_primary_table ( + struct acpi_pointer *address, + struct acpi_table_desc *table_info) +{ + acpi_status status; + struct acpi_table_header header; + + + ACPI_FUNCTION_TRACE ("tb_get_primary_table"); + + + /* Ignore a NULL address in the RSDT */ + + if (!address->pointer.value) { + return_ACPI_STATUS (AE_OK); + } + + /* + * Get the header in order to get signature and table size + */ + status = acpi_tb_get_table_header (address, &header); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Clear the table_info */ + + ACPI_MEMSET (table_info, 0, sizeof (struct acpi_table_desc)); + + /* + * Check the table signature and make sure it is recognized. + * Also checks the header checksum + */ + table_info->pointer = &header; + status = acpi_tb_recognize_table (table_info, ACPI_TABLE_PRIMARY); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the entire table */ + + status = acpi_tb_get_table_body (address, &header, table_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Install the table */ + + status = acpi_tb_install_table (table_info); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_secondary_table + * + * PARAMETERS: Address - Physical address of table to retrieve + * *table_info - Where the table info is returned + * + * RETURN: Status + * + * DESCRIPTION: Maps the physical address of table into a logical address + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_secondary_table ( + struct acpi_pointer *address, + acpi_string signature, + struct acpi_table_desc *table_info) +{ + acpi_status status; + struct acpi_table_header header; + + + ACPI_FUNCTION_TRACE_STR ("tb_get_secondary_table", signature); + + + /* Get the header in order to match the signature */ + + status = acpi_tb_get_table_header (address, &header); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Signature must match request */ + + if (ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) { + ACPI_REPORT_ERROR (("Incorrect table signature - wanted [%s] found [%4.4s]\n", + signature, header.signature)); + return_ACPI_STATUS (AE_BAD_SIGNATURE); + } + + /* + * Check the table signature and make sure it is recognized. + * Also checks the header checksum + */ + table_info->pointer = &header; + status = acpi_tb_recognize_table (table_info, ACPI_TABLE_SECONDARY); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the entire table */ + + status = acpi_tb_get_table_body (address, &header, table_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Install the table */ + + status = acpi_tb_install_table (table_info); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_required_tables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must + * already be loaded and validated. + * + * Get the minimum set of ACPI tables, namely: + * + * 1) FADT (via RSDT in loop below) + * 2) FACS (via FADT) + * 3) DSDT (via FADT) + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_required_tables ( + void) +{ + acpi_status status = AE_OK; + u32 i; + struct acpi_table_desc table_info; + struct acpi_pointer address; + + + ACPI_FUNCTION_TRACE ("tb_get_required_tables"); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%d ACPI tables in RSDT\n", + acpi_gbl_rsdt_table_count)); + + + address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING; + + /* + * Loop through all table pointers found in RSDT. + * This will NOT include the FACS and DSDT - we must get + * them after the loop. + * + * The only tables we are interested in getting here is the FADT and + * any SSDTs. + */ + for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { + /* Get the table address from the common internal XSDT */ + + address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i]; + + /* + * Get the tables needed by this subsystem (FADT and any SSDTs). + * NOTE: All other tables are completely ignored at this time. + */ + status = acpi_tb_get_primary_table (&address, &table_info); + if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) { + ACPI_REPORT_WARNING (("%s, while getting table at %8.8X%8.8X\n", + acpi_format_exception (status), + ACPI_FORMAT_UINT64 (address.pointer.value))); + } + } + + /* We must have a FADT to continue */ + + if (!acpi_gbl_FADT) { + ACPI_REPORT_ERROR (("No FADT present in RSDT/XSDT\n")); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* + * Convert the FADT to a common format. This allows earlier revisions of the + * table to coexist with newer versions, using common access code. + */ + status = acpi_tb_convert_table_fadt (); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n")); + return_ACPI_STATUS (status); + } + + /* + * Get the FACS (Pointed to by the FADT) + */ + address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl; + + status = acpi_tb_get_secondary_table (&address, FACS_SIG, &table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not get/install the FACS, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + /* + * Create the common FACS pointer table + * (Contains pointers to the original table) + */ + status = acpi_tb_build_common_facs (&table_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Get/install the DSDT (Pointed to by the FADT) + */ + address.pointer.value = acpi_gbl_FADT->Xdsdt; + + status = acpi_tb_get_secondary_table (&address, DSDT_SIG, &table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not get/install the DSDT\n")); + return_ACPI_STATUS (status); + } + + /* Set Integer Width (32/64) based upon DSDT revision */ + + acpi_ut_set_integer_width (acpi_gbl_DSDT->revision); + + /* Dump the entire DSDT */ + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, + "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n", + acpi_gbl_DSDT->length, acpi_gbl_DSDT->length, acpi_gbl_integer_bit_width)); + ACPI_DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, acpi_gbl_DSDT->length); + + /* Always delete the RSDP mapping, we are done with it */ + + acpi_tb_delete_tables_by_type (ACPI_TABLE_RSDP); + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c new file mode 100644 index 00000000000..85d5bb01022 --- /dev/null +++ b/drivers/acpi/tables/tbinstal.c @@ -0,0 +1,553 @@ +/****************************************************************************** + * + * Module Name: tbinstal - ACPI table installation and removal + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <acpi/acpi.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbinstal") + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_match_signature + * + * PARAMETERS: Signature - Table signature to match + * table_info - Return data + * + * RETURN: Status + * + * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned" + * tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match. + * + ******************************************************************************/ + +acpi_status +acpi_tb_match_signature ( + char *signature, + struct acpi_table_desc *table_info, + u8 search_type) +{ + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("tb_match_signature"); + + + /* + * Search for a signature match among the known table types + */ + for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) { + if (!(acpi_gbl_table_data[i].flags & search_type)) { + continue; + } + + if (!ACPI_STRNCMP (signature, acpi_gbl_table_data[i].signature, + acpi_gbl_table_data[i].sig_length)) { + /* Found a signature match, return index if requested */ + + if (table_info) { + table_info->type = (u8) i; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Table [%4.4s] is an ACPI table consumed by the core subsystem\n", + (char *) acpi_gbl_table_data[i].signature)); + + return_ACPI_STATUS (AE_OK); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n", + (char *) signature)); + + return_ACPI_STATUS (AE_TABLE_NOT_SUPPORTED); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_install_table + * + * PARAMETERS: table_info - Return value from acpi_tb_get_table_body + * + * RETURN: Status + * + * DESCRIPTION: Load and validate all tables other than the RSDT. The RSDT must + * already be loaded and validated. + * Install the table into the global data structs. + * + ******************************************************************************/ + +acpi_status +acpi_tb_install_table ( + struct acpi_table_desc *table_info) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE ("tb_install_table"); + + + /* Lock tables while installing */ + + status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not acquire table mutex for [%4.4s], %s\n", + table_info->pointer->signature, acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + /* Install the table into the global data structure */ + + status = acpi_tb_init_table_descriptor (table_info->type, table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not install ACPI table [%4.4s], %s\n", + table_info->pointer->signature, acpi_format_exception (status))); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s located at %p\n", + acpi_gbl_table_data[table_info->type].name, table_info->pointer)); + + (void) acpi_ut_release_mutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_recognize_table + * + * PARAMETERS: table_info - Return value from acpi_tb_get_table_body + * + * RETURN: Status + * + * DESCRIPTION: Check a table signature for a match against known table types + * + * NOTE: All table pointers are validated as follows: + * 1) Table pointer must point to valid physical memory + * 2) Signature must be 4 ASCII chars, even if we don't recognize the + * name + * 3) Table must be readable for length specified in the header + * 4) Table checksum must be valid (with the exception of the FACS + * which has no checksum for some odd reason) + * + ******************************************************************************/ + +acpi_status +acpi_tb_recognize_table ( + struct acpi_table_desc *table_info, + u8 search_type) +{ + struct acpi_table_header *table_header; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("tb_recognize_table"); + + + /* Ensure that we have a valid table pointer */ + + table_header = (struct acpi_table_header *) table_info->pointer; + if (!table_header) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * We only "recognize" a limited number of ACPI tables -- namely, the + * ones that are used by the subsystem (DSDT, FADT, etc.) + * + * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized. + * This can be any one of many valid ACPI tables, it just isn't one of + * the tables that is consumed by the core subsystem + */ + status = acpi_tb_match_signature (table_header->signature, table_info, search_type); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_tb_validate_table_header (table_header); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Return the table type and length via the info struct */ + + table_info->length = (acpi_size) table_header->length; + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_init_table_descriptor + * + * PARAMETERS: table_type - The type of the table + * table_info - A table info struct + * + * RETURN: None. + * + * DESCRIPTION: Install a table into the global data structs. + * + ******************************************************************************/ + +acpi_status +acpi_tb_init_table_descriptor ( + acpi_table_type table_type, + struct acpi_table_desc *table_info) +{ + struct acpi_table_list *list_head; + struct acpi_table_desc *table_desc; + + + ACPI_FUNCTION_TRACE_U32 ("tb_init_table_descriptor", table_type); + + + /* Allocate a descriptor for this table */ + + table_desc = ACPI_MEM_CALLOCATE (sizeof (struct acpi_table_desc)); + if (!table_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Install the table into the global data structure + */ + list_head = &acpi_gbl_table_lists[table_type]; + + /* + * Two major types of tables: 1) Only one instance is allowed. This + * includes most ACPI tables such as the DSDT. 2) Multiple instances of + * the table are allowed. This includes SSDT and PSDTs. + */ + if (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags)) { + /* + * Only one table allowed, and a table has alread been installed + * at this location, so return an error. + */ + if (list_head->next) { + ACPI_MEM_FREE (table_desc); + return_ACPI_STATUS (AE_ALREADY_EXISTS); + } + + table_desc->next = list_head->next; + list_head->next = table_desc; + + if (table_desc->next) { + table_desc->next->prev = table_desc; + } + + list_head->count++; + } + else { + /* + * Link the new table in to the list of tables of this type. + * Insert at the end of the list, order IS IMPORTANT. + * + * table_desc->Prev & Next are already NULL from calloc() + */ + list_head->count++; + + if (!list_head->next) { + list_head->next = table_desc; + } + else { + table_desc->next = list_head->next; + + while (table_desc->next->next) { + table_desc->next = table_desc->next->next; + } + + table_desc->next->next = table_desc; + table_desc->prev = table_desc->next; + table_desc->next = NULL; + } + } + + /* Finish initialization of the table descriptor */ + + table_desc->type = (u8) table_type; + table_desc->pointer = table_info->pointer; + table_desc->length = table_info->length; + table_desc->allocation = table_info->allocation; + table_desc->aml_start = (u8 *) (table_desc->pointer + 1), + table_desc->aml_length = (u32) (table_desc->length - + (u32) sizeof (struct acpi_table_header)); + table_desc->table_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_TABLE); + table_desc->loaded_into_namespace = FALSE; + + /* + * Set the appropriate global pointer (if there is one) to point to the + * newly installed table + */ + if (acpi_gbl_table_data[table_type].global_ptr) { + *(acpi_gbl_table_data[table_type].global_ptr) = table_info->pointer; + } + + /* Return Data */ + + table_info->table_id = table_desc->table_id; + table_info->installed_desc = table_desc; + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_delete_all_tables + * + * PARAMETERS: None. + * + * RETURN: None. + * + * DESCRIPTION: Delete all internal ACPI tables + * + ******************************************************************************/ + +void +acpi_tb_delete_all_tables (void) +{ + acpi_table_type type; + + + /* + * Free memory allocated for ACPI tables + * Memory can either be mapped or allocated + */ + for (type = 0; type < NUM_ACPI_TABLE_TYPES; type++) { + acpi_tb_delete_tables_by_type (type); + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_delete_tables_by_type + * + * PARAMETERS: Type - The table type to be deleted + * + * RETURN: None. + * + * DESCRIPTION: Delete an internal ACPI table + * Locks the ACPI table mutex + * + ******************************************************************************/ + +void +acpi_tb_delete_tables_by_type ( + acpi_table_type type) +{ + struct acpi_table_desc *table_desc; + u32 count; + u32 i; + + + ACPI_FUNCTION_TRACE_U32 ("tb_delete_tables_by_type", type); + + + if (type > ACPI_TABLE_MAX) { + return_VOID; + } + + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_TABLES))) { + return; + } + + /* Clear the appropriate "typed" global table pointer */ + + switch (type) { + case ACPI_TABLE_RSDP: + acpi_gbl_RSDP = NULL; + break; + + case ACPI_TABLE_DSDT: + acpi_gbl_DSDT = NULL; + break; + + case ACPI_TABLE_FADT: + acpi_gbl_FADT = NULL; + break; + + case ACPI_TABLE_FACS: + acpi_gbl_FACS = NULL; + break; + + case ACPI_TABLE_XSDT: + acpi_gbl_XSDT = NULL; + break; + + case ACPI_TABLE_SSDT: + case ACPI_TABLE_PSDT: + default: + break; + } + + /* + * Free the table + * 1) Get the head of the list + */ + table_desc = acpi_gbl_table_lists[type].next; + count = acpi_gbl_table_lists[type].count; + + /* + * 2) Walk the entire list, deleting both the allocated tables + * and the table descriptors + */ + for (i = 0; i < count; i++) { + table_desc = acpi_tb_uninstall_table (table_desc); + } + + (void) acpi_ut_release_mutex (ACPI_MTX_TABLES); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_delete_single_table + * + * PARAMETERS: table_info - A table info struct + * + * RETURN: None. + * + * DESCRIPTION: Low-level free for a single ACPI table. Handles cases where + * the table was allocated a buffer or was mapped. + * + ******************************************************************************/ + +void +acpi_tb_delete_single_table ( + struct acpi_table_desc *table_desc) +{ + + /* Must have a valid table descriptor and pointer */ + + if ((!table_desc) || + (!table_desc->pointer)) { + return; + } + + /* Valid table, determine type of memory allocation */ + + switch (table_desc->allocation) { + case ACPI_MEM_NOT_ALLOCATED: + break; + + case ACPI_MEM_ALLOCATED: + + ACPI_MEM_FREE (table_desc->pointer); + break; + + case ACPI_MEM_MAPPED: + + acpi_os_unmap_memory (table_desc->pointer, table_desc->length); + break; + + default: + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_uninstall_table + * + * PARAMETERS: table_info - A table info struct + * + * RETURN: Pointer to the next table in the list (of same type) + * + * DESCRIPTION: Free the memory associated with an internal ACPI table that + * is either installed or has never been installed. + * Table mutex should be locked. + * + ******************************************************************************/ + +struct acpi_table_desc * +acpi_tb_uninstall_table ( + struct acpi_table_desc *table_desc) +{ + struct acpi_table_desc *next_desc; + + + ACPI_FUNCTION_TRACE_PTR ("tb_uninstall_table", table_desc); + + + if (!table_desc) { + return_PTR (NULL); + } + + /* Unlink the descriptor from the doubly linked list */ + + if (table_desc->prev) { + table_desc->prev->next = table_desc->next; + } + else { + /* Is first on list, update list head */ + + acpi_gbl_table_lists[table_desc->type].next = table_desc->next; + } + + if (table_desc->next) { + table_desc->next->prev = table_desc->prev; + } + + /* Free the memory allocated for the table itself */ + + acpi_tb_delete_single_table (table_desc); + + /* Free the table descriptor */ + + next_desc = table_desc->next; + ACPI_MEM_FREE (table_desc); + + /* Return pointer to the next descriptor */ + + return_PTR (next_desc); +} + + diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c new file mode 100644 index 00000000000..9c6913238d5 --- /dev/null +++ b/drivers/acpi/tables/tbrsdt.c @@ -0,0 +1,324 @@ +/****************************************************************************** + * + * Module Name: tbrsdt - ACPI RSDT table utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <acpi/acpi.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbrsdt") + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_verify_rsdp + * + * PARAMETERS: Address - RSDP (Pointer to RSDT) + * + * RETURN: Status + * + * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table) + * + ******************************************************************************/ + +acpi_status +acpi_tb_verify_rsdp ( + struct acpi_pointer *address) +{ + struct acpi_table_desc table_info; + acpi_status status; + struct rsdp_descriptor *rsdp; + + + ACPI_FUNCTION_TRACE ("tb_verify_rsdp"); + + + switch (address->pointer_type) { + case ACPI_LOGICAL_POINTER: + + rsdp = address->pointer.logical; + break; + + case ACPI_PHYSICAL_POINTER: + /* + * Obtain access to the RSDP structure + */ + status = acpi_os_map_memory (address->pointer.physical, sizeof (struct rsdp_descriptor), + (void *) &rsdp); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * The signature and checksum must both be correct + */ + if (ACPI_STRNCMP ((char *) rsdp, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + /* Nope, BAD Signature */ + + status = AE_BAD_SIGNATURE; + goto cleanup; + } + + /* Check the standard checksum */ + + if (acpi_tb_checksum (rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { + status = AE_BAD_CHECKSUM; + goto cleanup; + } + + /* Check extended checksum if table version >= 2 */ + + if (rsdp->revision >= 2) { + if (acpi_tb_checksum (rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) { + status = AE_BAD_CHECKSUM; + goto cleanup; + } + } + + /* The RSDP supplied is OK */ + + table_info.pointer = ACPI_CAST_PTR (struct acpi_table_header, rsdp); + table_info.length = sizeof (struct rsdp_descriptor); + table_info.allocation = ACPI_MEM_MAPPED; + + /* Save the table pointers and allocation info */ + + status = acpi_tb_init_table_descriptor (ACPI_TABLE_RSDP, &table_info); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Save the RSDP in a global for easy access */ + + acpi_gbl_RSDP = ACPI_CAST_PTR (struct rsdp_descriptor, table_info.pointer); + return_ACPI_STATUS (status); + + + /* Error exit */ +cleanup: + + if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) { + acpi_os_unmap_memory (rsdp, sizeof (struct rsdp_descriptor)); + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_rsdt_address + * + * PARAMETERS: None + * + * RETURN: RSDT physical address + * + * DESCRIPTION: Extract the address of the RSDT or XSDT, depending on the + * version of the RSDP + * + ******************************************************************************/ + +void +acpi_tb_get_rsdt_address ( + struct acpi_pointer *out_address) +{ + + ACPI_FUNCTION_ENTRY (); + + + out_address->pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING; + + /* + * For RSDP revision 0 or 1, we use the RSDT. + * For RSDP revision 2 (and above), we use the XSDT + */ + if (acpi_gbl_RSDP->revision < 2) { + out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address; + } + else { + out_address->pointer.value = acpi_gbl_RSDP->xsdt_physical_address; + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_validate_rsdt + * + * PARAMETERS: table_ptr - Addressable pointer to the RSDT. + * + * RETURN: Status + * + * DESCRIPTION: Validate signature for the RSDT or XSDT + * + ******************************************************************************/ + +acpi_status +acpi_tb_validate_rsdt ( + struct acpi_table_header *table_ptr) +{ + int no_match; + + + ACPI_FUNCTION_NAME ("tb_validate_rsdt"); + + + /* + * For RSDP revision 0 or 1, we use the RSDT. + * For RSDP revision 2 and above, we use the XSDT + */ + if (acpi_gbl_RSDP->revision < 2) { + no_match = ACPI_STRNCMP ((char *) table_ptr, RSDT_SIG, + sizeof (RSDT_SIG) -1); + } + else { + no_match = ACPI_STRNCMP ((char *) table_ptr, XSDT_SIG, + sizeof (XSDT_SIG) -1); + } + + if (no_match) { + /* Invalid RSDT or XSDT signature */ + + ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n")); + + ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20); + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, + "RSDT/XSDT signature at %X (%p) is invalid\n", + acpi_gbl_RSDP->rsdt_physical_address, + (void *) (acpi_native_uint) acpi_gbl_RSDP->rsdt_physical_address)); + + if (acpi_gbl_RSDP->revision < 2) { + ACPI_REPORT_ERROR (("Looking for RSDT (RSDP->Rev < 2)\n")) + } + else { + ACPI_REPORT_ERROR (("Looking for XSDT (RSDP->Rev >= 2)\n")) + } + + ACPI_DUMP_BUFFER ((char *) table_ptr, 48); + + return (AE_BAD_SIGNATURE); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_table_rsdt + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table) + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_table_rsdt ( + void) +{ + struct acpi_table_desc table_info; + acpi_status status; + struct acpi_pointer address; + + + ACPI_FUNCTION_TRACE ("tb_get_table_rsdt"); + + + /* Get the RSDT/XSDT via the RSDP */ + + acpi_tb_get_rsdt_address (&address); + + table_info.type = ACPI_TABLE_XSDT; + status = acpi_tb_get_table (&address, &table_info); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "RSDP located at %p, points to RSDT physical=%8.8X%8.8X \n", + acpi_gbl_RSDP, + ACPI_FORMAT_UINT64 (address.pointer.value))); + + /* Check the RSDT or XSDT signature */ + + status = acpi_tb_validate_rsdt (table_info.pointer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the number of tables defined in the RSDT or XSDT */ + + acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer); + + /* Convert and/or copy to an XSDT structure */ + + status = acpi_tb_convert_to_xsdt (&table_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Save the table pointers and allocation info */ + + status = acpi_tb_init_table_descriptor (ACPI_TABLE_XSDT, &table_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + acpi_gbl_XSDT = ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info.pointer); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c new file mode 100644 index 00000000000..fede5804c78 --- /dev/null +++ b/drivers/acpi/tables/tbutils.c @@ -0,0 +1,240 @@ +/****************************************************************************** + * + * Module Name: tbutils - Table manipulation utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <acpi/acpi.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbutils") + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_handle_to_object + * + * PARAMETERS: table_id - Id for which the function is searching + * table_desc - Pointer to return the matching table + * descriptor. + * + * RETURN: Search the tables to find one with a matching table_id and + * return a pointer to that table descriptor. + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +acpi_status +acpi_tb_handle_to_object ( + u16 table_id, + struct acpi_table_desc **return_table_desc) +{ + u32 i; + struct acpi_table_desc *table_desc; + + + ACPI_FUNCTION_NAME ("tb_handle_to_object"); + + + for (i = 0; i < ACPI_TABLE_MAX; i++) { + table_desc = acpi_gbl_table_lists[i].next; + while (table_desc) { + if (table_desc->table_id == table_id) { + *return_table_desc = table_desc; + return (AE_OK); + } + + table_desc = table_desc->next; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id)); + return (AE_BAD_PARAMETER); +} +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_validate_table_header + * + * PARAMETERS: table_header - Logical pointer to the table + * + * RETURN: Status + * + * DESCRIPTION: Check an ACPI table header for validity + * + * NOTE: Table pointers are validated as follows: + * 1) Table pointer must point to valid physical memory + * 2) Signature must be 4 ASCII chars, even if we don't recognize the + * name + * 3) Table must be readable for length specified in the header + * 4) Table checksum must be valid (with the exception of the FACS + * which has no checksum because it contains variable fields) + * + ******************************************************************************/ + +acpi_status +acpi_tb_validate_table_header ( + struct acpi_table_header *table_header) +{ + acpi_name signature; + + + ACPI_FUNCTION_NAME ("tb_validate_table_header"); + + + /* Verify that this is a valid address */ + + if (!acpi_os_readable (table_header, sizeof (struct acpi_table_header))) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Cannot read table header at %p\n", table_header)); + return (AE_BAD_ADDRESS); + } + + /* Ensure that the signature is 4 ASCII characters */ + + ACPI_MOVE_32_TO_32 (&signature, table_header->signature); + if (!acpi_ut_valid_acpi_name (signature)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Table signature at %p [%p] has invalid characters\n", + table_header, &signature)); + + ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n", + (char *) &signature)); + ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header)); + return (AE_BAD_SIGNATURE); + } + + /* Validate the table length */ + + if (table_header->length < sizeof (struct acpi_table_header)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid length in table header %p name %4.4s\n", + table_header, (char *) &signature)); + + ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n", + (u32) table_header->length)); + ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header)); + return (AE_BAD_HEADER); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_verify_table_checksum + * + * PARAMETERS: *table_header - ACPI table to verify + * + * RETURN: 8 bit checksum of table + * + * DESCRIPTION: Does an 8 bit checksum of table and returns status. A correct + * table should have a checksum of 0. + * + ******************************************************************************/ + +acpi_status +acpi_tb_verify_table_checksum ( + struct acpi_table_header *table_header) +{ + u8 checksum; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("tb_verify_table_checksum"); + + + /* Compute the checksum on the table */ + + checksum = acpi_tb_checksum (table_header, table_header->length); + + /* Return the appropriate exception */ + + if (checksum) { + ACPI_REPORT_WARNING (("Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n", + table_header->signature, (u32) table_header->checksum, (u32) checksum)); + + status = AE_BAD_CHECKSUM; + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_checksum + * + * PARAMETERS: Buffer - Buffer to checksum + * Length - Size of the buffer + * + * RETURNS 8 bit checksum of buffer + * + * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it. + * + ******************************************************************************/ + +u8 +acpi_tb_checksum ( + void *buffer, + u32 length) +{ + const u8 *limit; + const u8 *rover; + u8 sum = 0; + + + if (buffer && length) { + /* Buffer and Length are valid */ + + limit = (u8 *) buffer + length; + + for (rover = buffer; rover < limit; rover++) { + sum = (u8) (sum + *rover); + } + } + return (sum); +} + + diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c new file mode 100644 index 00000000000..7715043461c --- /dev/null +++ b/drivers/acpi/tables/tbxface.c @@ -0,0 +1,448 @@ +/****************************************************************************** + * + * Module Name: tbxface - Public interfaces to the ACPI subsystem + * ACPI table oriented interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbxface") + + +/******************************************************************************* + * + * FUNCTION: acpi_load_tables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: This function is called to load the ACPI tables from the + * provided RSDT + * + ******************************************************************************/ + +acpi_status +acpi_load_tables (void) +{ + struct acpi_pointer rsdp_address; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_load_tables"); + + + /* Get the RSDP */ + + status = acpi_os_get_root_pointer (ACPI_LOGICAL_ADDRESSING, + &rsdp_address); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("acpi_load_tables: Could not get RSDP, %s\n", + acpi_format_exception (status))); + goto error_exit; + } + + /* Map and validate the RSDP */ + + acpi_gbl_table_flags = rsdp_address.pointer_type; + + status = acpi_tb_verify_rsdp (&rsdp_address); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("acpi_load_tables: RSDP Failed validation: %s\n", + acpi_format_exception (status))); + goto error_exit; + } + + /* Get the RSDT via the RSDP */ + + status = acpi_tb_get_table_rsdt (); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("acpi_load_tables: Could not load RSDT: %s\n", + acpi_format_exception (status))); + goto error_exit; + } + + /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */ + + status = acpi_tb_get_required_tables (); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n", + acpi_format_exception (status))); + goto error_exit; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); + + + /* Load the namespace from the tables */ + + status = acpi_ns_load_namespace (); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("acpi_load_tables: Could not load namespace: %s\n", + acpi_format_exception (status))); + goto error_exit; + } + + return_ACPI_STATUS (AE_OK); + + +error_exit: + ACPI_REPORT_ERROR (("acpi_load_tables: Could not load tables: %s\n", + acpi_format_exception (status))); + + return_ACPI_STATUS (status); +} + + +#ifdef ACPI_FUTURE_USAGE + +/******************************************************************************* + * + * FUNCTION: acpi_load_table + * + * PARAMETERS: table_ptr - pointer to a buffer containing the entire + * table to be loaded + * + * RETURN: Status + * + * DESCRIPTION: This function is called to load a table from the caller's + * buffer. The buffer must contain an entire ACPI Table including + * a valid header. The header fields will be verified, and if it + * is determined that the table is invalid, the call will fail. + * + ******************************************************************************/ + +acpi_status +acpi_load_table ( + struct acpi_table_header *table_ptr) +{ + acpi_status status; + struct acpi_table_desc table_info; + struct acpi_pointer address; + + + ACPI_FUNCTION_TRACE ("acpi_load_table"); + + + if (!table_ptr) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Copy the table to a local buffer */ + + address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING; + address.pointer.logical = table_ptr; + + status = acpi_tb_get_table_body (&address, table_ptr, &table_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Install the new table into the local data structures */ + + status = acpi_tb_install_table (&table_info); + if (ACPI_FAILURE (status)) { + /* Free table allocated by acpi_tb_get_table_body */ + + acpi_tb_delete_single_table (&table_info); + return_ACPI_STATUS (status); + } + + /* Convert the table to common format if necessary */ + + switch (table_info.type) { + case ACPI_TABLE_FADT: + + status = acpi_tb_convert_table_fadt (); + break; + + case ACPI_TABLE_FACS: + + status = acpi_tb_build_common_facs (&table_info); + break; + + default: + /* Load table into namespace if it contains executable AML */ + + status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node); + break; + } + + if (ACPI_FAILURE (status)) { + /* Uninstall table and free the buffer */ + + (void) acpi_tb_uninstall_table (table_info.installed_desc); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_unload_table + * + * PARAMETERS: table_type - Type of table to be unloaded + * + * RETURN: Status + * + * DESCRIPTION: This routine is used to force the unload of a table + * + ******************************************************************************/ + +acpi_status +acpi_unload_table ( + acpi_table_type table_type) +{ + struct acpi_table_desc *table_desc; + + + ACPI_FUNCTION_TRACE ("acpi_unload_table"); + + + /* Parameter validation */ + + if (table_type > ACPI_TABLE_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + + /* Find all tables of the requested type */ + + table_desc = acpi_gbl_table_lists[table_type].next; + while (table_desc) { + /* + * Delete all namespace entries owned by this table. Note that these + * entries can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not + * simply a position within the hierarchy + */ + acpi_ns_delete_namespace_by_owner (table_desc->table_id); + + table_desc = table_desc->next; + } + + /* Delete (or unmap) all tables of this type */ + + acpi_tb_delete_tables_by_type (table_type); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_get_table_header + * + * PARAMETERS: table_type - one of the defined table types + * Instance - the non zero instance of the table, allows + * support for multiple tables of the same type + * see acpi_gbl_acpi_table_flag + * out_table_header - pointer to the struct acpi_table_header if successful + * + * DESCRIPTION: This function is called to get an ACPI table header. The caller + * supplies an pointer to a data area sufficient to contain an ACPI + * struct acpi_table_header structure. + * + * The header contains a length field that can be used to determine + * the size of the buffer needed to contain the entire table. This + * function is not valid for the RSD PTR table since it does not + * have a standard header and is fixed length. + * + ******************************************************************************/ + +acpi_status +acpi_get_table_header ( + acpi_table_type table_type, + u32 instance, + struct acpi_table_header *out_table_header) +{ + struct acpi_table_header *tbl_ptr; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_get_table_header"); + + + if ((instance == 0) || + (table_type == ACPI_TABLE_RSDP) || + (!out_table_header)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Check the table type and instance */ + + if ((table_type > ACPI_TABLE_MAX) || + (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags) && + instance > 1)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + + /* Get a pointer to the entire table */ + + status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * The function will return a NULL pointer if the table is not loaded + */ + if (tbl_ptr == NULL) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* + * Copy the header to the caller's buffer + */ + ACPI_MEMCPY ((void *) out_table_header, (void *) tbl_ptr, + sizeof (struct acpi_table_header)); + + return_ACPI_STATUS (status); +} + + +#endif /* ACPI_FUTURE_USAGE */ + +/******************************************************************************* + * + * FUNCTION: acpi_get_table + * + * PARAMETERS: table_type - one of the defined table types + * Instance - the non zero instance of the table, allows + * support for multiple tables of the same type + * see acpi_gbl_acpi_table_flag + * ret_buffer - pointer to a structure containing a buffer to + * receive the table + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get an ACPI table. The caller + * supplies an out_buffer large enough to contain the entire ACPI + * table. The caller should call the acpi_get_table_header function + * first to determine the buffer size needed. Upon completion + * the out_buffer->Length field will indicate the number of bytes + * copied into the out_buffer->buf_ptr buffer. This table will be + * a complete table including the header. + * + ******************************************************************************/ + +acpi_status +acpi_get_table ( + acpi_table_type table_type, + u32 instance, + struct acpi_buffer *ret_buffer) +{ + struct acpi_table_header *tbl_ptr; + acpi_status status; + acpi_size table_length; + + + ACPI_FUNCTION_TRACE ("acpi_get_table"); + + + /* Parameter validation */ + + if (instance == 0) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + status = acpi_ut_validate_buffer (ret_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Check the table type and instance */ + + if ((table_type > ACPI_TABLE_MAX) || + (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags) && + instance > 1)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + + /* Get a pointer to the entire table */ + + status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * acpi_tb_get_table_ptr will return a NULL pointer if the + * table is not loaded. + */ + if (tbl_ptr == NULL) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Get the table length */ + + if (table_type == ACPI_TABLE_RSDP) { + /* + * RSD PTR is the only "table" without a header + */ + table_length = sizeof (struct rsdp_descriptor); + } + else { + table_length = (acpi_size) tbl_ptr->length; + } + + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (ret_buffer, table_length); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Copy the table to the buffer */ + + ACPI_MEMCPY ((void *) ret_buffer->pointer, (void *) tbl_ptr, table_length); + return_ACPI_STATUS (AE_OK); +} +EXPORT_SYMBOL(acpi_get_table); + diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c new file mode 100644 index 00000000000..6e8072ebbac --- /dev/null +++ b/drivers/acpi/tables/tbxfroot.c @@ -0,0 +1,606 @@ +/****************************************************************************** + * + * Module Name: tbxfroot - Find the root ACPI table (RSDT) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * 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 <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbxfroot") + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_find_table + * + * PARAMETERS: Signature - String with ACPI table signature + * oem_id - String with the table OEM ID + * oem_table_id - String with the OEM Table ID. + * + * RETURN: Status + * + * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the + * Signature, OEM ID and OEM Table ID. + * + ******************************************************************************/ + +acpi_status +acpi_tb_find_table ( + char *signature, + char *oem_id, + char *oem_table_id, + struct acpi_table_header **table_ptr) +{ + acpi_status status; + struct acpi_table_header *table; + + + ACPI_FUNCTION_TRACE ("tb_find_table"); + + + /* Validate string lengths */ + + if ((ACPI_STRLEN (signature) > ACPI_NAME_SIZE) || + (ACPI_STRLEN (oem_id) > sizeof (table->oem_id)) || + (ACPI_STRLEN (oem_table_id) > sizeof (table->oem_table_id))) { + return_ACPI_STATUS (AE_AML_STRING_LIMIT); + } + + if (!ACPI_STRNCMP (signature, DSDT_SIG, ACPI_NAME_SIZE)) { + /* + * The DSDT pointer is contained in the FADT, not the RSDT. + * This code should suffice, because the only code that would perform + * a "find" on the DSDT is the data_table_region() AML opcode -- in + * which case, the DSDT is guaranteed to be already loaded. + * If this becomes insufficient, the FADT will have to be found first. + */ + if (!acpi_gbl_DSDT) { + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + table = acpi_gbl_DSDT; + } + else { + /* Find the table */ + + status = acpi_get_firmware_table (signature, 1, + ACPI_LOGICAL_ADDRESSING, &table); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Check oem_id and oem_table_id */ + + if ((oem_id[0] && ACPI_STRNCMP ( + oem_id, table->oem_id, sizeof (table->oem_id))) || + (oem_table_id[0] && ACPI_STRNCMP ( + oem_table_id, table->oem_table_id, sizeof (table->oem_table_id)))) { + return_ACPI_STATUS (AE_AML_NAME_NOT_FOUND); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", table->signature)); + *table_ptr = table; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_get_firmware_table + * + * PARAMETERS: Signature - Any ACPI table signature + * Instance - the non zero instance of the table, allows + * support for multiple tables of the same type + * Flags - Physical/Virtual support + * table_pointer - Where a buffer containing the table is + * returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get an ACPI table. A buffer is + * allocated for the table and returned in table_pointer. + * This table will be a complete table including the header. + * + ******************************************************************************/ + +acpi_status +acpi_get_firmware_table ( + acpi_string signature, + u32 instance, + u32 flags, + struct acpi_table_header **table_pointer) +{ + acpi_status status; + struct acpi_pointer address; + struct acpi_table_header *header = NULL; + struct acpi_table_desc *table_info = NULL; + struct acpi_table_desc *rsdt_info; + u32 table_count; + u32 i; + u32 j; + + + ACPI_FUNCTION_TRACE ("acpi_get_firmware_table"); + + + /* + * Ensure that at least the table manager is initialized. We don't + * require that the entire ACPI subsystem is up for this interface. + * If we have a buffer, we must have a length too + */ + if ((instance == 0) || + (!signature) || + (!table_pointer)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Ensure that we have a RSDP */ + + if (!acpi_gbl_RSDP) { + /* Get the RSDP */ + + status = acpi_os_get_root_pointer (flags, &address); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* Map and validate the RSDP */ + + if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { + status = acpi_os_map_memory (address.pointer.physical, sizeof (struct rsdp_descriptor), + (void *) &acpi_gbl_RSDP); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + else { + acpi_gbl_RSDP = address.pointer.logical; + } + + /* The signature and checksum must both be correct */ + + if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + /* Nope, BAD Signature */ + + return_ACPI_STATUS (AE_BAD_SIGNATURE); + } + + if (acpi_tb_checksum (acpi_gbl_RSDP, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { + /* Nope, BAD Checksum */ + + return_ACPI_STATUS (AE_BAD_CHECKSUM); + } + } + + /* Get the RSDT address via the RSDP */ + + acpi_tb_get_rsdt_address (&address); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", + acpi_gbl_RSDP, + ACPI_FORMAT_UINT64 (address.pointer.value))); + + /* Insert processor_mode flags */ + + address.pointer_type |= flags; + + /* Get and validate the RSDT */ + + rsdt_info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_table_desc)); + if (!rsdt_info) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + status = acpi_tb_get_table (&address, rsdt_info); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_tb_validate_rsdt (rsdt_info->pointer); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Allocate a scratch table header and table descriptor */ + + header = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_header)); + if (!header) { + status = AE_NO_MEMORY; + goto cleanup; + } + + table_info = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_desc)); + if (!table_info) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Get the number of table pointers within the RSDT */ + + table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info->pointer); + address.pointer_type = acpi_gbl_table_flags | flags; + + /* + * Search the RSDT/XSDT for the correct instance of the + * requested table + */ + for (i = 0, j = 0; i < table_count; i++) { + /* Get the next table pointer, handle RSDT vs. XSDT */ + + if (acpi_gbl_RSDP->revision < 2) { + address.pointer.value = (ACPI_CAST_PTR ( + RSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; + } + else { + address.pointer.value = (ACPI_CAST_PTR ( + XSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i]; + } + + /* Get the table header */ + + status = acpi_tb_get_table_header (&address, header); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Compare table signatures and table instance */ + + if (!ACPI_STRNCMP (header->signature, signature, ACPI_NAME_SIZE)) { + /* An instance of the table was found */ + + j++; + if (j >= instance) { + /* Found the correct instance, get the entire table */ + + status = acpi_tb_get_table_body (&address, header, table_info); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + *table_pointer = table_info->pointer; + goto cleanup; + } + } + } + + /* Did not find the table */ + + status = AE_NOT_EXIST; + + +cleanup: + acpi_os_unmap_memory (rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length); + ACPI_MEM_FREE (rsdt_info); + + if (header) { + ACPI_MEM_FREE (header); + } + if (table_info) { + ACPI_MEM_FREE (table_info); + } + return_ACPI_STATUS (status); +} +EXPORT_SYMBOL(acpi_get_firmware_table); + + +/* TBD: Move to a new file */ + +#if ACPI_MACHINE_WIDTH != 16 + +/******************************************************************************* + * + * FUNCTION: acpi_find_root_pointer + * + * PARAMETERS: **rsdp_address - Where to place the RSDP address + * Flags - Logical/Physical addressing + * + * RETURN: Status, Physical address of the RSDP + * + * DESCRIPTION: Find the RSDP + * + ******************************************************************************/ + +acpi_status +acpi_find_root_pointer ( + u32 flags, + struct acpi_pointer *rsdp_address) +{ + struct acpi_table_desc table_info; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_find_root_pointer"); + + + /* Get the RSDP */ + + status = acpi_tb_find_rsdp (&table_info, flags); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "RSDP structure not found, %s Flags=%X\n", + acpi_format_exception (status), flags)); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER; + rsdp_address->pointer.physical = table_info.physical_address; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_scan_memory_for_rsdp + * + * PARAMETERS: start_address - Starting pointer for search + * Length - Maximum length to search + * + * RETURN: Pointer to the RSDP if found, otherwise NULL. + * + * DESCRIPTION: Search a block of memory for the RSDP signature + * + ******************************************************************************/ + +u8 * +acpi_tb_scan_memory_for_rsdp ( + u8 *start_address, + u32 length) +{ + u8 *mem_rover; + u8 *end_address; + u8 checksum; + + + ACPI_FUNCTION_TRACE ("tb_scan_memory_for_rsdp"); + + + end_address = start_address + length; + + /* Search from given start address for the requested length */ + + for (mem_rover = start_address; mem_rover < end_address; + mem_rover += ACPI_RSDP_SCAN_STEP) { + /* The signature and checksum must both be correct */ + + if (ACPI_STRNCMP ((char *) mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + /* No signature match, keep looking */ + + continue; + } + + /* Signature matches, check the appropriate checksum */ + + if ((ACPI_CAST_PTR (struct rsdp_descriptor, mem_rover))->revision < 2) { + /* ACPI version 1.0 */ + + checksum = acpi_tb_checksum (mem_rover, ACPI_RSDP_CHECKSUM_LENGTH); + } + else { + /* Post ACPI 1.0, use extended_checksum */ + + checksum = acpi_tb_checksum (mem_rover, ACPI_RSDP_XCHECKSUM_LENGTH); + } + + if (checksum == 0) { + /* Checksum valid, we have found a valid RSDP */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "RSDP located at physical address %p\n", mem_rover)); + return_PTR (mem_rover); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Found an RSDP at physical address %p, but it has a bad checksum\n", + mem_rover)); + } + + /* Searched entire block, no RSDP was found */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Searched entire block, no valid RSDP was found.\n")); + return_PTR (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_tb_find_rsdp + * + * PARAMETERS: *table_info - Where the table info is returned + * Flags - Current memory mode (logical vs. + * physical addressing) + * + * RETURN: Status, RSDP physical address + * + * DESCRIPTION: search lower 1_mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. + * + * NOTE1: The RSDp must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) + * Only a 32-bit physical address is necessary. + * + * NOTE2: This function is always available, regardless of the + * initialization state of the rest of ACPI. + * + ******************************************************************************/ + +acpi_status +acpi_tb_find_rsdp ( + struct acpi_table_desc *table_info, + u32 flags) +{ + u8 *table_ptr; + u8 *mem_rover; + u32 physical_address; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("tb_find_rsdp"); + + + /* + * Scan supports either 1) Logical addressing or 2) Physical addressing + */ + if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { + /* + * 1a) Get the location of the EBDA + */ + status = acpi_os_map_memory ((acpi_physical_address) ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH, + (void *) &table_ptr); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not map memory at %8.8X for length %X\n", + ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); + return_ACPI_STATUS (status); + } + + ACPI_MOVE_16_TO_32 (&physical_address, table_ptr); + physical_address <<= 4; /* Convert segment to physical address */ + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH); + + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + status = acpi_os_map_memory ((acpi_physical_address) physical_address, + ACPI_EBDA_WINDOW_SIZE, + (void *) &table_ptr); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not map memory at %8.8X for length %X\n", + physical_address, ACPI_EBDA_WINDOW_SIZE)); + return_ACPI_STATUS (status); + } + + mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE); + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_WINDOW_SIZE); + + if (mem_rover) { + /* Found it, return the physical address */ + + physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr); + + table_info->physical_address = (acpi_physical_address) physical_address; + return_ACPI_STATUS (AE_OK); + } + } + + /* + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh + */ + status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE, + (void *) &table_ptr); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not map memory at %8.8X for length %X\n", + ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); + return_ACPI_STATUS (status); + } + + mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); + acpi_os_unmap_memory (table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); + + if (mem_rover) { + /* Found it, return the physical address */ + + physical_address = ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); + + table_info->physical_address = (acpi_physical_address) physical_address; + return_ACPI_STATUS (AE_OK); + } + } + + /* + * Physical addressing + */ + else { + /* + * 1a) Get the location of the EBDA + */ + ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION); + physical_address <<= 4; /* Convert segment to physical address */ + + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (physical_address), + ACPI_EBDA_WINDOW_SIZE); + if (mem_rover) { + /* Found it, return the physical address */ + + table_info->physical_address = ACPI_TO_INTEGER (mem_rover); + return_ACPI_STATUS (AE_OK); + } + } + + /* + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh + */ + mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), + ACPI_HI_RSDP_WINDOW_SIZE); + if (mem_rover) { + /* Found it, return the physical address */ + + table_info->physical_address = ACPI_TO_INTEGER (mem_rover); + return_ACPI_STATUS (AE_OK); + } + } + + /* RSDP signature was not found */ + + return_ACPI_STATUS (AE_NOT_FOUND); +} + +#endif + |