Пример #1
0
static acpi_status osl_list_bios_tables(void)
{
	struct acpi_table_header *mapped_table = NULL;
	u8 *table_data;
	u8 number_of_tables;
	u8 item_size;
	acpi_physical_address table_address = 0;
	acpi_status status = AE_OK;
	u32 i;

	if (osl_can_use_xsdt()) {
		item_size = sizeof(u64);
		table_data =
		    ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
		number_of_tables =
		    (u8)((gbl_xsdt->header.length -
			  sizeof(struct acpi_table_header))
			 / item_size);
	} else {		/* Use RSDT if XSDT is not available */

		item_size = sizeof(u32);
		table_data =
		    ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);
		number_of_tables =
		    (u8)((gbl_rsdt->header.length -
			  sizeof(struct acpi_table_header))
			 / item_size);
	}

	/* Search RSDT/XSDT for the requested table */

	for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
		if (osl_can_use_xsdt()) {
			table_address =
			    (acpi_physical_address) (*ACPI_CAST64(table_data));
		} else {
			table_address =
			    (acpi_physical_address) (*ACPI_CAST32(table_data));
		}

		/* Skip NULL entries in RSDT/XSDT */

		if (!table_address) {
			continue;
		}

		status = osl_map_table(table_address, NULL, &mapped_table);
		if (ACPI_FAILURE(status)) {
			return (status);
		}

		osl_add_table_to_list(mapped_table->signature, 0);
		osl_unmap_table(mapped_table);
	}

	return (AE_OK);
}
Пример #2
0
acpi_status
acpi_os_get_table_by_address(acpi_physical_address address,
			     struct acpi_table_header ** table)
{
	u32 table_length;
	struct acpi_table_header *mapped_table;
	struct acpi_table_header *local_table = NULL;
	acpi_status status = AE_OK;

	/* Get main ACPI tables from memory on first invocation of this function */

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

	/* Map the table and validate it */

	status = osl_map_table(address, NULL, &mapped_table);
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	/* Copy table to local buffer and return it */

	table_length = ap_get_table_length(mapped_table);
	if (table_length == 0) {
		status = AE_BAD_HEADER;
		goto exit;
	}

	local_table = calloc(1, table_length);
	if (!local_table) {
		status = AE_NO_MEMORY;
		goto exit;
	}

	memcpy(local_table, mapped_table, table_length);

exit:
	osl_unmap_table(mapped_table);
	*table = local_table;
	return (status);
}
Пример #3
0
static acpi_status
osl_get_bios_table(char *signature,
		   u32 instance,
		   struct acpi_table_header **table,
		   acpi_physical_address * address)
{
	struct acpi_table_header *local_table = NULL;
	struct acpi_table_header *mapped_table = NULL;
	u8 *table_data;
	u8 number_of_tables;
	u8 item_size;
	u32 current_instance = 0;
	acpi_physical_address table_address = 0;
	u32 table_length = 0;
	acpi_status status = AE_OK;
	u32 i;

	/* Handle special tables whose addresses are not in RSDT/XSDT */

	if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) ||
	    ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) ||
	    ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) ||
	    ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) ||
	    ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
		if (instance > 0) {
			return (AE_LIMIT);
		}

		/*
		 * Get the appropriate address, either 32-bit or 64-bit. Be very
		 * careful about the FADT length and validate table addresses.
		 * Note: The 64-bit addresses have priority.
		 */
		if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) {
			if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) &&
			    gbl_fadt->Xdsdt) {
				table_address =
				    (acpi_physical_address) gbl_fadt->Xdsdt;
			} else
			    if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT)
				&& gbl_fadt->dsdt) {
				table_address =
				    (acpi_physical_address) gbl_fadt->dsdt;
			}
		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
			if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) &&
			    gbl_fadt->Xfacs) {
				table_address =
				    (acpi_physical_address) gbl_fadt->Xfacs;
			} else
			    if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS)
				&& gbl_fadt->facs) {
				table_address =
				    (acpi_physical_address) gbl_fadt->facs;
			}
		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) {
			if (!gbl_revision) {
				return (AE_BAD_SIGNATURE);
			}
			table_address =
			    (acpi_physical_address) gbl_rsdp.
			    xsdt_physical_address;
		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) {
			table_address =
			    (acpi_physical_address) gbl_rsdp.
			    rsdt_physical_address;
		} else {
			table_address =
			    (acpi_physical_address) gbl_rsdp_address;
			signature = ACPI_SIG_RSDP;
		}

		/* Now we can get the requested special table */

		status = osl_map_table(table_address, signature, &mapped_table);
		if (ACPI_FAILURE(status)) {
			return (status);
		}

		table_length = ap_get_table_length(mapped_table);
	} else {		/* Case for a normal ACPI table */

		if (osl_can_use_xsdt()) {
			item_size = sizeof(u64);
			table_data =
			    ACPI_CAST8(gbl_xsdt) +
			    sizeof(struct acpi_table_header);
			number_of_tables =
			    (u8)((gbl_xsdt->header.length -
				  sizeof(struct acpi_table_header))
				 / item_size);
		} else {	/* Use RSDT if XSDT is not available */

			item_size = sizeof(u32);
			table_data =
			    ACPI_CAST8(gbl_rsdt) +
			    sizeof(struct acpi_table_header);
			number_of_tables =
			    (u8)((gbl_rsdt->header.length -
				  sizeof(struct acpi_table_header))
				 / item_size);
		}

		/* Search RSDT/XSDT for the requested table */

		for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
			if (osl_can_use_xsdt()) {
				table_address =
				    (acpi_physical_address) (*ACPI_CAST64
							     (table_data));
			} else {
				table_address =
				    (acpi_physical_address) (*ACPI_CAST32
							     (table_data));
			}

			/* Skip NULL entries in RSDT/XSDT */

			if (!table_address) {
				continue;
			}

			status =
			    osl_map_table(table_address, NULL, &mapped_table);
			if (ACPI_FAILURE(status)) {
				return (status);
			}
			table_length = mapped_table->length;

			/* Does this table match the requested signature? */

			if (!ACPI_COMPARE_NAME
			    (mapped_table->signature, signature)) {
				osl_unmap_table(mapped_table);
				mapped_table = NULL;
				continue;
			}

			/* Match table instance (for SSDT/UEFI tables) */

			if (current_instance != instance) {
				osl_unmap_table(mapped_table);
				mapped_table = NULL;
				current_instance++;
				continue;
			}

			break;
		}
	}

	if (!mapped_table) {
		return (AE_LIMIT);
	}

	if (table_length == 0) {
		status = AE_BAD_HEADER;
		goto exit;
	}

	/* Copy table to local buffer and return it */

	local_table = calloc(1, table_length);
	if (!local_table) {
		status = AE_NO_MEMORY;
		goto exit;
	}

	ACPI_MEMCPY(local_table, mapped_table, table_length);
	*address = table_address;
	*table = local_table;

exit:
	osl_unmap_table(mapped_table);
	return (status);
}