Exemple #1
0
ACPI_STATUS
acpi_tb_map_acpi_table (
	ACPI_PHYSICAL_ADDRESS   physical_address,
	u32                     *size,
	void                    **logical_address)
{
	ACPI_TABLE_HEADER       *table;
	u32                     table_size = *size;
	ACPI_STATUS             status = AE_OK;


	/* If size is zero, look at the table header to get the actual size */

	if ((*size) == 0) {
		/* Get the table header so we can extract the table length */

		status = acpi_os_map_memory (physical_address, sizeof (ACPI_TABLE_HEADER),
				  (void **) &table);
		if (ACPI_FAILURE (status)) {
			return (status);
		}

		/* Extract the full table length before we delete the mapping */

		table_size = table->length;

		/*
		 * Validate the header and delete the mapping.
		 * We will create a mapping for the full table below.
		 */

		status = acpi_tb_validate_table_header (table);

		/* Always unmap the memory for the header */

		acpi_os_unmap_memory (table, sizeof (ACPI_TABLE_HEADER));

		/* Exit if header invalid */

		if (ACPI_FAILURE (status)) {
			return (status);
		}
	}


	/* Map the physical memory for the correct length */

	status = acpi_os_map_memory (physical_address, table_size, (void **) &table);
	if (ACPI_FAILURE (status)) {
		return (status);
	}

	*size = table_size;
	*logical_address = table;

	return (status);
}
/******************************************************************************
 *
 * 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_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);
        }
    }

    /* Always calculate checksum, ignore bad checksum if requested */

    status =
        acpi_tb_verify_checksum(table_desc->pointer, table_desc->length);

    return_ACPI_STATUS(status);
}
Exemple #4
0
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);
}
Exemple #5
0
void acpi_tb_parse_fadt(u32 table_index)
{
	u32 length;
	struct acpi_table_header *table;

	
	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;
	}

	
	(void)acpi_tb_verify_checksum(table, length);

	

	acpi_tb_create_local_fadt(table, length);

	

	acpi_os_unmap_memory(table, length);

	

	acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
			      ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);

	acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
			      ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
}
Exemple #6
0
acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
{
	acpi_status status = AE_OK;

	ACPI_FUNCTION_TRACE(tb_verify_table);

	

	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);
		}
	}

	

	if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) {

		

		status =
		    acpi_tb_verify_checksum(table_desc->pointer,
					    table_desc->length);
	}

	return_ACPI_STATUS(status);
}
Exemple #7
0
/******************************************************************************
 *
 * 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);
}
Exemple #8
0
static acpi_status
acpi_tb_check_xsdt(acpi_physical_address address)
{
	struct acpi_table_header *table;
	u32 length;
	u64 xsdt_entry_address;
	u8 *table_entry;
	u32 table_count;
	int i;

	/* map table header, verify length */
	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
	if (!table)
		return AE_NO_MEMORY;

	length = table->length; /* length of entire table, incl header */
	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
	if (length < sizeof(struct acpi_table_header))
		return AE_INVALID_TABLE_LENGTH;

	/* map entire table, not just header */
	table = acpi_os_map_memory(address, length);
	if (!table)
		return AE_NO_MEMORY;

	/* Calculate the number of tables described in XSDT */
	table_count =
		(u32) ((table->length -
		sizeof(struct acpi_table_header)) / sizeof(u64));
	table_entry =
		ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
	for (i = 0; i < table_count; i++) {
		ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
		if (!xsdt_entry_address) {
			/* XSDT has NULL entry */
			break;
		}
		table_entry += sizeof(u64);
	}
	acpi_os_unmap_memory(table, length);

	if (i < table_count)
		return AE_NULL_ENTRY;
	else
		return AE_OK;
}
Exemple #9
0
static acpi_status
acpi_table_initrd_override(struct acpi_table_header *existing_table,
			   acpi_physical_address *address, u32 *length)
{
	int table_offset = 0;
	int table_index = 0;
	struct acpi_table_header *table;
	u32 table_length;

	*length = 0;
	*address = 0;
	if (!acpi_tables_addr)
		return AE_OK;

	while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
		table = acpi_os_map_memory(acpi_tables_addr + table_offset,
					   ACPI_HEADER_SIZE);
		if (table_offset + table->length > all_tables_size) {
			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
			WARN_ON(1);
			return AE_OK;
		}

		table_length = table->length;

		/* Only override tables matched */
		if (memcmp(existing_table->signature, table->signature, 4) ||
		    memcmp(table->oem_id, existing_table->oem_id,
			   ACPI_OEM_ID_SIZE) ||
		    memcmp(table->oem_table_id, existing_table->oem_table_id,
			   ACPI_OEM_TABLE_ID_SIZE)) {
			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
			goto next_table;
		}
		/*
		 * Mark the table to avoid being used in
		 * acpi_table_initrd_scan() and check the revision.
		 */
		if (test_and_set_bit(table_index, acpi_initrd_installed) ||
		    existing_table->oem_revision >= table->oem_revision) {
			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
			goto next_table;
		}

		*length = table_length;
		*address = acpi_tables_addr + table_offset;
		pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s]\n",
			table->signature, table->oem_id,
			table->oem_table_id);
		acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
		break;

next_table:
		table_offset += table_length;
		table_index++;
	}
	return AE_OK;
}
Exemple #10
0
void acpi_tb_parse_fadt(u32 table_index)
{
	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);

	/* Create 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_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
				    ACPI_SIG_DSDT, &acpi_gbl_dsdt_index);

	/* If Hardware Reduced flag is set, there is no FACS */

	if (!acpi_gbl_reduced_hardware) {
		if (acpi_gbl_FADT.facs) {
			acpi_tb_install_fixed_table((acpi_physical_address)
						    acpi_gbl_FADT.facs,
						    ACPI_SIG_FACS,
						    &acpi_gbl_facs_index);
		}
		if (acpi_gbl_FADT.Xfacs) {
			acpi_tb_install_fixed_table((acpi_physical_address)
						    acpi_gbl_FADT.Xfacs,
						    ACPI_SIG_FACS,
						    &acpi_gbl_xfacs_index);
		}
	}
}
static acpi_status
acpi_tb_check_xsdt(acpi_physical_address address)
{
	struct acpi_table_header *table;
	u32 length;
	u64 xsdt_entry_address;
	u8 *table_entry;
	u32 table_count;
	int i;

	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
	if (!table)
		return AE_NO_MEMORY;

	length = table->length;
	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
	if (length < sizeof(struct acpi_table_header))
		return AE_INVALID_TABLE_LENGTH;

	table = acpi_os_map_memory(address, length);
	if (!table)
		return AE_NO_MEMORY;

	
	table_count =
		(u32) ((table->length -
		sizeof(struct acpi_table_header)) / sizeof(u64));
	table_entry =
		ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
	for (i = 0; i < table_count; i++) {
		ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
		if (!xsdt_entry_address) {
			
			break;
		}
		table_entry += sizeof(u64);
	}
	acpi_os_unmap_memory(table, length);

	if (i < table_count)
		return AE_NULL_ENTRY;
	else
		return AE_OK;
}
Exemple #12
0
static void __init acpi_table_initrd_scan(void)
{
	int table_offset = 0;
	int table_index = 0;
	u32 table_length;
	struct acpi_table_header *table;

	if (!acpi_tables_addr)
		return;

	while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
		table = acpi_os_map_memory(acpi_tables_addr + table_offset,
					   ACPI_HEADER_SIZE);
		if (table_offset + table->length > all_tables_size) {
			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
			WARN_ON(1);
			return;
		}

		table_length = table->length;

		/* Skip RSDT/XSDT which should only be used for override */
		if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
		    ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) {
			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
			goto next_table;
		}
		/*
		 * Mark the table to avoid being used in
		 * acpi_table_initrd_override(). Though this is not possible
		 * because override is disabled in acpi_install_table().
		 */
		if (test_and_set_bit(table_index, acpi_initrd_installed)) {
			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
			goto next_table;
		}

		pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n",
			table->signature, table->oem_id,
			table->oem_table_id);
		acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
		acpi_install_table(acpi_tables_addr + table_offset, TRUE);
next_table:
		table_offset += table_length;
		table_index++;
	}
}
Exemple #13
0
acpi_status
acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc,
			   acpi_physical_address address, u8 flags)
{
	struct acpi_table_header *table_header;

	switch (flags & ACPI_TABLE_ORIGIN_MASK) {
	case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:

		/* Get the length of the full table from the header */

		table_header =
		    acpi_os_map_memory(address,
				       sizeof(struct acpi_table_header));
		if (!table_header) {
			return (AE_NO_MEMORY);
		}

		acpi_tb_init_table_descriptor(table_desc, address, flags,
					      table_header);
		acpi_os_unmap_memory(table_header,
				     sizeof(struct acpi_table_header));
		return (AE_OK);

	case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
	case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:

		table_header = ACPI_CAST_PTR(struct acpi_table_header,
					     ACPI_PHYSADDR_TO_PTR(address));
		if (!table_header) {
			return (AE_NO_MEMORY);
		}

		acpi_tb_init_table_descriptor(table_desc, address, flags,
					      table_header);
		return (AE_OK);

	default:

		break;
	}

	/* Table is not valid yet */

	return (AE_NO_MEMORY);
}
Exemple #14
0
static acpi_status osl_load_rsdp(void)
{
	struct acpi_table_header *mapped_table;
	u8 *rsdp_address;
	acpi_physical_address rsdp_base;
	acpi_size rsdp_size;

	/* Get RSDP from memory */

	rsdp_size = sizeof(struct acpi_table_rsdp);
	if (gbl_rsdp_base) {
		rsdp_base = gbl_rsdp_base;
	} else {
		rsdp_base = osl_find_rsdp_via_efi();
	}

	if (!rsdp_base) {
		rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
		rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
	}

	rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
	if (!rsdp_address) {
		return (osl_get_last_status(AE_BAD_ADDRESS));
	}

	/* Search low memory for the RSDP */

	mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
				     acpi_tb_scan_memory_for_rsdp(rsdp_address,
								  rsdp_size));
	if (!mapped_table) {
		acpi_os_unmap_memory(rsdp_address, rsdp_size);
		return (AE_NOT_FOUND);
	}

	gbl_rsdp_address =
	    rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);

	memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));
	acpi_os_unmap_memory(rsdp_address, rsdp_size);

	return (AE_OK);
}
void __init 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);
}
Exemple #16
0
int acpi_os_map_generic_address(struct acpi_generic_address *gas)
{
	u64 addr;
	void __iomem *virt;

	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
		return 0;

	/* Handle possible alignment issues */
	memcpy(&addr, &gas->address, sizeof(addr));
	if (!addr || !gas->bit_width)
		return -EINVAL;

	virt = acpi_os_map_memory(addr, gas->bit_width / 8);
	if (!virt)
		return -EIO;

	return 0;
}
struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
						 *table_header,
						 struct acpi_table_desc
						 *table_desc)
{
	acpi_status status;
	struct acpi_table_header *new_table = NULL;
	acpi_physical_address new_address = 0;
	u32 new_table_length = 0;
	u8 new_flags;
	char *override_type;

	/* (1) Attempt logical override (returns a logical address) */

	status = acpi_os_table_override(table_header, &new_table);
	if (ACPI_SUCCESS(status) && new_table) {
		new_address = ACPI_PTR_TO_PHYSADDR(new_table);
		new_table_length = new_table->length;
		new_flags = ACPI_TABLE_ORIGIN_OVERRIDE;
		override_type = "Logical";
		goto finish_override;
	}

	/* (2) Attempt physical override (returns a physical address) */

	status = acpi_os_physical_table_override(table_header,
						 &new_address,
						 &new_table_length);
	if (ACPI_SUCCESS(status) && new_address && new_table_length) {

		/* Map the entire new table */

		new_table = acpi_os_map_memory(new_address, new_table_length);
		if (!new_table) {
			ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
					"%4.4s %p Attempted physical table override failed",
					table_header->signature,
					ACPI_CAST_PTR(void,
						      table_desc->address)));
			return (NULL);
		}
Exemple #18
0
acpi_status
acpi_tb_acquire_table(struct acpi_table_desc *table_desc,
		      struct acpi_table_header **table_ptr,
		      u32 *table_length, u8 *table_flags)
{
	struct acpi_table_header *table = NULL;

	switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
	case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:

		table =
		    acpi_os_map_memory(table_desc->address, table_desc->length);
		break;

	case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
	case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:

		table = ACPI_CAST_PTR(struct acpi_table_header,
				      ACPI_PHYSADDR_TO_PTR(table_desc->
							   address));
		break;

	default:

		break;
	}

	/* Table is not valid yet */

	if (!table) {
		return (AE_NO_MEMORY);
	}

	/* Fill the return values */

	*table_ptr = table;
	*table_length = table_desc->length;
	*table_flags = table_desc->flags;
	return (AE_OK);
}
Exemple #19
0
void
acpi_tb_install_table(acpi_physical_address address,
		      char *signature, u32 table_index)
{
	struct acpi_table_header *table;
	struct acpi_table_header *final_table;
	struct acpi_table_desc *table_desc;

	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) {
		ACPI_ERROR((AE_INFO,
			    "Could not map memory for table [%s] at %p",
			    signature, ACPI_CAST_PTR(void, address)));
		return;
	}
Exemple #20
0
acpi_status
acpi_os_physical_table_override(struct acpi_table_header *existing_table,
				acpi_physical_address *address,
				u32 *table_length)
{
#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
	*table_length = 0;
	*address = 0;
	return AE_OK;
#else
	int table_offset = 0;
	struct acpi_table_header *table;

	*table_length = 0;
	*address = 0;

	if (!acpi_tables_addr)
		return AE_OK;

	do {
		if (table_offset + ACPI_HEADER_SIZE > all_tables_size) {
			WARN_ON(1);
			return AE_OK;
		}

		table = acpi_os_map_memory(acpi_tables_addr + table_offset,
					   ACPI_HEADER_SIZE);

		if (table_offset + table->length > all_tables_size) {
			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
			WARN_ON(1);
			return AE_OK;
		}

		table_offset += table->length;

		if (memcmp(existing_table->signature, table->signature, 4)) {
			acpi_os_unmap_memory(table,
				     ACPI_HEADER_SIZE);
			continue;
		}

		/* Only override tables with matching oem id */
		if (memcmp(table->oem_table_id, existing_table->oem_table_id,
			   ACPI_OEM_TABLE_ID_SIZE)) {
			acpi_os_unmap_memory(table,
				     ACPI_HEADER_SIZE);
			continue;
		}

		table_offset -= table->length;
		*table_length = table->length;
		acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
		*address = acpi_tables_addr + table_offset;
		break;
	} while (table_offset + ACPI_HEADER_SIZE < all_tables_size);

	if (*address != 0)
		acpi_table_taint(existing_table);
	return AE_OK;
#endif
}
Exemple #21
0
static 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);
}
acpi_status
acpi_ex_system_memory_space_handler (
	u32                     function,
	ACPI_PHYSICAL_ADDRESS   address,
	u32                     bit_width,
	u32                     *value,
	void                    *handler_context,
	void                    *region_context)
{
	acpi_status             status = AE_OK;
	void                    *logical_addr_ptr = NULL;
	acpi_mem_space_context  *mem_info = region_context;
	u32                     length;


	FUNCTION_TRACE ("Ex_system_memory_space_handler");


	/* Validate and translate the bit width */

	switch (bit_width) {
	case 8:
		length = 1;
		break;

	case 16:
		length = 2;
		break;

	case 32:
		length = 4;
		break;

	default:
		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid System_memory width %d\n",
			bit_width));
		return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
		break;
	}


	/*
	 * Does the request fit into the cached memory mapping?
	 * Is 1) Address below the current mapping? OR
	 *    2) Address beyond the current mapping?
	 */
	if ((address < mem_info->mapped_physical_address) ||
		(((acpi_integer) address + length) >
			((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) {
		/*
		 * The request cannot be resolved by the current memory mapping;
		 * Delete the existing mapping and create a new one.
		 */
		if (mem_info->mapped_length) {
			/* Valid mapping, delete it */

			acpi_os_unmap_memory (mem_info->mapped_logical_address,
					   mem_info->mapped_length);
		}

		mem_info->mapped_length = 0; /* In case of failure below */

		/* Create a new mapping starting at the address given */

		status = acpi_os_map_memory (address, SYSMEM_REGION_WINDOW_SIZE,
				  (void **) &mem_info->mapped_logical_address);
		if (ACPI_FAILURE (status)) {
			return_ACPI_STATUS (status);
		}

		/* Save the physical address and mapping size */

		mem_info->mapped_physical_address = address;
		mem_info->mapped_length = SYSMEM_REGION_WINDOW_SIZE;
	}


	/*
	 * Generate a logical pointer corresponding to the address we want to
	 * access
	 */

	/* TBD: should these pointers go to 64-bit in all cases ? */

	logical_addr_ptr = mem_info->mapped_logical_address +
			  ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address);

	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
		"System_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width,
		HIDWORD (address), LODWORD (address)));

   /* Perform the memory read or write */

	switch (function) {

	case ACPI_READ_ADR_SPACE:

		switch (bit_width) {
		case 8:
			*value = (u32)* (u8 *) logical_addr_ptr;
			break;

		case 16:
			MOVE_UNALIGNED16_TO_32 (value, logical_addr_ptr);
			break;

		case 32:
			MOVE_UNALIGNED32_TO_32 (value, logical_addr_ptr);
			break;
		}

		break;


	case ACPI_WRITE_ADR_SPACE:

		switch (bit_width) {
		case 8:
			*(u8 *) logical_addr_ptr = (u8) *value;
			break;

		case 16:
			MOVE_UNALIGNED16_TO_16 (logical_addr_ptr, value);
			break;

		case 32:
			MOVE_UNALIGNED32_TO_32 (logical_addr_ptr, value);
			break;
		}

		break;


	default:
		status = AE_BAD_PARAMETER;
		break;
	}

	return_ACPI_STATUS (status);
}
Exemple #23
0
static int __init pvh_setup_acpi(struct domain *d, paddr_t start_info)
{
    unsigned long pfn, nr_pages;
    paddr_t madt_paddr, xsdt_paddr, rsdp_paddr;
    unsigned int i;
    int rc;
    struct acpi_table_rsdp *native_rsdp, rsdp = {
        .signature = ACPI_SIG_RSDP,
        .revision = 2,
        .length = sizeof(rsdp),
    };


    /* Scan top-level tables and add their regions to the guest memory map. */
    for( i = 0; i < acpi_gbl_root_table_list.count; i++ )
    {
        const char *sig = acpi_gbl_root_table_list.tables[i].signature.ascii;
        unsigned long addr = acpi_gbl_root_table_list.tables[i].address;
        unsigned long size = acpi_gbl_root_table_list.tables[i].length;

        /*
         * Make sure the original MADT is also mapped, so that Dom0 can
         * properly access the data returned by _MAT methods in case it's
         * re-using MADT memory.
         */
        if ( strncmp(sig, ACPI_SIG_MADT, ACPI_NAME_SIZE)
             ? pvh_acpi_table_allowed(sig)
             : !acpi_memory_banned(addr, size) )
             pvh_add_mem_range(d, addr, addr + size, E820_ACPI);
    }

    /* Identity map ACPI e820 regions. */
    for ( i = 0; i < d->arch.nr_e820; i++ )
    {
        if ( d->arch.e820[i].type != E820_ACPI &&
             d->arch.e820[i].type != E820_NVS )
            continue;

        pfn = PFN_DOWN(d->arch.e820[i].addr);
        nr_pages = PFN_UP((d->arch.e820[i].addr & ~PAGE_MASK) +
                          d->arch.e820[i].size);

        rc = modify_identity_mmio(d, pfn, nr_pages, true);
        if ( rc )
        {
            printk("Failed to map ACPI region [%#lx, %#lx) into Dom0 memory map\n",
                   pfn, pfn + nr_pages);
            return rc;
        }
    }

    rc = pvh_setup_acpi_madt(d, &madt_paddr);
    if ( rc )
        return rc;

    rc = pvh_setup_acpi_xsdt(d, madt_paddr, &xsdt_paddr);
    if ( rc )
        return rc;

    /* Craft a custom RSDP. */
    native_rsdp = acpi_os_map_memory(acpi_os_get_root_pointer(), sizeof(rsdp));
    if ( !native_rsdp )
    {
        printk("Failed to map native RSDP\n");
        return -ENOMEM;
    }
    memcpy(rsdp.oem_id, native_rsdp->oem_id, sizeof(rsdp.oem_id));
    acpi_os_unmap_memory(native_rsdp, sizeof(rsdp));
    rsdp.xsdt_physical_address = xsdt_paddr;
    /*
     * Calling acpi_tb_checksum here is a layering violation, but
     * introducing a wrapper for such simple usage seems overkill.
     */
    rsdp.checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, &rsdp),
                                      ACPI_RSDP_REV0_SIZE);
    rsdp.extended_checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, &rsdp),
                                               sizeof(rsdp));

    /*
     * Place the new RSDP in guest memory space.
     *
     * NB: this RSDP is not going to replace the original RSDP, which should
     * still be accessible to the guest. However that RSDP is going to point to
     * the native RSDT, and should not be used for the Dom0 kernel's boot
     * purposes (we keep it visible for post boot access).
     */
    if ( pvh_steal_ram(d, sizeof(rsdp), 0, GB(4), &rsdp_paddr) )
    {
        printk("Unable to allocate guest RAM for RSDP\n");
        return -ENOMEM;
    }

    /* Mark this region as E820_ACPI. */
    if ( pvh_add_mem_range(d, rsdp_paddr, rsdp_paddr + sizeof(rsdp),
                           E820_ACPI) )
        printk("Unable to add RSDP region to memory map\n");

    /* Copy RSDP into guest memory. */
    rc = hvm_copy_to_guest_phys(rsdp_paddr, &rsdp, sizeof(rsdp), d->vcpu[0]);
    if ( rc )
    {
        printk("Unable to copy RSDP into guest memory\n");
        return rc;
    }

    /* Copy RSDP address to start_info. */
    rc = hvm_copy_to_guest_phys(start_info +
                                offsetof(struct hvm_start_info, rsdp_paddr),
                                &rsdp_paddr,
                                sizeof(((struct hvm_start_info *)
                                        0)->rsdp_paddr),
                                d->vcpu[0]);
    if ( rc )
    {
        printk("Unable to copy RSDP into guest memory\n");
        return rc;
    }

    return 0;
}

int __init dom0_construct_pvh(struct domain *d, const module_t *image,
                              unsigned long image_headroom,
                              module_t *initrd,
                              void *(*bootstrap_map)(const module_t *),
                              char *cmdline)
{
    paddr_t entry, start_info;
    int rc;

    printk("** Building a PVH Dom0 **\n");

    iommu_hwdom_init(d);

    rc = pvh_setup_p2m(d);
    if ( rc )
    {
        printk("Failed to setup Dom0 physical memory map\n");
        return rc;
    }

    rc = pvh_load_kernel(d, image, image_headroom, initrd, bootstrap_map(image),
                         cmdline, &entry, &start_info);
    if ( rc )
    {
        printk("Failed to load Dom0 kernel\n");
        return rc;
    }

    rc = pvh_setup_cpus(d, entry, start_info);
    if ( rc )
    {
        printk("Failed to setup Dom0 CPUs: %d\n", rc);
        return rc;
    }

    rc = pvh_setup_acpi(d, start_info);
    if ( rc )
    {
        printk("Failed to setup Dom0 ACPI tables: %d\n", rc);
        return rc;
    }

    panic("Building a PVHv2 Dom0 is not yet supported.");
    return 0;
}
Exemple #24
0
static int __init pvh_setup_acpi_xsdt(struct domain *d, paddr_t madt_addr,
                                      paddr_t *addr)
{
    struct acpi_table_xsdt *xsdt;
    struct acpi_table_header *table;
    struct acpi_table_rsdp *rsdp;
    unsigned long size = sizeof(*xsdt);
    unsigned int i, j, num_tables = 0;
    paddr_t xsdt_paddr;
    int rc;

    /*
     * Restore original DMAR table signature, we are going to filter it from
     * the new XSDT that is presented to the guest, so it is no longer
     * necessary to have it's signature zapped.
     */
    acpi_dmar_reinstate();

    /* Count the number of tables that will be added to the XSDT. */
    for( i = 0; i < acpi_gbl_root_table_list.count; i++ )
    {
        const char *sig = acpi_gbl_root_table_list.tables[i].signature.ascii;

        if ( pvh_acpi_table_allowed(sig) )
            num_tables++;
    }

    /*
     * No need to add or subtract anything because struct acpi_table_xsdt
     * includes one array slot already, and we have filtered out the original
     * MADT and we are going to add a custom built MADT.
     */
    size += num_tables * sizeof(xsdt->table_offset_entry[0]);

    xsdt = xzalloc_bytes(size);
    if ( !xsdt )
    {
        printk("Unable to allocate memory for XSDT table\n");
        rc = -ENOMEM;
        goto out;
    }

    /* Copy the native XSDT table header. */
    rsdp = acpi_os_map_memory(acpi_os_get_root_pointer(), sizeof(*rsdp));
    if ( !rsdp )
    {
        printk("Unable to map RSDP\n");
        rc = -EINVAL;
        goto out;
    }
    xsdt_paddr = rsdp->xsdt_physical_address;
    acpi_os_unmap_memory(rsdp, sizeof(*rsdp));
    table = acpi_os_map_memory(xsdt_paddr, sizeof(*table));
    if ( !table )
    {
        printk("Unable to map XSDT\n");
        rc = -EINVAL;
        goto out;
    }
    xsdt->header = *table;
    acpi_os_unmap_memory(table, sizeof(*table));

    /* Add the custom MADT. */
    xsdt->table_offset_entry[0] = madt_addr;

    /* Copy the addresses of the rest of the allowed tables. */
    for( i = 0, j = 1; i < acpi_gbl_root_table_list.count; i++ )
    {
        const char *sig = acpi_gbl_root_table_list.tables[i].signature.ascii;

        if ( pvh_acpi_table_allowed(sig) )
            xsdt->table_offset_entry[j++] =
                acpi_gbl_root_table_list.tables[i].address;
    }

    xsdt->header.revision = 1;
    xsdt->header.length = size;
    /*
     * Calling acpi_tb_checksum here is a layering violation, but
     * introducing a wrapper for such simple usage seems overkill.
     */
    xsdt->header.checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, xsdt), size);

    /* Place the new XSDT in guest memory space. */
    if ( pvh_steal_ram(d, size, 0, GB(4), addr) )
    {
        printk("Unable to find guest RAM for XSDT\n");
        rc = -ENOMEM;
        goto out;
    }

    /* Mark this region as E820_ACPI. */
    if ( pvh_add_mem_range(d, *addr, *addr + size, E820_ACPI) )
        printk("Unable to add XSDT region to memory map\n");

    rc = hvm_copy_to_guest_phys(*addr, xsdt, size, d->vcpu[0]);
    if ( rc )
    {
        printk("Unable to copy XSDT into guest memory\n");
        goto out;
    }

    rc = 0;

 out:
    xfree(xsdt);

    return rc;
}
Exemple #25
0
acpi_status
acpi_ex_system_memory_space_handler (
	u32                             function,
	acpi_physical_address           address,
	u32                             bit_width,
	acpi_integer                    *value,
	void                            *handler_context,
	void                            *region_context)
{
	acpi_status                     status = AE_OK;
	void                            *logical_addr_ptr = NULL;
	struct acpi_mem_space_context   *mem_info = region_context;
	u32                             length;
	acpi_size                       window_size;
#ifndef ACPI_MISALIGNED_TRANSFERS
	u32                             remainder;
#endif

	ACPI_FUNCTION_TRACE ("ex_system_memory_space_handler");


	/* Validate and translate the bit width */

	switch (bit_width) {
	case 8:
		length = 1;
		break;

	case 16:
		length = 2;
		break;

	case 32:
		length = 4;
		break;

	case 64:
		length = 8;
		break;

	default:
		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid system_memory width %d\n",
			bit_width));
		return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
	}


#ifndef ACPI_MISALIGNED_TRANSFERS
	/*
	 * Hardware does not support non-aligned data transfers, we must verify
	 * the request.
	 */
	(void) acpi_ut_short_divide ((acpi_integer) address, length, NULL, &remainder);
	if (remainder != 0) {
		return_ACPI_STATUS (AE_AML_ALIGNMENT);
	}
#endif

	/*
	 * Does the request fit into the cached memory mapping?
	 * Is 1) Address below the current mapping? OR
	 *    2) Address beyond the current mapping?
	 */
	if ((address < mem_info->mapped_physical_address) ||
		(((acpi_integer) address + length) >
			((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) {
		/*
		 * The request cannot be resolved by the current memory mapping;
		 * Delete the existing mapping and create a new one.
		 */
		if (mem_info->mapped_length) {
			/* Valid mapping, delete it */

			acpi_os_unmap_memory (mem_info->mapped_logical_address,
					   mem_info->mapped_length);
		}

		/*
		 * Don't attempt to map memory beyond the end of the region, and
		 * constrain the maximum mapping size to something reasonable.
		 */
		window_size = (acpi_size) ((mem_info->address + mem_info->length) - address);
		if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) {
			window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE;
		}

		/* Create a new mapping starting at the address given */

		status = acpi_os_map_memory (address, window_size,
				  (void **) &mem_info->mapped_logical_address);
		if (ACPI_FAILURE (status)) {
			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n",
					ACPI_FORMAT_UINT64 (address), (u32) window_size));
			mem_info->mapped_length = 0;
			return_ACPI_STATUS (status);
		}

		/* Save the physical address and mapping size */

		mem_info->mapped_physical_address = address;
		mem_info->mapped_length = window_size;
	}

	/*
	 * Generate a logical pointer corresponding to the address we want to
	 * access
	 */
	logical_addr_ptr = mem_info->mapped_logical_address +
			  ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address);

	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
			"system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width,
			ACPI_FORMAT_UINT64 (address)));

   /*
	* Perform the memory read or write
	*
	* Note: For machines that do not support non-aligned transfers, the target
	* address was checked for alignment above.  We do not attempt to break the
	* transfer up into smaller (byte-size) chunks because the AML specifically
	* asked for a transfer width that the hardware may require.
	*/
	switch (function) {
	case ACPI_READ:

		*value = 0;
		switch (bit_width) {
		case 8:
			*value = (acpi_integer) *((u8 *) logical_addr_ptr);
			break;

		case 16:
			*value = (acpi_integer) *((u16 *) logical_addr_ptr);
			break;

		case 32:
			*value = (acpi_integer) *((u32 *) logical_addr_ptr);
			break;

#if ACPI_MACHINE_WIDTH != 16
		case 64:
			*value = (acpi_integer) *((u64 *) logical_addr_ptr);
			break;
#endif
		default:
			/* bit_width was already validated */
			break;
		}
		break;

	case ACPI_WRITE:

		switch (bit_width) {
		case 8:
			*(u8 *) logical_addr_ptr = (u8) *value;
			break;

		case 16:
			*(u16 *) logical_addr_ptr = (u16) *value;
			break;

		case 32:
			*(u32 *) logical_addr_ptr = (u32) *value;
			break;

#if ACPI_MACHINE_WIDTH != 16
		case 64:
			*(u64 *) logical_addr_ptr = (u64) *value;
			break;
#endif

		default:
			/* bit_width was already validated */
			break;
		}
		break;

	default:
		status = AE_BAD_PARAMETER;
		break;
	}

	return_ACPI_STATUS (status);
}
acpi_status acpi_find_root_pointer(acpi_size *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 0x%8.8X for length %u",
			    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 1K length)
		 */
		table_ptr = acpi_os_map_memory((acpi_physical_address)
					       physical_address,
					       ACPI_EBDA_WINDOW_SIZE);
		if (!table_ptr) {
			ACPI_ERROR((AE_INFO,
				    "Could not map memory at 0x%8.8X for length %u",
				    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 0x%8.8X for length %u",
			    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_BIOS_ERROR((AE_INFO, "A valid RSDP was not found"));
	return_ACPI_STATUS(AE_NOT_FOUND);
}
Exemple #27
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_system_memory_space_handler
 *
 * PARAMETERS:  Function            - Read or Write operation
 *              Address             - Where in the space to read or write
 *              bit_width           - Field width in bits (8, 16, or 32)
 *              Value               - Pointer to in or out value
 *              handler_context     - Pointer to Handler's context
 *              region_context      - Pointer to context specific to the
 *                                    accessed region
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Handler for the System Memory address space (Op Region)
 *
 ******************************************************************************/
acpi_status
acpi_ex_system_memory_space_handler(u32 function,
				    acpi_physical_address address,
				    u32 bit_width,
				    u64 *value,
				    void *handler_context, void *region_context)
{
	acpi_status status = AE_OK;
	void *logical_addr_ptr = NULL;
	struct acpi_mem_space_context *mem_info = region_context;
	u32 length;
	acpi_size map_length;
	acpi_size page_boundary_map_length;
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
	u32 remainder;
#endif

	ACPI_FUNCTION_TRACE(ex_system_memory_space_handler);

	/* Validate and translate the bit width */

	switch (bit_width) {
	case 8:
		length = 1;
		break;

	case 16:
		length = 2;
		break;

	case 32:
		length = 4;
		break;

	case 64:
		length = 8;
		break;

	default:
		ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u",
			    bit_width));
		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
	}

#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
	/*
	 * Hardware does not support non-aligned data transfers, we must verify
	 * the request.
	 */
	(void)acpi_ut_short_divide((u64) address, length, NULL, &remainder);
	if (remainder != 0) {
		return_ACPI_STATUS(AE_AML_ALIGNMENT);
	}
#endif

	/*
	 * Does the request fit into the cached memory mapping?
	 * Is 1) Address below the current mapping? OR
	 *    2) Address beyond the current mapping?
	 */
	if ((address < mem_info->mapped_physical_address) ||
	    (((u64) address + length) > ((u64)
					 mem_info->mapped_physical_address +
					 mem_info->mapped_length))) {
		/*
		 * The request cannot be resolved by the current memory mapping;
		 * Delete the existing mapping and create a new one.
		 */
		if (mem_info->mapped_length) {

			/* Valid mapping, delete it */

			acpi_os_unmap_memory(mem_info->mapped_logical_address,
					     mem_info->mapped_length);
		}

		/*
		 * Attempt to map from the requested address to the end of the region.
		 * However, we will never map more than one page, nor will we cross
		 * a page boundary.
		 */
		map_length = (acpi_size)
		    ((mem_info->address + mem_info->length) - address);

		/*
		 * If mapping the entire remaining portion of the region will cross
		 * a page boundary, just map up to the page boundary, do not cross.
		 * On some systems, crossing a page boundary while mapping regions
		 * can cause warnings if the pages have different attributes
		 * due to resource management
		 */
		page_boundary_map_length =
		    ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address;

		if (!page_boundary_map_length) {
			page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
		}

		if (map_length > page_boundary_map_length) {
			map_length = page_boundary_map_length;
		}

		/* Create a new mapping starting at the address given */

		mem_info->mapped_logical_address = acpi_os_map_memory((acpi_physical_address) address, map_length);
		if (!mem_info->mapped_logical_address) {
			ACPI_ERROR((AE_INFO,
				    "Could not map memory at 0x%8.8X%8.8X, size %u",
				    ACPI_FORMAT_NATIVE_UINT(address),
				    (u32) map_length));
			mem_info->mapped_length = 0;
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		/* Save the physical address and mapping size */

		mem_info->mapped_physical_address = address;
		mem_info->mapped_length = map_length;
	}

	/*
	 * Generate a logical pointer corresponding to the address we want to
	 * access
	 */
	logical_addr_ptr = mem_info->mapped_logical_address +
	    ((u64) address - (u64) mem_info->mapped_physical_address);

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
			  bit_width, function,
			  ACPI_FORMAT_NATIVE_UINT(address)));

	/*
	 * Perform the memory read or write
	 *
	 * Note: For machines that do not support non-aligned transfers, the target
	 * address was checked for alignment above.  We do not attempt to break the
	 * transfer up into smaller (byte-size) chunks because the AML specifically
	 * asked for a transfer width that the hardware may require.
	 */
	switch (function) {
	case ACPI_READ:

		*value = 0;
		switch (bit_width) {
		case 8:
			*value = (u64) ACPI_GET8(logical_addr_ptr);
			break;

		case 16:
			*value = (u64) ACPI_GET16(logical_addr_ptr);
			break;

		case 32:
			*value = (u64) ACPI_GET32(logical_addr_ptr);
			break;

		case 64:
			*value = (u64) ACPI_GET64(logical_addr_ptr);
			break;

		default:
			/* bit_width was already validated */
			break;
		}
		break;

	case ACPI_WRITE:

		switch (bit_width) {
		case 8:
			ACPI_SET8(logical_addr_ptr) = (u8) * value;
			break;

		case 16:
			ACPI_SET16(logical_addr_ptr) = (u16) * value;
			break;

		case 32:
			ACPI_SET32(logical_addr_ptr) = (u32) * value;
			break;

		case 64:
			ACPI_SET64(logical_addr_ptr) = (u64) * value;
			break;

		default:
			/* bit_width was already validated */
			break;
		}
		break;

	default:
		status = AE_BAD_PARAMETER;
		break;
	}

	return_ACPI_STATUS(status);
}
acpi_status
acpi_tb_find_rsdp (
	struct acpi_table_desc          *table_info,
	u32                             flags)
{
	u8                              *table_ptr;
	u8                              *mem_rover;
	u64                             phys_addr;
	acpi_status                     status = AE_OK;


	ACPI_FUNCTION_TRACE ("tb_find_rsdp");


	/*
	 * Scan supports either 1) Logical addressing or 2) Physical addressing
	 */
	if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
		/*
		 * 1) Search EBDA (low memory) paragraphs
		 */
		status = acpi_os_map_memory ((u64) ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE,
				  (void *) &table_ptr);
		if (ACPI_FAILURE (status)) {
			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n",
				ACPI_LO_RSDP_WINDOW_BASE, ACPI_LO_RSDP_WINDOW_SIZE));
			return_ACPI_STATUS (status);
		}

		mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE);
		acpi_os_unmap_memory (table_ptr, ACPI_LO_RSDP_WINDOW_SIZE);

		if (mem_rover) {
			/* Found it, return the physical address */

			phys_addr = ACPI_LO_RSDP_WINDOW_BASE;
			phys_addr += ACPI_PTR_DIFF (mem_rover,table_ptr);

			table_info->physical_address = phys_addr;
			return_ACPI_STATUS (AE_OK);
		}

		/*
		 * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h
		 */
		status = acpi_os_map_memory ((u64) 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 %X 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 */

			phys_addr = ACPI_HI_RSDP_WINDOW_BASE;
			phys_addr += ACPI_PTR_DIFF (mem_rover, table_ptr);

			table_info->physical_address = phys_addr;
			return_ACPI_STATUS (AE_OK);
		}
	}

	/*
	 * Physical addressing
	 */
	else {
		/*
		 * 1) Search EBDA (low memory) paragraphs
		 */
		mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_LO_RSDP_WINDOW_BASE),
				  ACPI_LO_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);
		}

		/*
		 * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h
		 */
		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);
}
acpi_status
acpi_get_firmware_table (
	acpi_string                     signature,
	u32                             instance,
	u32                             flags,
	struct acpi_table_header        **table_pointer)
{
	struct acpi_pointer             rsdp_address;
	struct acpi_pointer             address;
	acpi_status                     status;
	struct acpi_table_header        header;
	struct acpi_table_desc          table_info;
	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);
	}

	rsdt_info.pointer = NULL;

	if (!acpi_gbl_RSDP) {
		/* Get the RSDP */

		status = acpi_os_get_root_pointer (flags, &rsdp_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 (rsdp_address.pointer.physical, sizeof (struct rsdp_descriptor),
					  (void *) &acpi_gbl_RSDP);
			if (ACPI_FAILURE (status)) {
				return_ACPI_STATUS (status);
			}
		}
		else {
			acpi_gbl_RSDP = 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 and validate it */

	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_HIDWORD (address.pointer.value),
		ACPI_LODWORD (address.pointer.value)));

	/* Insert processor_mode flags */

	address.pointer_type |= flags;

	status = acpi_tb_get_table (&address, &rsdt_info);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	status = acpi_tb_validate_rsdt (rsdt_info.pointer);
	if (ACPI_FAILURE (status)) {
		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 = ((RSDT_DESCRIPTOR *) rsdt_info.pointer)->table_offset_entry[i];
		}
		else {
			address.pointer.value =
				((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);
	return_ACPI_STATUS (status);
}
static int __init extlog_init(void)
{
	struct extlog_l1_head *l1_head;
	void __iomem *extlog_l1_hdr;
	size_t l1_hdr_size;
	struct resource *r;
	u64 cap;
	int rc;

	rc = -ENODEV;

	rdmsrl(MSR_IA32_MCG_CAP, cap);
	if (!(cap & MCG_ELOG_P))
		return rc;

	if (!extlog_get_l1addr())
		return rc;

	rc = -EINVAL;
	/* get L1 header to fetch necessary information */
	l1_hdr_size = sizeof(struct extlog_l1_head);
	r = request_mem_region(l1_dirbase, l1_hdr_size, "L1 DIR HDR");
	if (!r) {
		pr_warn(FW_BUG EMCA_BUG,
			(unsigned long long)l1_dirbase,
			(unsigned long long)l1_dirbase + l1_hdr_size);
		goto err;
	}

	extlog_l1_hdr = acpi_os_map_memory(l1_dirbase, l1_hdr_size);
	l1_head = (struct extlog_l1_head *)extlog_l1_hdr;
	l1_size = l1_head->total_len;
	l1_percpu_entry = l1_head->entries;
	elog_base = l1_head->elog_base;
	elog_size = l1_head->elog_len;
	acpi_os_unmap_memory(extlog_l1_hdr, l1_hdr_size);
	release_mem_region(l1_dirbase, l1_hdr_size);

	/* remap L1 header again based on completed information */
	r = request_mem_region(l1_dirbase, l1_size, "L1 Table");
	if (!r) {
		pr_warn(FW_BUG EMCA_BUG,
			(unsigned long long)l1_dirbase,
			(unsigned long long)l1_dirbase + l1_size);
		goto err;
	}
	extlog_l1_addr = acpi_os_map_memory(l1_dirbase, l1_size);
	l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size);

	/* remap elog table */
	r = request_mem_region(elog_base, elog_size, "Elog Table");
	if (!r) {
		pr_warn(FW_BUG EMCA_BUG,
			(unsigned long long)elog_base,
			(unsigned long long)elog_base + elog_size);
		goto err_release_l1_dir;
	}
	elog_addr = acpi_os_map_memory(elog_base, elog_size);

	rc = -ENOMEM;
	/* allocate buffer to save elog record */
	elog_buf = kmalloc(ELOG_ENTRY_LEN, GFP_KERNEL);
	if (elog_buf == NULL)
		goto err_release_elog;

	mce_register_decode_chain(&extlog_mce_dec);
	/* enable OS to be involved to take over management from BIOS */
	((struct extlog_l1_head *)extlog_l1_addr)->flags |= FLAG_OS_OPTIN;

	return 0;

err_release_elog:
	if (elog_addr)
		acpi_os_unmap_memory(elog_addr, elog_size);
	release_mem_region(elog_base, elog_size);
err_release_l1_dir:
	if (extlog_l1_addr)
		acpi_os_unmap_memory(extlog_l1_addr, l1_size);
	release_mem_region(l1_dirbase, l1_size);
err:
	pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n");
	return rc;
}