Exemple #1
0
acpi_status
acpi_tb_get_table_rsdt (
	void)
{
	struct acpi_table_desc          table_info;
	acpi_status                     status;
	struct acpi_pointer             address;


	ACPI_FUNCTION_TRACE ("tb_get_table_rsdt");


	/* Get the RSDT/XSDT via the RSDP */

	acpi_tb_get_rsdt_address (&address);

	table_info.type = ACPI_TABLE_XSDT;
	status = acpi_tb_get_table (&address, &table_info);
	if (ACPI_FAILURE (status)) {
		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n",
			acpi_format_exception (status)));
		return_ACPI_STATUS (status);
	}

	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
		"RSDP located at %p, points to RSDT physical=%8.8X%8.8X \n",
		acpi_gbl_RSDP,
		ACPI_FORMAT_UINT64 (address.pointer.value)));

	/* Check the RSDT or XSDT signature */

	status = acpi_tb_validate_rsdt (table_info.pointer);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	/* Get the number of tables defined in the RSDT or XSDT */

	acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer);

	/* Convert and/or copy to an XSDT structure */

	status = acpi_tb_convert_to_xsdt (&table_info);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	/* Save the table pointers and allocation info */

	status = acpi_tb_init_table_descriptor (ACPI_TABLE_XSDT, &table_info);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	acpi_gbl_XSDT = ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info.pointer);

	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
	return_ACPI_STATUS (status);
}
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);
}
acpi_status
acpi_get_firmware_table(acpi_string signature,
			u32 instance,
			u32 flags, struct acpi_table_header **table_pointer)
{
	acpi_status status;
	struct acpi_pointer address;
	struct acpi_table_header *header = NULL;
	struct acpi_table_desc *table_info = NULL;
	struct acpi_table_desc *rsdt_info;
	u32 table_count;
	u32 i;
	u32 j;

	ACPI_FUNCTION_TRACE("acpi_get_firmware_table");

	/*
	 * Ensure that at least the table manager is initialized.  We don't
	 * require that the entire ACPI subsystem is up for this interface.
	 * If we have a buffer, we must have a length too
	 */
	if ((instance == 0) || (!signature) || (!table_pointer)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	/* Ensure that we have a RSDP */

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

		status = acpi_os_get_root_pointer(flags, &address);
		if (ACPI_FAILURE(status)) {
			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n"));
			return_ACPI_STATUS(AE_NO_ACPI_TABLES);
		}

		/* Map and validate the RSDP */

		if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
			status = acpi_os_map_memory(address.pointer.physical,
						    sizeof(struct
							   rsdp_descriptor),
						    (void *)&acpi_gbl_RSDP);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}
		} else {
			acpi_gbl_RSDP = address.pointer.logical;
		}

		/* The RDSP signature and checksum must both be correct */

		status = acpi_tb_validate_rsdp(acpi_gbl_RSDP);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
	}

	/* Get the RSDT address via the RSDP */

	acpi_tb_get_rsdt_address(&address);
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "RSDP located at %p, RSDT physical=%8.8X%8.8X \n",
			  acpi_gbl_RSDP,
			  ACPI_FORMAT_UINT64(address.pointer.value)));

	/* Insert processor_mode flags */

	address.pointer_type |= flags;

	/* Get and validate the RSDT */

	rsdt_info = ACPI_MEM_CALLOCATE(sizeof(struct acpi_table_desc));
	if (!rsdt_info) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

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

	status = acpi_tb_validate_rsdt(rsdt_info->pointer);
	if (ACPI_FAILURE(status)) {
		goto cleanup;
	}

	/* Allocate a scratch table header and table descriptor */

	header = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_header));
	if (!header) {
		status = AE_NO_MEMORY;
		goto cleanup;
	}

	table_info = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_desc));
	if (!table_info) {
		status = AE_NO_MEMORY;
		goto cleanup;
	}

	/* Get the number of table pointers within the RSDT */

	table_count =
	    acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer);
	address.pointer_type = acpi_gbl_table_flags | flags;

	/*
	 * Search the RSDT/XSDT for the correct instance of the
	 * requested table
	 */
	for (i = 0, j = 0; i < table_count; i++) {
		/*
		 * Get the next table pointer, handle RSDT vs. XSDT
		 * RSDT pointers are 32 bits, XSDT pointers are 64 bits
		 */
		if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
			address.pointer.value =
			    (ACPI_CAST_PTR
			     (RSDT_DESCRIPTOR,
			      rsdt_info->pointer))->table_offset_entry[i];
		} else {
			address.pointer.value =
			    (ACPI_CAST_PTR
			     (XSDT_DESCRIPTOR,
			      rsdt_info->pointer))->table_offset_entry[i];
		}

		/* Get the table header */

		status = acpi_tb_get_table_header(&address, header);
		if (ACPI_FAILURE(status)) {
			goto cleanup;
		}

		/* Compare table signatures and table instance */

		if (!ACPI_STRNCMP(header->signature, signature, ACPI_NAME_SIZE)) {
			/* An instance of the table was found */

			j++;
			if (j >= instance) {
				/* Found the correct instance, get the entire table */

				status =
				    acpi_tb_get_table_body(&address, header,
							   table_info);
				if (ACPI_FAILURE(status)) {
					goto cleanup;
				}

				*table_pointer = table_info->pointer;
				goto cleanup;
			}
		}
	}

	/* Did not find the table */

	status = AE_NOT_EXIST;

      cleanup:
	if (rsdt_info->pointer) {
		acpi_os_unmap_memory(rsdt_info->pointer,
				     (acpi_size) rsdt_info->pointer->length);
	}
	ACPI_MEM_FREE(rsdt_info);

	if (header) {
		ACPI_MEM_FREE(header);
	}
	if (table_info) {
		ACPI_MEM_FREE(table_info);
	}
	return_ACPI_STATUS(status);
}
acpi_status
acpi_tb_convert_to_xsdt (
	acpi_table_desc         *table_info,
	u32                     *number_of_tables)
{
	u32                     table_size;
	u32                     i;
	xsdt_descriptor         *new_table;


	FUNCTION_ENTRY ();


	*number_of_tables = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info->pointer);


	/* Compute size of the converted XSDT */

	table_size = (*number_of_tables * sizeof (u64)) + sizeof (acpi_table_header);


	/* Allocate an XSDT */

	new_table = ACPI_MEM_CALLOCATE (table_size);
	if (!new_table) {
		return (AE_NO_MEMORY);
	}

	/* Copy the header and set the length */

	MEMCPY (new_table, table_info->pointer, sizeof (acpi_table_header));
	new_table->header.length = table_size;

	/* Copy the table pointers */

	for (i = 0; i < *number_of_tables; i++) {
		if (acpi_gbl_RSDP->revision < 2) {
#ifdef _IA64
			new_table->table_offset_entry[i] =
				((RSDT_DESCRIPTOR_REV071 *) table_info->pointer)->table_offset_entry[i];
#else
			ACPI_STORE_ADDRESS (new_table->table_offset_entry[i],
				((RSDT_DESCRIPTOR_REV1 *) table_info->pointer)->table_offset_entry[i]);
#endif
		}
		else {
			new_table->table_offset_entry[i] =
				((xsdt_descriptor *) table_info->pointer)->table_offset_entry[i];
		}
	}


	/* Delete the original table (either mapped or in a buffer) */

	acpi_tb_delete_single_table (table_info);


	/* Point the table descriptor to the new table */

	table_info->pointer     = (acpi_table_header *) new_table;
	table_info->base_pointer = (acpi_table_header *) new_table;
	table_info->length      = table_size;
	table_info->allocation  = ACPI_MEM_ALLOCATED;

	return (AE_OK);
}