Esempio n. 1
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);
}
Esempio n. 2
0
int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
{
	char filename[ACPI_NAME_SIZE + 16];
	char instance_str[16];
	ACPI_FILE file;
	size_t actual;
	u32 table_length;

	/* Obtain table length */

	table_length = ap_get_table_length(table);

	/* Construct lower-case filename from the table local signature */

	if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
		ACPI_MOVE_NAME(filename, ACPI_RSDP_NAME);
	} else {
		ACPI_MOVE_NAME(filename, table->signature);
	}
	filename[0] = (char)ACPI_TOLOWER(filename[0]);
	filename[1] = (char)ACPI_TOLOWER(filename[1]);
	filename[2] = (char)ACPI_TOLOWER(filename[2]);
	filename[3] = (char)ACPI_TOLOWER(filename[3]);
	filename[ACPI_NAME_SIZE] = 0;

	/* Handle multiple SSDts - create different filenames for each */

	if (instance > 0) {
		acpi_ut_snprintf(instance_str, sizeof(instance_str), "%u",
				 instance);
		ACPI_STRCAT(filename, instance_str);
	}

	ACPI_STRCAT(filename, ACPI_TABLE_FILE_SUFFIX);

	if (gbl_verbose_mode) {
		acpi_log_error
		    ("Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n",
		     table->signature, filename, table->length, table->length);
	}

	/* Open the file and dump the entire table in binary mode */

	file = acpi_os_open_file(filename,
				 ACPI_FILE_WRITING | ACPI_FILE_BINARY);
	if (!file) {
		acpi_log_error("Could not open output file: %s\n", filename);
		return (-1);
	}

	actual = acpi_os_write_file(file, table, 1, table_length);
	if (actual != table_length) {
		acpi_log_error("Error writing binary output file: %s\n",
			       filename);
		acpi_os_close_file(file);
		return (-1);
	}

	acpi_os_close_file(file);
	return (0);
}
Esempio n. 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);
}
Esempio n. 4
0
static acpi_status
osl_read_table_from_file(char *filename,
			 acpi_size file_offset,
			 char *signature, struct acpi_table_header **table)
{
	FILE *table_file;
	struct acpi_table_header header;
	struct acpi_table_header *local_table = NULL;
	u32 table_length;
	s32 count;
	acpi_status status = AE_OK;

	/* Open the file */

	table_file = fopen(filename, "rb");
	if (table_file == NULL) {
		fprintf(stderr, "Could not open table file: %s\n", filename);
		return (osl_get_last_status(AE_NOT_FOUND));
	}

	fseek(table_file, file_offset, SEEK_SET);

	/* Read the Table header to get the table length */

	count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
	if (count != sizeof(struct acpi_table_header)) {
		fprintf(stderr, "Could not read table header: %s\n", filename);
		status = AE_BAD_HEADER;
		goto exit;
	}

	/* If signature is specified, it must match the table */

	if (signature) {
		if (ACPI_VALIDATE_RSDP_SIG(signature)) {
			if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) {
				fprintf(stderr,
					"Incorrect RSDP signature: found %8.8s\n",
					header.signature);
				status = AE_BAD_SIGNATURE;
				goto exit;
			}
		} else if (!ACPI_COMPARE_NAME(signature, header.signature)) {
			fprintf(stderr,
				"Incorrect signature: Expecting %4.4s, found %4.4s\n",
				signature, header.signature);
			status = AE_BAD_SIGNATURE;
			goto exit;
		}
	}

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

	/* Read the entire table into a local buffer */

	local_table = calloc(1, table_length);
	if (!local_table) {
		fprintf(stderr,
			"%4.4s: Could not allocate buffer for table of length %X\n",
			header.signature, table_length);
		status = AE_NO_MEMORY;
		goto exit;
	}

	fseek(table_file, file_offset, SEEK_SET);

	count = fread(local_table, 1, table_length, table_file);
	if (count != table_length) {
		fprintf(stderr, "%4.4s: Could not read table content\n",
			header.signature);
		status = AE_INVALID_TABLE_LENGTH;
		goto exit;
	}

	/* Validate checksum */

	(void)ap_is_valid_checksum(local_table);

exit:
	fclose(table_file);
	*table = local_table;
	return (status);
}
Esempio n. 5
0
static void osl_unmap_table(struct acpi_table_header *table)
{
	if (table) {
		acpi_os_unmap_memory(table, ap_get_table_length(table));
	}
}
Esempio n. 6
0
static acpi_status
osl_map_table(acpi_size address,
	      char *signature, struct acpi_table_header **table)
{
	struct acpi_table_header *mapped_table;
	u32 length;

	if (!address) {
		return (AE_BAD_ADDRESS);
	}

	/*
	 * Map the header so we can get the table length.
	 * Use sizeof (struct acpi_table_header) as:
	 * 1. it is bigger than 24 to include RSDP->Length
	 * 2. it is smaller than sizeof (struct acpi_table_rsdp)
	 */
	mapped_table =
	    acpi_os_map_memory(address, sizeof(struct acpi_table_header));
	if (!mapped_table) {
		fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n",
			ACPI_FORMAT_UINT64(address));
		return (osl_get_last_status(AE_BAD_ADDRESS));
	}

	/* If specified, signature must match */

	if (signature) {
		if (ACPI_VALIDATE_RSDP_SIG(signature)) {
			if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) {
				acpi_os_unmap_memory(mapped_table,
						     sizeof(struct
							    acpi_table_header));
				return (AE_BAD_SIGNATURE);
			}
		} else
		    if (!ACPI_COMPARE_NAME(signature, mapped_table->signature))
		{
			acpi_os_unmap_memory(mapped_table,
					     sizeof(struct acpi_table_header));
			return (AE_BAD_SIGNATURE);
		}
	}

	/* Map the entire table */

	length = ap_get_table_length(mapped_table);
	acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
	if (length == 0) {
		return (AE_BAD_HEADER);
	}

	mapped_table = acpi_os_map_memory(address, length);
	if (!mapped_table) {
		fprintf(stderr,
			"Could not map table at 0x%8.8X%8.8X length %8.8X\n",
			ACPI_FORMAT_UINT64(address), length);
		return (osl_get_last_status(AE_INVALID_TABLE_LENGTH));
	}

	(void)ap_is_valid_checksum(mapped_table);

	*table = mapped_table;
	return (AE_OK);
}