Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6273f00e authored by Lv Zheng's avatar Lv Zheng Committed by Rafael J. Wysocki
Browse files

ACPICA: Fix buffer allocation issue for generic_serial_bus region accesses.



The size of the buffer allocated for generic_serial_bus region access
is not correct.  This patch introduces acpi_ex_get_serial_access_length()
to be invoked to obtain correct data buffer length.

Signed-off-by: default avatarLv Zheng <lv.zheng@intel.com>
Reported by: Lan Tianyu <tianyu.lan@intel.com>
Acked-by: default avatarLan Tianyu <tianyu.lan@intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent a798c10f
Loading
Loading
Loading
Loading
+97 −7
Original line number Diff line number Diff line
@@ -45,10 +45,71 @@
#include "accommon.h"
#include "acdispat.h"
#include "acinterp.h"
#include "amlcode.h"

#define _COMPONENT          ACPI_EXECUTER
ACPI_MODULE_NAME("exfield")

/* Local prototypes */
static u32
acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length);

/*******************************************************************************
 *
 * FUNCTION:    acpi_get_serial_access_bytes
 *
 * PARAMETERS:  accessor_type   - The type of the protocol indicated by region
 *                                field access attributes
 *              access_length   - The access length of the region field
 *
 * RETURN:      Decoded access length
 *
 * DESCRIPTION: This routine returns the length of the generic_serial_bus
 *              protocol bytes
 *
 ******************************************************************************/

static u32
acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length)
{
	u32 length;

	switch (accessor_type) {
	case AML_FIELD_ATTRIB_QUICK:

		length = 0;
		break;

	case AML_FIELD_ATTRIB_SEND_RCV:
	case AML_FIELD_ATTRIB_BYTE:

		length = 1;
		break;

	case AML_FIELD_ATTRIB_WORD:
	case AML_FIELD_ATTRIB_WORD_CALL:

		length = 2;
		break;

	case AML_FIELD_ATTRIB_MULTIBYTE:
	case AML_FIELD_ATTRIB_RAW_BYTES:
	case AML_FIELD_ATTRIB_RAW_PROCESS:

		length = access_length;
		break;

	case AML_FIELD_ATTRIB_BLOCK:
	case AML_FIELD_ATTRIB_BLOCK_CALL:
	default:

		length = ACPI_GSBUS_BUFFER_SIZE;
		break;
	}

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_read_data_from_field
@@ -63,6 +124,7 @@ ACPI_MODULE_NAME("exfield")
 *              Buffer, depending on the size of the field.
 *
 ******************************************************************************/

acpi_status
acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state,
			     union acpi_operand_object *obj_desc,
@@ -73,6 +135,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
	acpi_size length;
	void *buffer;
	u32 function;
	u16 accessor_type;

	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);

@@ -116,9 +179,22 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
			    ACPI_READ | (obj_desc->field.attribute << 16);
		} else if (obj_desc->field.region_obj->region.space_id ==
			   ACPI_ADR_SPACE_GSBUS) {
			length = ACPI_GSBUS_BUFFER_SIZE;
			function =
			    ACPI_READ | (obj_desc->field.attribute << 16);
			accessor_type = obj_desc->field.attribute;
			length = acpi_ex_get_serial_access_length(accessor_type,
								  obj_desc->
								  field.
								  access_length);

			/*
			 * Add additional 2 bytes for modeled generic_serial_bus data buffer:
			 * typedef struct {
			 *     BYTEStatus; // Byte 0 of the data buffer
			 *     BYTELength; // Byte 1 of the data buffer
			 *     BYTE[x-1]Data; // Bytes 2-x of the arbitrary length data buffer,
			 * }
			 */
			length += 2;
			function = ACPI_READ | (accessor_type << 16);
		} else {	/* IPMI */

			length = ACPI_IPMI_BUFFER_SIZE;
@@ -231,6 +307,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
	void *buffer;
	union acpi_operand_object *buffer_desc;
	u32 function;
	u16 accessor_type;

	ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);

@@ -284,9 +361,22 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
			    ACPI_WRITE | (obj_desc->field.attribute << 16);
		} else if (obj_desc->field.region_obj->region.space_id ==
			   ACPI_ADR_SPACE_GSBUS) {
			length = ACPI_GSBUS_BUFFER_SIZE;
			function =
			    ACPI_WRITE | (obj_desc->field.attribute << 16);
			accessor_type = obj_desc->field.attribute;
			length = acpi_ex_get_serial_access_length(accessor_type,
								  obj_desc->
								  field.
								  access_length);

			/*
			 * Add additional 2 bytes for modeled generic_serial_bus data buffer:
			 * typedef struct {
			 *     BYTEStatus; // Byte 0 of the data buffer
			 *     BYTELength; // Byte 1 of the data buffer
			 *     BYTE[x-1]Data; // Bytes 2-x of the arbitrary length data buffer,
			 * }
			 */
			length += 2;
			function = ACPI_WRITE | (accessor_type << 16);
		} else {	/* IPMI */

			length = ACPI_IPMI_BUFFER_SIZE;