Creation of Cybook 2416 (actually Gen4) repository

This commit is contained in:
mlt
2009-12-18 17:10:00 +00:00
committed by godzil
commit 76f20f4d40
13791 changed files with 6812321 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
#
# Makefile for all Linux ACPI interpreter subdirectories
#
obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)

View File

@@ -0,0 +1,448 @@
/******************************************************************************
*
* Module Name: tbfadt - FADT table utilities
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2007, 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("tbfadt")
/* Local prototypes */
static void inline
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 bit_width, u64 address);
static void acpi_tb_convert_fadt(void);
static void acpi_tb_validate_fadt(void);
/* Table for conversion of FADT to common internal format and FADT validation */
typedef struct acpi_fadt_info {
char *name;
u8 target;
u8 source;
u8 length;
u8 type;
} acpi_fadt_info;
#define ACPI_FADT_REQUIRED 1
#define ACPI_FADT_SEPARATE_LENGTH 2
static struct acpi_fadt_info fadt_info_table[] = {
{"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
ACPI_FADT_OFFSET(pm1a_event_block),
ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
{"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
ACPI_FADT_OFFSET(pm1b_event_block),
ACPI_FADT_OFFSET(pm1_event_length), 0},
{"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
ACPI_FADT_OFFSET(pm1a_control_block),
ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
{"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
ACPI_FADT_OFFSET(pm1b_control_block),
ACPI_FADT_OFFSET(pm1_control_length), 0},
{"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
ACPI_FADT_OFFSET(pm2_control_block),
ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
{"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
ACPI_FADT_OFFSET(pm_timer_block),
ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
{"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
ACPI_FADT_OFFSET(gpe0_block),
ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
{"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
ACPI_FADT_OFFSET(gpe1_block),
ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
};
#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
/*******************************************************************************
*
* FUNCTION: acpi_tb_init_generic_address
*
* PARAMETERS: generic_address - GAS struct to be initialized
* bit_width - Width of this register
* Address - Address of the register
*
* RETURN: None
*
* DESCRIPTION: Initialize a Generic Address Structure (GAS)
* See the ACPI specification for a full description and
* definition of this structure.
*
******************************************************************************/
static void inline
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 bit_width, u64 address)
{
/*
* The 64-bit Address field is non-aligned in the byte packed
* GAS struct.
*/
ACPI_MOVE_64_TO_64(&generic_address->address, &address);
/* All other fields are byte-wide */
generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
generic_address->bit_width = bit_width;
generic_address->bit_offset = 0;
generic_address->access_width = 0;
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_parse_fadt
*
* PARAMETERS: table_index - Index for the FADT
* Flags - Flags
*
* RETURN: None
*
* DESCRIPTION: Initialize the FADT, DSDT and FACS tables
* (FADT contains the addresses of the DSDT and FACS)
*
******************************************************************************/
void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
{
u32 length;
struct acpi_table_header *table;
/*
* The FADT has multiple versions with different lengths,
* and it contains pointers to both the DSDT and FACS tables.
*
* Get a local copy of the FADT and convert it to a common format
* Map entire FADT, assumed to be smaller than one page.
*/
length = acpi_gbl_root_table_list.tables[table_index].length;
table =
acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index].
address, length);
if (!table) {
return;
}
/*
* Validate the FADT checksum before we copy the table. Ignore
* checksum error as we want to try to get the DSDT and FACS.
*/
(void)acpi_tb_verify_checksum(table, length);
/* Obtain a local copy of the FADT in common ACPI 2.0+ format */
acpi_tb_create_local_fadt(table, length);
/* All done with the real FADT, unmap it */
acpi_os_unmap_memory(table, length);
/* Obtain the DSDT and FACS tables via their addresses within the FADT */
acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_create_local_fadt
*
* PARAMETERS: Table - Pointer to BIOS FADT
* Length - Length of the table
*
* RETURN: None
*
* DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
* Performs validation on some important FADT fields.
*
******************************************************************************/
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
{
/*
* Check if the FADT is larger than what we know about (ACPI 2.0 version).
* Truncate the table, but make some noise.
*/
if (length > sizeof(struct acpi_table_fadt)) {
ACPI_WARNING((AE_INFO,
"FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX",
table->revision, (unsigned)length,
sizeof(struct acpi_table_fadt)));
}
/* Copy the entire FADT locally. Zero first for tb_convert_fadt */
ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
ACPI_MEMCPY(&acpi_gbl_FADT, table,
ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
/*
* 1) Convert the local copy of the FADT to the common internal format
* 2) Validate some of the important values within the FADT
*/
acpi_tb_convert_fadt();
acpi_tb_validate_fadt();
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_convert_fadt
*
* PARAMETERS: None, uses acpi_gbl_FADT
*
* RETURN: None
*
* DESCRIPTION: Converts all versions of the FADT to a common internal format.
* -> Expand all 32-bit addresses to 64-bit.
*
* NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
* and must contain a copy of the actual FADT.
*
* ACPICA will use the "X" fields of the FADT for all addresses.
*
* "X" fields are optional extensions to the original V1.0 fields. Even if
* they are present in the structure, they can be optionally not used by
* setting them to zero. Therefore, we must selectively expand V1.0 fields
* if the corresponding X field is zero.
*
* For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
* "X" fields.
*
* For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
* expanding the corresponding ACPI 1.0 field.
*
******************************************************************************/
static void acpi_tb_convert_fadt(void)
{
u8 pm1_register_length;
struct acpi_generic_address *target;
acpi_native_uint i;
/* Update the local FADT table header length */
acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
/* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
if (!acpi_gbl_FADT.Xfacs) {
acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
}
if (!acpi_gbl_FADT.Xdsdt) {
acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
}
/*
* Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
* structures as necessary.
*/
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
target =
ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
fadt_info_table[i].target);
/* Expand only if the X target is null */
if (!target->address) {
acpi_tb_init_generic_address(target,
*ACPI_ADD_PTR(u8,
&acpi_gbl_FADT,
fadt_info_table
[i].length),
(u64) * ACPI_ADD_PTR(u32,
&acpi_gbl_FADT,
fadt_info_table
[i].
source));
}
}
/*
* Calculate separate GAS structs for the PM1 Enable registers.
* These addresses do not appear (directly) in the FADT, so it is
* useful to calculate them once, here.
*
* The PM event blocks are split into two register blocks, first is the
* PM Status Register block, followed immediately by the PM Enable Register
* block. Each is of length (pm1_event_length/2)
*/
pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
/* The PM1A register block is required */
acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
pm1_register_length,
(acpi_gbl_FADT.xpm1a_event_block.address +
pm1_register_length));
/* Don't forget to copy space_id of the GAS */
acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
/* The PM1B register block is optional, ignore if not present */
if (acpi_gbl_FADT.xpm1b_event_block.address) {
acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
pm1_register_length,
(acpi_gbl_FADT.xpm1b_event_block.
address + pm1_register_length));
/* Don't forget to copy space_id of the GAS */
acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
}
/*
* _CST object and C States change notification start with
* ACPI 2.0 (FADT r3). Although the field should be Reserved
* and 0 before then, some pre-r3 FADT set this field and
* it results in SMM-related boot failures. For them, clear it.
*/
if ((acpi_gbl_FADT.header.revision < 3) &&
(acpi_gbl_FADT.cst_control != 0)) {
ACPI_WARNING((AE_INFO,
"Ignoring BIOS FADT r%u C-state control",
acpi_gbl_FADT.header.revision));
acpi_gbl_FADT.cst_control = 0;
}
}
/******************************************************************************
*
* FUNCTION: acpi_tb_validate_fadt
*
* PARAMETERS: Table - Pointer to the FADT to be validated
*
* RETURN: None
*
* DESCRIPTION: Validate various important fields within the FADT. If a problem
* is found, issue a message, but no status is returned.
* Used by both the table manager and the disassembler.
*
* Possible additional checks:
* (acpi_gbl_FADT.pm1_event_length >= 4)
* (acpi_gbl_FADT.pm1_control_length >= 2)
* (acpi_gbl_FADT.pm_timer_length >= 4)
* Gpe block lengths must be multiple of 2
*
******************************************************************************/
static void acpi_tb_validate_fadt(void)
{
u32 *address32;
struct acpi_generic_address *address64;
u8 length;
acpi_native_uint i;
/* Examine all of the 64-bit extended address fields (X fields) */
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
/* Generate pointers to the 32-bit and 64-bit addresses and get the length */
address64 =
ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
fadt_info_table[i].target);
address32 =
ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
fadt_info_table[i].source);
length =
*ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
fadt_info_table[i].length);
if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
/*
* Field is required (Pm1a_event, Pm1a_control, pm_timer).
* Both the address and length must be non-zero.
*/
if (!address64->address || !length) {
ACPI_ERROR((AE_INFO,
"Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
fadt_info_table[i].name,
ACPI_FORMAT_UINT64(address64->
address),
length));
}
} else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
/*
* Field is optional (PM2Control, GPE0, GPE1) AND has its own
* length field. If present, both the address and length must be valid.
*/
if ((address64->address && !length)
|| (!address64->address && length)) {
ACPI_WARNING((AE_INFO,
"Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
fadt_info_table[i].name,
ACPI_FORMAT_UINT64(address64->
address),
length));
}
}
/* If both 32- and 64-bit addresses are valid (non-zero), they must match */
if (address64->address && *address32 &&
(address64->address != (u64) * address32)) {
ACPI_ERROR((AE_INFO,
"32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
fadt_info_table[i].name, *address32,
ACPI_FORMAT_UINT64(address64->address)));
}
}
}

View File

@@ -0,0 +1,126 @@
/******************************************************************************
*
* Module Name: tbfind - find table
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2007, 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("tbfind")
/*******************************************************************************
*
* 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
* table_index - Where the table index is returned
*
* RETURN: Status and table index
*
* DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
* Signature, OEM ID and OEM Table ID. Returns an index that can
* be used to get the table header or entire table.
*
******************************************************************************/
acpi_status
acpi_tb_find_table(char *signature,
char *oem_id,
char *oem_table_id, acpi_native_uint * table_index)
{
acpi_native_uint i;
acpi_status status;
ACPI_FUNCTION_TRACE(tb_find_table);
for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
signature, ACPI_NAME_SIZE)) {
/* Not the requested table */
continue;
}
/* Table with matching signature has been found */
if (!acpi_gbl_root_table_list.tables[i].pointer) {
/* Table is not currently mapped, map it */
status =
acpi_tb_verify_table(&acpi_gbl_root_table_list.
tables[i]);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (!acpi_gbl_root_table_list.tables[i].pointer) {
continue;
}
}
/* Check for table match on all IDs */
if (!ACPI_MEMCMP
(acpi_gbl_root_table_list.tables[i].pointer->signature,
signature, ACPI_NAME_SIZE) && (!oem_id[0]
||
!ACPI_MEMCMP
(acpi_gbl_root_table_list.
tables[i].pointer->oem_id,
oem_id, ACPI_OEM_ID_SIZE))
&& (!oem_table_id[0]
|| !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
pointer->oem_table_id, oem_table_id,
ACPI_OEM_TABLE_ID_SIZE))) {
*table_index = i;
ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
"Found table [%4.4s]\n", signature));
return_ACPI_STATUS(AE_OK);
}
}
return_ACPI_STATUS(AE_NOT_FOUND);
}

View File

@@ -0,0 +1,539 @@
/******************************************************************************
*
* Module Name: tbinstal - ACPI table installation and removal
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2007, 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/acnamesp.h>
#include <acpi/actables.h>
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbinstal")
/******************************************************************************
*
* FUNCTION: acpi_tb_verify_table
*
* PARAMETERS: table_desc - table
*
* RETURN: Status
*
* DESCRIPTION: this function is called to verify and map table
*
*****************************************************************************/
acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(tb_verify_table);
/* Map the table if necessary */
if (!table_desc->pointer) {
if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
ACPI_TABLE_ORIGIN_MAPPED) {
table_desc->pointer =
acpi_os_map_memory(table_desc->address,
table_desc->length);
}
if (!table_desc->pointer) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
}
/* FACS is the odd table, has no standard ACPI header and no checksum */
if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) {
/* Always calculate checksum, ignore bad checksum if requested */
status =
acpi_tb_verify_checksum(table_desc->pointer,
table_desc->length);
}
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_add_table
*
* PARAMETERS: table_desc - Table descriptor
* table_index - Where the table index is returned
*
* RETURN: Status
*
* DESCRIPTION: This function is called to add the ACPI table
*
******************************************************************************/
acpi_status
acpi_tb_add_table(struct acpi_table_desc *table_desc,
acpi_native_uint * table_index)
{
acpi_native_uint i;
acpi_native_uint length;
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(tb_add_table);
if (!table_desc->pointer) {
status = acpi_tb_verify_table(table_desc);
if (ACPI_FAILURE(status) || !table_desc->pointer) {
return_ACPI_STATUS(status);
}
}
/* The table must be either an SSDT or a PSDT */
if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
&&
(!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)))
{
ACPI_ERROR((AE_INFO,
"Table has invalid signature [%4.4s], must be SSDT or PSDT",
table_desc->pointer->signature));
return_ACPI_STATUS(AE_BAD_SIGNATURE);
}
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
/* Check if table is already registered */
for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
if (!acpi_gbl_root_table_list.tables[i].pointer) {
status =
acpi_tb_verify_table(&acpi_gbl_root_table_list.
tables[i]);
if (ACPI_FAILURE(status)
|| !acpi_gbl_root_table_list.tables[i].pointer) {
continue;
}
}
length = ACPI_MIN(table_desc->length,
acpi_gbl_root_table_list.tables[i].length);
if (ACPI_MEMCMP(table_desc->pointer,
acpi_gbl_root_table_list.tables[i].pointer,
length)) {
continue;
}
/* Table is already registered */
acpi_tb_delete_table(table_desc);
*table_index = i;
goto release;
}
/*
* Add the table to the global table list
*/
status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
table_desc->length, table_desc->flags,
table_index);
if (ACPI_FAILURE(status)) {
goto release;
}
acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
release:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_resize_root_table_list
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Expand the size of global table array
*
******************************************************************************/
acpi_status acpi_tb_resize_root_table_list(void)
{
struct acpi_table_desc *tables;
ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
/* allow_resize flag is a parameter to acpi_initialize_tables */
if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
ACPI_ERROR((AE_INFO,
"Resize of Root Table Array is not allowed"));
return_ACPI_STATUS(AE_SUPPORT);
}
/* Increase the Table Array size */
tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size +
ACPI_ROOT_TABLE_SIZE_INCREMENT)
* sizeof(struct acpi_table_desc));
if (!tables) {
ACPI_ERROR((AE_INFO,
"Could not allocate new root table array"));
return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Copy and free the previous table array */
if (acpi_gbl_root_table_list.tables) {
ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
acpi_gbl_root_table_list.size *
sizeof(struct acpi_table_desc));
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
ACPI_FREE(acpi_gbl_root_table_list.tables);
}
}
acpi_gbl_root_table_list.tables = tables;
acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT;
acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED;
return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_store_table
*
* PARAMETERS: Address - Table address
* Table - Table header
* Length - Table length
* Flags - flags
*
* RETURN: Status and table index.
*
* DESCRIPTION: Add an ACPI table to the global table list
*
******************************************************************************/
acpi_status
acpi_tb_store_table(acpi_physical_address address,
struct acpi_table_header *table,
u32 length, u8 flags, acpi_native_uint * table_index)
{
acpi_status status = AE_OK;
/* Ensure that there is room for the table in the Root Table List */
if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) {
status = acpi_tb_resize_root_table_list();
if (ACPI_FAILURE(status)) {
return (status);
}
}
/* Initialize added table */
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
address = address;
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
pointer = table;
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length =
length;
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
owner_id = 0;
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags =
flags;
ACPI_MOVE_32_TO_32(&
(acpi_gbl_root_table_list.
tables[acpi_gbl_root_table_list.count].signature),
table->signature);
*table_index = acpi_gbl_root_table_list.count;
acpi_gbl_root_table_list.count++;
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_delete_table
*
* PARAMETERS: table_index - Table index
*
* RETURN: None
*
* DESCRIPTION: Delete one internal ACPI table
*
******************************************************************************/
void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
{
/* Table must be mapped or allocated */
if (!table_desc->pointer) {
return;
}
switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
case ACPI_TABLE_ORIGIN_MAPPED:
acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
break;
case ACPI_TABLE_ORIGIN_ALLOCATED:
ACPI_FREE(table_desc->pointer);
break;
default:;
}
table_desc->pointer = NULL;
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_terminate
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Delete all internal ACPI tables
*
******************************************************************************/
void acpi_tb_terminate(void)
{
acpi_native_uint i;
ACPI_FUNCTION_TRACE(tb_terminate);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
/* Delete the individual tables */
for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
}
/*
* Delete the root table array if allocated locally. Array cannot be
* mapped, so we don't need to check for that flag.
*/
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
ACPI_FREE(acpi_gbl_root_table_list.tables);
}
acpi_gbl_root_table_list.tables = NULL;
acpi_gbl_root_table_list.flags = 0;
acpi_gbl_root_table_list.count = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_delete_namespace_by_owner
*
* PARAMETERS: table_index - Table index
*
* RETURN: None
*
* DESCRIPTION: Delete all namespace objects created when this table was loaded.
*
******************************************************************************/
void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
{
acpi_owner_id owner_id;
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.count) {
owner_id =
acpi_gbl_root_table_list.tables[table_index].owner_id;
} else {
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
acpi_ns_delete_namespace_by_owner(owner_id);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_allocate_owner_id
*
* PARAMETERS: table_index - Table index
*
* RETURN: Status
*
* DESCRIPTION: Allocates owner_id in table_desc
*
******************************************************************************/
acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
{
acpi_status status = AE_BAD_PARAMETER;
ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.count) {
status = acpi_ut_allocate_owner_id
(&(acpi_gbl_root_table_list.tables[table_index].owner_id));
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_release_owner_id
*
* PARAMETERS: table_index - Table index
*
* RETURN: Status
*
* DESCRIPTION: Releases owner_id in table_desc
*
******************************************************************************/
acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
{
acpi_status status = AE_BAD_PARAMETER;
ACPI_FUNCTION_TRACE(tb_release_owner_id);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.count) {
acpi_ut_release_owner_id(&
(acpi_gbl_root_table_list.
tables[table_index].owner_id));
status = AE_OK;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_get_owner_id
*
* PARAMETERS: table_index - Table index
* owner_id - Where the table owner_id is returned
*
* RETURN: Status
*
* DESCRIPTION: returns owner_id for the ACPI table
*
******************************************************************************/
acpi_status
acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
{
acpi_status status = AE_BAD_PARAMETER;
ACPI_FUNCTION_TRACE(tb_get_owner_id);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.count) {
*owner_id =
acpi_gbl_root_table_list.tables[table_index].owner_id;
status = AE_OK;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_is_table_loaded
*
* PARAMETERS: table_index - Table index
*
* RETURN: Table Loaded Flag
*
******************************************************************************/
u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
{
u8 is_loaded = FALSE;
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.count) {
is_loaded = (u8)
(acpi_gbl_root_table_list.tables[table_index].
flags & ACPI_TABLE_IS_LOADED);
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return (is_loaded);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_set_table_loaded_flag
*
* PARAMETERS: table_index - Table index
* is_loaded - TRUE if table is loaded, FALSE otherwise
*
* RETURN: None
*
* DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
*
******************************************************************************/
void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded)
{
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.count) {
if (is_loaded) {
acpi_gbl_root_table_list.tables[table_index].flags |=
ACPI_TABLE_IS_LOADED;
} else {
acpi_gbl_root_table_list.tables[table_index].flags &=
~ACPI_TABLE_IS_LOADED;
}
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}

View File

@@ -0,0 +1,487 @@
/******************************************************************************
*
* Module Name: tbutils - table utilities
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2007, 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")
/* Local prototypes */
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 * table_entry,
acpi_native_uint table_entry_size);
/*******************************************************************************
*
* FUNCTION: acpi_tb_tables_loaded
*
* PARAMETERS: None
*
* RETURN: TRUE if required ACPI tables are loaded
*
* DESCRIPTION: Determine if the minimum required ACPI tables are present
* (FADT, FACS, DSDT)
*
******************************************************************************/
u8 acpi_tb_tables_loaded(void)
{
if (acpi_gbl_root_table_list.count >= 3) {
return (TRUE);
}
return (FALSE);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_print_table_header
*
* PARAMETERS: Address - Table physical address
* Header - Table header
*
* RETURN: None
*
* DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
*
******************************************************************************/
void
acpi_tb_print_table_header(acpi_physical_address address,
struct acpi_table_header *header)
{
if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
/* FACS only has signature and length fields of common table header */
ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X",
header->signature, (unsigned long)address,
header->length));
} else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
/* RSDP has no common fields */
ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)",
(unsigned long)address,
(ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
revision >
0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
header)->length : 20,
ACPI_CAST_PTR(struct acpi_table_rsdp,
header)->revision,
ACPI_CAST_PTR(struct acpi_table_rsdp,
header)->oem_id));
} else {
/* Standard ACPI table with full common header */
ACPI_INFO((AE_INFO,
"%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)",
header->signature, (unsigned long)address,
header->length, header->revision, header->oem_id,
header->oem_table_id, header->oem_revision,
header->asl_compiler_id,
header->asl_compiler_revision));
}
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_checksum
*
* PARAMETERS: Table - ACPI table to verify
* Length - Length of entire table
*
* RETURN: Status
*
* DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
* exception on bad checksum.
*
******************************************************************************/
acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
{
u8 checksum;
/* Compute the checksum on the table */
checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
/* Checksum ok? (should be zero) */
if (checksum) {
ACPI_WARNING((AE_INFO,
"Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
table->signature, table->checksum,
(u8) (table->checksum - checksum)));
#if (ACPI_CHECKSUM_ABORT)
return (AE_BAD_CHECKSUM);
#endif
}
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_checksum
*
* PARAMETERS: Buffer - Pointer to memory region to be checked
* Length - Length of this memory region
*
* RETURN: Checksum (u8)
*
* DESCRIPTION: Calculates circular checksum of memory region.
*
******************************************************************************/
u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
{
u8 sum = 0;
u8 *end = buffer + length;
while (buffer < end) {
sum = (u8) (sum + *(buffer++));
}
return sum;
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_install_table
*
* PARAMETERS: Address - Physical address of DSDT or FACS
* Flags - Flags
* Signature - Table signature, NULL if no need to
* match
* table_index - Index into root table array
*
* RETURN: None
*
* DESCRIPTION: Install an ACPI table into the global data structure.
*
******************************************************************************/
void
acpi_tb_install_table(acpi_physical_address address,
u8 flags, char *signature, acpi_native_uint table_index)
{
struct acpi_table_header *table;
if (!address) {
ACPI_ERROR((AE_INFO,
"Null physical address for ACPI table [%s]",
signature));
return;
}
/* Map just the table header */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
if (!table) {
return;
}
/* If a particular signature is expected, signature must match */
if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
ACPI_ERROR((AE_INFO,
"Invalid signature 0x%X for ACPI table [%s]",
*ACPI_CAST_PTR(u32, table->signature), signature));
goto unmap_and_exit;
}
/* Initialize the table entry */
acpi_gbl_root_table_list.tables[table_index].address = address;
acpi_gbl_root_table_list.tables[table_index].length = table->length;
acpi_gbl_root_table_list.tables[table_index].flags = flags;
ACPI_MOVE_32_TO_32(&
(acpi_gbl_root_table_list.tables[table_index].
signature), table->signature);
acpi_tb_print_table_header(address, table);
if (table_index == ACPI_TABLE_INDEX_DSDT) {
/* Global integer width is based upon revision of the DSDT */
acpi_ut_set_integer_width(table->revision);
}
unmap_and_exit:
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_get_root_table_entry
*
* PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry
* table_entry_size - sizeof 32 or 64 (RSDT or XSDT)
*
* RETURN: Physical address extracted from the root table
*
* DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
* both 32-bit and 64-bit platforms
*
* NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
* 64-bit platforms.
*
******************************************************************************/
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 * table_entry,
acpi_native_uint table_entry_size)
{
u64 address64;
/*
* Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
* Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
*/
if (table_entry_size == sizeof(u32)) {
/*
* 32-bit platform, RSDT: Return 32-bit table entry
* 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
*/
return ((acpi_physical_address)
(*ACPI_CAST_PTR(u32, table_entry)));
} else {
/*
* 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
* 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit
*/
ACPI_MOVE_64_TO_64(&address64, table_entry);
#if ACPI_MACHINE_WIDTH == 32
if (address64 > ACPI_UINT32_MAX) {
/* Will truncate 64-bit address to 32 bits, issue warning */
ACPI_WARNING((AE_INFO,
"64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating",
ACPI_FORMAT_UINT64(address64)));
}
#endif
return ((acpi_physical_address) (address64));
}
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_parse_root_table
*
* PARAMETERS: Rsdp - Pointer to the RSDP
* Flags - Flags
*
* RETURN: Status
*
* DESCRIPTION: This function is called to parse the Root System Description
* Table (RSDT or XSDT)
*
* NOTE: Tables are mapped (not copied) for efficiency. The FACS must
* be mapped and cannot be copied because it contains the actual
* memory location of the ACPI Global Lock.
*
******************************************************************************/
acpi_status __init
acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
{
struct acpi_table_rsdp *rsdp;
acpi_native_uint table_entry_size;
acpi_native_uint i;
u32 table_count;
struct acpi_table_header *table;
acpi_physical_address address;
u32 length;
u8 *table_entry;
acpi_status status;
ACPI_FUNCTION_TRACE(tb_parse_root_table);
/*
* Map the entire RSDP and extract the address of the RSDT or XSDT
*/
rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
if (!rsdp) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
acpi_tb_print_table_header(rsdp_address,
ACPI_CAST_PTR(struct acpi_table_header,
rsdp));
/* Differentiate between RSDT and XSDT root tables */
if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
/*
* Root table is an XSDT (64-bit physical addresses). We must use the
* XSDT if the revision is > 1 and the XSDT pointer is present, as per
* the ACPI specification.
*/
address = (acpi_physical_address) rsdp->xsdt_physical_address;
table_entry_size = sizeof(u64);
} else {
/* Root table is an RSDT (32-bit physical addresses) */
address = (acpi_physical_address) rsdp->rsdt_physical_address;
table_entry_size = sizeof(u32);
}
/*
* It is not possible to map more than one entry in some environments,
* so unmap the RSDP here before mapping other tables
*/
acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
/* Map the RSDT/XSDT table header to get the full table length */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
if (!table) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
acpi_tb_print_table_header(address, table);
/* Get the length of the full table, verify length and map entire table */
length = table->length;
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
if (length < sizeof(struct acpi_table_header)) {
ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
length));
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
}
table = acpi_os_map_memory(address, length);
if (!table) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Validate the root table checksum */
status = acpi_tb_verify_checksum(table, length);
if (ACPI_FAILURE(status)) {
acpi_os_unmap_memory(table, length);
return_ACPI_STATUS(status);
}
/* Calculate the number of tables described in the root table */
table_count =
(u32) ((table->length -
sizeof(struct acpi_table_header)) / table_entry_size);
/*
* First two entries in the table array are reserved for the DSDT and FACS,
* which are not actually present in the RSDT/XSDT - they come from the FADT
*/
table_entry =
ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
acpi_gbl_root_table_list.count = 2;
/*
* Initialize the root table array from the RSDT/XSDT
*/
for (i = 0; i < table_count; i++) {
if (acpi_gbl_root_table_list.count >=
acpi_gbl_root_table_list.size) {
/* There is no more room in the root table array, attempt resize */
status = acpi_tb_resize_root_table_list();
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO,
"Truncating %u table entries!",
(unsigned)
(acpi_gbl_root_table_list.size -
acpi_gbl_root_table_list.
count)));
break;
}
}
/* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
address =
acpi_tb_get_root_table_entry(table_entry, table_entry_size);
table_entry += table_entry_size;
acpi_gbl_root_table_list.count++;
}
/*
* It is not possible to map more than one entry in some environments,
* so unmap the root table here before mapping other tables
*/
acpi_os_unmap_memory(table, length);
/*
* Complete the initialization of the root table array by examining
* the header of each table
*/
for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
address, flags, NULL, i);
/* Special case for FADT - get the DSDT and FACS */
if (ACPI_COMPARE_NAME
(&acpi_gbl_root_table_list.tables[i].signature,
ACPI_SIG_FADT)) {
acpi_tb_parse_fadt(i, flags);
}
}
return_ACPI_STATUS(AE_OK);
}

View File

@@ -0,0 +1,624 @@
/******************************************************************************
*
* Module Name: tbxface - Public interfaces to the ACPI subsystem
* ACPI table oriented interfaces
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2007, 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/acnamesp.h>
#include <acpi/actables.h>
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxface")
/* Local prototypes */
static acpi_status acpi_tb_load_namespace(void);
/*******************************************************************************
*
* FUNCTION: acpi_allocate_root_table
*
* PARAMETERS: initial_table_count - Size of initial_table_array, in number of
* struct acpi_table_desc structures
*
* RETURN: Status
*
* DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and
* acpi_initialize_tables.
*
******************************************************************************/
acpi_status acpi_allocate_root_table(u32 initial_table_count)
{
acpi_gbl_root_table_list.size = initial_table_count;
acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;
return (acpi_tb_resize_root_table_list());
}
/*******************************************************************************
*
* FUNCTION: acpi_initialize_tables
*
* PARAMETERS: initial_table_array - Pointer to an array of pre-allocated
* struct acpi_table_desc structures. If NULL, the
* array is dynamically allocated.
* initial_table_count - Size of initial_table_array, in number of
* struct acpi_table_desc structures
* allow_realloc - Flag to tell Table Manager if resize of
* pre-allocated array is allowed. Ignored
* if initial_table_array is NULL.
*
* RETURN: Status
*
* DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
*
* NOTE: Allows static allocation of the initial table array in order
* to avoid the use of dynamic memory in confined environments
* such as the kernel boot sequence where it may not be available.
*
* If the host OS memory managers are initialized, use NULL for
* initial_table_array, and the table will be dynamically allocated.
*
******************************************************************************/
acpi_status __init
acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
u32 initial_table_count, u8 allow_resize)
{
acpi_physical_address rsdp_address;
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_initialize_tables);
/*
* Set up the Root Table Array
* Allocate the table array if requested
*/
if (!initial_table_array) {
status = acpi_allocate_root_table(initial_table_count);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
} else {
/* Root Table Array has been statically allocated by the host */
ACPI_MEMSET(initial_table_array, 0,
initial_table_count *
sizeof(struct acpi_table_desc));
acpi_gbl_root_table_list.tables = initial_table_array;
acpi_gbl_root_table_list.size = initial_table_count;
acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
if (allow_resize) {
acpi_gbl_root_table_list.flags |=
ACPI_ROOT_ALLOW_RESIZE;
}
}
/* Get the address of the RSDP */
rsdp_address = acpi_os_get_root_pointer();
if (!rsdp_address) {
return_ACPI_STATUS(AE_NOT_FOUND);
}
/*
* Get the root table (RSDT or XSDT) and extract all entries to the local
* Root Table Array. This array contains the information of the RSDT/XSDT
* in a common, more useable format.
*/
status =
acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_reallocate_root_table
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
* root list from the previously provided scratch area. Should
* be called once dynamic memory allocation is available in the
* kernel
*
******************************************************************************/
acpi_status acpi_reallocate_root_table(void)
{
struct acpi_table_desc *tables;
acpi_size new_size;
ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
/*
* Only reallocate the root table if the host provided a static buffer
* for the table array in the call to acpi_initialize_tables.
*/
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
return_ACPI_STATUS(AE_SUPPORT);
}
new_size =
(acpi_gbl_root_table_list.count +
ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
/* Create new array and copy the old array */
tables = ACPI_ALLOCATE_ZEROED(new_size);
if (!tables) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size);
acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count;
acpi_gbl_root_table_list.tables = tables;
acpi_gbl_root_table_list.flags =
ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE;
return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
* 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;
acpi_native_uint table_index;
struct acpi_table_desc table_desc;
if (!table_ptr)
return AE_BAD_PARAMETER;
ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
table_desc.pointer = table_ptr;
table_desc.length = table_ptr->length;
table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
/*
* Install the new table into the local data structures
*/
status = acpi_tb_add_table(&table_desc, &table_index);
if (ACPI_FAILURE(status)) {
return status;
}
status = acpi_ns_load_table(table_index, acpi_gbl_root_node);
return status;
}
ACPI_EXPORT_SYMBOL(acpi_load_table)
/******************************************************************************
*
* FUNCTION: acpi_get_table_header
*
* PARAMETERS: Signature - ACPI signature of needed table
* Instance - Which instance (for SSDTs)
* out_table_header - The pointer to the table header to fill
*
* RETURN: Status and pointer to mapped table header
*
* DESCRIPTION: Finds an ACPI table header.
*
* NOTE: Caller is responsible in unmapping the header with
* acpi_os_unmap_memory
*
*****************************************************************************/
acpi_status
acpi_get_table_header(char *signature,
acpi_native_uint instance,
struct acpi_table_header *out_table_header)
{
acpi_native_uint i;
acpi_native_uint j;
struct acpi_table_header *header;
/* Parameter validation */
if (!signature || !out_table_header) {
return (AE_BAD_PARAMETER);
}
/*
* Walk the root table list
*/
for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
if (!ACPI_COMPARE_NAME
(&(acpi_gbl_root_table_list.tables[i].signature),
signature)) {
continue;
}
if (++j < instance) {
continue;
}
if (!acpi_gbl_root_table_list.tables[i].pointer) {
if ((acpi_gbl_root_table_list.tables[i].
flags & ACPI_TABLE_ORIGIN_MASK) ==
ACPI_TABLE_ORIGIN_MAPPED) {
header =
acpi_os_map_memory(acpi_gbl_root_table_list.
tables[i].address,
sizeof(struct
acpi_table_header));
if (!header) {
return AE_NO_MEMORY;
}
ACPI_MEMCPY(out_table_header, header,
sizeof(struct acpi_table_header));
acpi_os_unmap_memory(header,
sizeof(struct
acpi_table_header));
} else {
return AE_NOT_FOUND;
}
} else {
ACPI_MEMCPY(out_table_header,
acpi_gbl_root_table_list.tables[i].pointer,
sizeof(struct acpi_table_header));
}
return (AE_OK);
}
return (AE_NOT_FOUND);
}
ACPI_EXPORT_SYMBOL(acpi_get_table_header)
/******************************************************************************
*
* FUNCTION: acpi_unload_table_id
*
* PARAMETERS: id - Owner ID of the table to be removed.
*
* RETURN: Status
*
* DESCRIPTION: This routine is used to force the unload of a table (by id)
*
******************************************************************************/
acpi_status acpi_unload_table_id(acpi_owner_id id)
{
int i;
acpi_status status = AE_NOT_EXIST;
ACPI_FUNCTION_TRACE(acpi_unload_table_id);
/* Find table in the global table list */
for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
continue;
}
/*
* Delete all namespace objects owned by this table. Note that these
* objects 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_tb_delete_namespace_by_owner(i);
status = acpi_tb_release_owner_id(i);
acpi_tb_set_table_loaded_flag(i, FALSE);
break;
}
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
/*******************************************************************************
*
* FUNCTION: acpi_get_table
*
* PARAMETERS: Signature - ACPI signature of needed table
* Instance - Which instance (for SSDTs)
* out_table - Where the pointer to the table is returned
*
* RETURN: Status and pointer to table
*
* DESCRIPTION: Finds and verifies an ACPI table.
*
*****************************************************************************/
acpi_status
acpi_get_table(char *signature,
acpi_native_uint instance, struct acpi_table_header ** out_table)
{
acpi_native_uint i;
acpi_native_uint j;
acpi_status status;
/* Parameter validation */
if (!signature || !out_table) {
return (AE_BAD_PARAMETER);
}
/*
* Walk the root table list
*/
for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
if (!ACPI_COMPARE_NAME
(&(acpi_gbl_root_table_list.tables[i].signature),
signature)) {
continue;
}
if (++j < instance) {
continue;
}
status =
acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
if (ACPI_SUCCESS(status)) {
*out_table = acpi_gbl_root_table_list.tables[i].pointer;
}
if (!acpi_gbl_permanent_mmap) {
acpi_gbl_root_table_list.tables[i].pointer = NULL;
}
return (status);
}
return (AE_NOT_FOUND);
}
ACPI_EXPORT_SYMBOL(acpi_get_table)
/*******************************************************************************
*
* FUNCTION: acpi_get_table_by_index
*
* PARAMETERS: table_index - Table index
* Table - Where the pointer to the table is returned
*
* RETURN: Status and pointer to the table
*
* DESCRIPTION: Obtain a table by an index into the global table list.
*
******************************************************************************/
acpi_status
acpi_get_table_by_index(acpi_native_uint table_index,
struct acpi_table_header ** table)
{
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
/* Parameter validation */
if (!table) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
/* Validate index */
if (table_index >= acpi_gbl_root_table_list.count) {
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
/* Table is not mapped, map it */
status =
acpi_tb_verify_table(&acpi_gbl_root_table_list.
tables[table_index]);
if (ACPI_FAILURE(status)) {
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
}
*table = acpi_gbl_root_table_list.tables[table_index].pointer;
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(AE_OK);
}
ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
/*******************************************************************************
*
* FUNCTION: acpi_tb_load_namespace
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
* the RSDT/XSDT.
*
******************************************************************************/
static acpi_status acpi_tb_load_namespace(void)
{
acpi_status status;
struct acpi_table_header *table;
acpi_native_uint i;
ACPI_FUNCTION_TRACE(tb_load_namespace);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
/*
* Load the namespace. The DSDT is required, but any SSDT and PSDT tables
* are optional.
*/
if (!acpi_gbl_root_table_list.count ||
!ACPI_COMPARE_NAME(&
(acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT].signature),
ACPI_SIG_DSDT)
||
ACPI_FAILURE(acpi_tb_verify_table
(&acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT]))) {
status = AE_NO_ACPI_TABLES;
goto unlock_and_exit;
}
/*
* Find DSDT table
*/
status =
acpi_os_table_override(acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT].pointer,
&table);
if (ACPI_SUCCESS(status) && table) {
/*
* DSDT table has been found
*/
acpi_tb_delete_table(&acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT]);
acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer =
table;
acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length =
table->length;
acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags =
ACPI_TABLE_ORIGIN_UNKNOWN;
ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
acpi_tb_print_table_header(0, table);
}
status =
acpi_tb_verify_table(&acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT]);
if (ACPI_FAILURE(status)) {
/* A valid DSDT is required */
status = AE_NO_ACPI_TABLES;
goto unlock_and_exit;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
/*
* Load and parse tables.
*/
status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/*
* Load any SSDT or PSDT tables. Note: Loop leaves tables locked
*/
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
if ((!ACPI_COMPARE_NAME
(&(acpi_gbl_root_table_list.tables[i].signature),
ACPI_SIG_SSDT)
&&
!ACPI_COMPARE_NAME(&
(acpi_gbl_root_table_list.tables[i].
signature), ACPI_SIG_PSDT))
||
ACPI_FAILURE(acpi_tb_verify_table
(&acpi_gbl_root_table_list.tables[i]))) {
continue;
}
/* Ignore errors while loading tables, get as many as possible */
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
(void)acpi_ns_load_table(i, acpi_gbl_root_node);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
}
ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_load_tables
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
*
******************************************************************************/
acpi_status acpi_load_tables(void)
{
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_load_tables);
/*
* Load the namespace from the tables
*/
status = acpi_tb_load_namespace();
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"While loading namespace from ACPI tables"));
}
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_load_tables)

View File

@@ -0,0 +1,275 @@
/******************************************************************************
*
* Module Name: tbxfroot - Find the root ACPI table (RSDT)
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2007, 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("tbxfroot")
/* Local prototypes */
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_rsdp
*
* PARAMETERS: Rsdp - Pointer to unvalidated RSDP
*
* RETURN: Status
*
* DESCRIPTION: Validate the RSDP (ptr)
*
******************************************************************************/
static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
{
ACPI_FUNCTION_ENTRY();
/*
* The signature and checksum must both be correct
*
* Note: Sometimes there exists more than one RSDP in memory; the valid
* RSDP has a valid checksum, all others have an invalid checksum.
*/
if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)
!= 0) {
/* Nope, BAD Signature */
return (AE_BAD_SIGNATURE);
}
/* Check the standard checksum */
if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
return (AE_BAD_CHECKSUM);
}
/* Check extended checksum if table version >= 2 */
if ((rsdp->revision >= 2) &&
(acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
return (AE_BAD_CHECKSUM);
}
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_find_rsdp
*
* PARAMETERS: table_address - Where the table pointer is returned
*
* 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_find_root_pointer(acpi_native_uint * table_address)
{
u8 *table_ptr;
u8 *mem_rover;
u32 physical_address;
ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
table_ptr = acpi_os_map_memory((acpi_physical_address)
ACPI_EBDA_PTR_LOCATION,
ACPI_EBDA_PTR_LENGTH);
if (!table_ptr) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X for length %X",
ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
return_ACPI_STATUS(AE_NO_MEMORY);
}
ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
/* Convert segment part to physical address */
physical_address <<= 4;
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)
*/
table_ptr = acpi_os_map_memory((acpi_native_uint)
physical_address,
ACPI_EBDA_WINDOW_SIZE);
if (!table_ptr) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X for length %X",
physical_address, ACPI_EBDA_WINDOW_SIZE));
return_ACPI_STATUS(AE_NO_MEMORY);
}
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) {
/* Return the physical address */
physical_address +=
(u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
*table_address = physical_address;
return_ACPI_STATUS(AE_OK);
}
}
/*
* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
*/
table_ptr = acpi_os_map_memory((acpi_physical_address)
ACPI_HI_RSDP_WINDOW_BASE,
ACPI_HI_RSDP_WINDOW_SIZE);
if (!table_ptr) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X for length %X",
ACPI_HI_RSDP_WINDOW_BASE,
ACPI_HI_RSDP_WINDOW_SIZE));
return_ACPI_STATUS(AE_NO_MEMORY);
}
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) {
/* Return the physical address */
physical_address = (u32)
(ACPI_HI_RSDP_WINDOW_BASE +
ACPI_PTR_DIFF(mem_rover, table_ptr));
*table_address = physical_address;
return_ACPI_STATUS(AE_OK);
}
/* A valid RSDP was not found */
ACPI_ERROR((AE_INFO, "A valid RSDP was not found"));
return_ACPI_STATUS(AE_NOT_FOUND);
}
ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
/*******************************************************************************
*
* 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
*
******************************************************************************/
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
{
acpi_status status;
u8 *mem_rover;
u8 *end_address;
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 RSDP signature and checksum must both be correct */
status =
acpi_tb_validate_rsdp(ACPI_CAST_PTR
(struct acpi_table_rsdp, mem_rover));
if (ACPI_SUCCESS(status)) {
/* Sig and checksum valid, we have found a real RSDP */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"RSDP located at physical address %p\n",
mem_rover));
return_PTR(mem_rover);
}
/* No sig match or bad checksum, keep searching */
}
/* Searched entire block, no RSDP was found */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Searched entire block from %p, valid RSDP was not found\n",
start_address));
return_PTR(NULL);
}