Esempio n. 1
0
acpi_status
acpi_ex_access_region(union acpi_operand_object *obj_desc,
		      u32 field_datum_byte_offset, u64 *value, u32 function)
{
	acpi_status status;
	union acpi_operand_object *rgn_desc;
	u32 region_offset;

	ACPI_FUNCTION_TRACE(ex_access_region);

	/*
	 * Ensure that the region operands are fully evaluated and verify
	 * the validity of the request
	 */
	status = acpi_ex_setup_region(obj_desc, field_datum_byte_offset);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/*
	 * The physical address of this field datum is:
	 *
	 * 1) The base of the region, plus
	 * 2) The base offset of the field, plus
	 * 3) The current offset into the field
	 */
	rgn_desc = obj_desc->common_field.region_obj;
	region_offset =
	    obj_desc->common_field.base_byte_offset + field_datum_byte_offset;

	if ((function & ACPI_IO_MASK) == ACPI_READ) {
		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[READ]"));
	} else {
		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[WRITE]"));
	}

	ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
			      " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
			      acpi_ut_get_region_name(rgn_desc->region.
						      space_id),
			      rgn_desc->region.space_id,
			      obj_desc->common_field.access_byte_width,
			      obj_desc->common_field.base_byte_offset,
			      field_datum_byte_offset, ACPI_CAST_PTR(void,
								     (rgn_desc->
								      region.
								      address +
								      region_offset))));

	/* Invoke the appropriate address_space/op_region handler */

	status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc,
						function, region_offset,
						ACPI_MUL_8(obj_desc->
							   common_field.
							   access_byte_width),
						value);

	if (ACPI_FAILURE(status)) {
		if (status == AE_NOT_IMPLEMENTED) {
			ACPI_ERROR((AE_INFO,
				    "Region %s (ID=%u) not implemented",
				    acpi_ut_get_region_name(rgn_desc->region.
							    space_id),
				    rgn_desc->region.space_id));
		} else if (status == AE_NOT_EXIST) {
			ACPI_ERROR((AE_INFO,
				    "Region %s (ID=%u) has no handler",
				    acpi_ut_get_region_name(rgn_desc->region.
							    space_id),
				    rgn_desc->region.space_id));
		}
	}

	return_ACPI_STATUS(status);
}
Esempio n. 2
0
acpi_status
acpi_ex_load_op(union acpi_operand_object *obj_desc,
		union acpi_operand_object *target,
		struct acpi_walk_state *walk_state)
{
	acpi_status status;
	union acpi_operand_object *ddb_handle;
	union acpi_operand_object *buffer_desc = NULL;
	struct acpi_table_header *table_ptr = NULL;
	acpi_physical_address address;
	struct acpi_table_header table_header;
	acpi_integer temp;
	u32 i;

	ACPI_FUNCTION_TRACE(ex_load_op);

	/* Object can be either an op_region or a Field */

	switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
	case ACPI_TYPE_REGION:

		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
				  obj_desc,
				  acpi_ut_get_object_type_name(obj_desc)));

		/*
		 * If the Region Address and Length have not been previously evaluated,
		 * evaluate them now and save the results.
		 */
		if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
			status = acpi_ds_get_region_arguments(obj_desc);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}
		}

		/* Get the base physical address of the region */

		address = obj_desc->region.address;

		/* Get part of the table header to get the table length */

		table_header.length = 0;
		for (i = 0; i < 8; i++) {
			status =
			    acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
							   (acpi_physical_address)
							   (i + address), 8,
							   &temp);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}

			/* Get the one valid byte of the returned 64-bit value */

			ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp;
		}

		/* Sanity check the table length */

		if (table_header.length < sizeof(struct acpi_table_header)) {
			return_ACPI_STATUS(AE_BAD_HEADER);
		}

		/* Allocate a buffer for the entire table */

		table_ptr = ACPI_ALLOCATE(table_header.length);
		if (!table_ptr) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		/* Get the entire table from the op region */

		for (i = 0; i < table_header.length; i++) {
			status =
			    acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
							   (acpi_physical_address)
							   (i + address), 8,
							   &temp);
			if (ACPI_FAILURE(status)) {
				goto cleanup;
			}

			/* Get the one valid byte of the returned 64-bit value */

			ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp;
		}
		break;

	case ACPI_TYPE_LOCAL_REGION_FIELD:
	case ACPI_TYPE_LOCAL_BANK_FIELD:
	case ACPI_TYPE_LOCAL_INDEX_FIELD:

		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n",
				  obj_desc,
				  acpi_ut_get_object_type_name(obj_desc)));

		/*
		 * The length of the field must be at least as large as the table.
		 * Read the entire field and thus the entire table.  Buffer is
		 * allocated during the read.
		 */
		status =
		    acpi_ex_read_data_from_field(walk_state, obj_desc,
						 &buffer_desc);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		table_ptr = ACPI_CAST_PTR(struct acpi_table_header,
					  buffer_desc->buffer.pointer);

		/* All done with the buffer_desc, delete it */

		buffer_desc->buffer.pointer = NULL;
		acpi_ut_remove_reference(buffer_desc);

		/* Sanity check the table length */

		if (table_ptr->length < sizeof(struct acpi_table_header)) {
			status = AE_BAD_HEADER;
			goto cleanup;
		}
		break;

	default:
		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
	}

	/* The table must be either an SSDT or a PSDT or an OEMx */

	if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) &&
	    (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG)) &&
		(strncmp(table_ptr->signature, "OEM", 3))) {
		ACPI_ERROR((AE_INFO,
			    "Table has invalid signature [%4.4s], must be SSDT, PSDT or OEMx",
			    table_ptr->signature));
		status = AE_BAD_SIGNATURE;
		goto cleanup;
	}

	/* Install the new table into the local data structures */

	status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
	if (ACPI_FAILURE(status)) {

		/* On error, table_ptr was deallocated above */

		return_ACPI_STATUS(status);
	}

	/* Store the ddb_handle into the Target operand */

	status = acpi_ex_store(ddb_handle, target, walk_state);
	if (ACPI_FAILURE(status)) {
		(void)acpi_ex_unload_table(ddb_handle);

		/* table_ptr was deallocated above */

		return_ACPI_STATUS(status);
	}

	ACPI_INFO((AE_INFO,
		   "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]",
		   table_ptr->oem_id, table_ptr->oem_table_id));

      cleanup:
	if (ACPI_FAILURE(status)) {
		ACPI_FREE(table_ptr);
	}
	return_ACPI_STATUS(status);
}