brintos

brintos / linux-shallow public Read only

0
0
Text · 10.5 KiB · 2fb78b3 Raw
406 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: exconcat - Concatenate-type AML operators5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acinterp.h"13#include "amlresrc.h"14 15#define _COMPONENT          ACPI_EXECUTER16ACPI_MODULE_NAME("exconcat")17 18/* Local Prototypes */19static acpi_status20acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,21				      union acpi_operand_object **result_desc);22 23/*******************************************************************************24 *25 * FUNCTION:    acpi_ex_do_concatenate26 *27 * PARAMETERS:  operand0            - First source object28 *              operand1            - Second source object29 *              actual_return_desc  - Where to place the return object30 *              walk_state          - Current walk state31 *32 * RETURN:      Status33 *34 * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion35 *              rules as necessary.36 * NOTE:37 * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,38 * String, and Buffer objects. However, we support all objects here39 * as an extension. This improves the usefulness of both Concatenate40 * and the Printf/Fprintf macros. The extension returns a string41 * describing the object type for the other objects.42 * 02/2016.43 *44 ******************************************************************************/45 46acpi_status47acpi_ex_do_concatenate(union acpi_operand_object *operand0,48		       union acpi_operand_object *operand1,49		       union acpi_operand_object **actual_return_desc,50		       struct acpi_walk_state *walk_state)51{52	union acpi_operand_object *local_operand0 = operand0;53	union acpi_operand_object *local_operand1 = operand1;54	union acpi_operand_object *temp_operand1 = NULL;55	union acpi_operand_object *return_desc;56	char *buffer;57	acpi_object_type operand0_type;58	acpi_object_type operand1_type;59	acpi_status status;60 61	ACPI_FUNCTION_TRACE(ex_do_concatenate);62 63	/* Operand 0 preprocessing */64 65	switch (operand0->common.type) {66	case ACPI_TYPE_INTEGER:67	case ACPI_TYPE_STRING:68	case ACPI_TYPE_BUFFER:69 70		operand0_type = operand0->common.type;71		break;72 73	default:74 75		/* For all other types, get the "object type" string */76 77		status =78		    acpi_ex_convert_to_object_type_string(operand0,79							  &local_operand0);80		if (ACPI_FAILURE(status)) {81			goto cleanup;82		}83 84		operand0_type = ACPI_TYPE_STRING;85		break;86	}87 88	/* Operand 1 preprocessing */89 90	switch (operand1->common.type) {91	case ACPI_TYPE_INTEGER:92	case ACPI_TYPE_STRING:93	case ACPI_TYPE_BUFFER:94 95		operand1_type = operand1->common.type;96		break;97 98	default:99 100		/* For all other types, get the "object type" string */101 102		status =103		    acpi_ex_convert_to_object_type_string(operand1,104							  &local_operand1);105		if (ACPI_FAILURE(status)) {106			goto cleanup;107		}108 109		operand1_type = ACPI_TYPE_STRING;110		break;111	}112 113	/*114	 * Convert the second operand if necessary. The first operand (0)115	 * determines the type of the second operand (1) (See the Data Types116	 * section of the ACPI specification). Both object types are117	 * guaranteed to be either Integer/String/Buffer by the operand118	 * resolution mechanism.119	 */120	switch (operand0_type) {121	case ACPI_TYPE_INTEGER:122 123		status =124		    acpi_ex_convert_to_integer(local_operand1, &temp_operand1,125					       ACPI_IMPLICIT_CONVERSION);126		break;127 128	case ACPI_TYPE_BUFFER:129 130		status =131		    acpi_ex_convert_to_buffer(local_operand1, &temp_operand1);132		break;133 134	case ACPI_TYPE_STRING:135 136		switch (operand1_type) {137		case ACPI_TYPE_INTEGER:138		case ACPI_TYPE_STRING:139		case ACPI_TYPE_BUFFER:140 141			/* Other types have already been converted to string */142 143			status =144			    acpi_ex_convert_to_string(local_operand1,145						      &temp_operand1,146						      ACPI_IMPLICIT_CONVERT_HEX);147			break;148 149		default:150 151			status = AE_OK;152			break;153		}154		break;155 156	default:157 158		ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",159			    operand0->common.type));160		status = AE_AML_INTERNAL;161	}162 163	if (ACPI_FAILURE(status)) {164		goto cleanup;165	}166 167	/* Take care with any newly created operand objects */168 169	if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) {170		acpi_ut_remove_reference(local_operand1);171	}172 173	local_operand1 = temp_operand1;174 175	/*176	 * Both operands are now known to be the same object type177	 * (Both are Integer, String, or Buffer), and we can now perform178	 * the concatenation.179	 *180	 * There are three cases to handle, as per the ACPI spec:181	 *182	 * 1) Two Integers concatenated to produce a new Buffer183	 * 2) Two Strings concatenated to produce a new String184	 * 3) Two Buffers concatenated to produce a new Buffer185	 */186	switch (operand0_type) {187	case ACPI_TYPE_INTEGER:188 189		/* Result of two Integers is a Buffer */190		/* Need enough buffer space for two integers */191 192		return_desc = acpi_ut_create_buffer_object((acpi_size)193							   ACPI_MUL_2194							   (acpi_gbl_integer_byte_width));195		if (!return_desc) {196			status = AE_NO_MEMORY;197			goto cleanup;198		}199 200		buffer = (char *)return_desc->buffer.pointer;201 202		/* Copy the first integer, LSB first */203 204		memcpy(buffer, &operand0->integer.value,205		       acpi_gbl_integer_byte_width);206 207		/* Copy the second integer (LSB first) after the first */208 209		memcpy(buffer + acpi_gbl_integer_byte_width,210		       &local_operand1->integer.value,211		       acpi_gbl_integer_byte_width);212		break;213 214	case ACPI_TYPE_STRING:215 216		/* Result of two Strings is a String */217 218		return_desc = acpi_ut_create_string_object(((acpi_size)219							    local_operand0->220							    string.length +221							    local_operand1->222							    string.length));223		if (!return_desc) {224			status = AE_NO_MEMORY;225			goto cleanup;226		}227 228		buffer = return_desc->string.pointer;229 230		/* Concatenate the strings */231 232		strcpy(buffer, local_operand0->string.pointer);233		strcat(buffer, local_operand1->string.pointer);234		break;235 236	case ACPI_TYPE_BUFFER:237 238		/* Result of two Buffers is a Buffer */239 240		return_desc = acpi_ut_create_buffer_object(((acpi_size)241							    operand0->buffer.242							    length +243							    local_operand1->244							    buffer.length));245		if (!return_desc) {246			status = AE_NO_MEMORY;247			goto cleanup;248		}249 250		buffer = (char *)return_desc->buffer.pointer;251 252		/* Concatenate the buffers */253 254		memcpy(buffer, operand0->buffer.pointer,255		       operand0->buffer.length);256		memcpy(buffer + operand0->buffer.length,257		       local_operand1->buffer.pointer,258		       local_operand1->buffer.length);259		break;260 261	default:262 263		/* Invalid object type, should not happen here */264 265		ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",266			    operand0->common.type));267		status = AE_AML_INTERNAL;268		goto cleanup;269	}270 271	*actual_return_desc = return_desc;272 273cleanup:274	if (local_operand0 != operand0) {275		acpi_ut_remove_reference(local_operand0);276	}277 278	if (local_operand1 != operand1) {279		acpi_ut_remove_reference(local_operand1);280	}281 282	return_ACPI_STATUS(status);283}284 285/*******************************************************************************286 *287 * FUNCTION:    acpi_ex_convert_to_object_type_string288 *289 * PARAMETERS:  obj_desc            - Object to be converted290 *              return_desc         - Where to place the return object291 *292 * RETURN:      Status293 *294 * DESCRIPTION: Convert an object of arbitrary type to a string object that295 *              contains the namestring for the object. Used for the296 *              concatenate operator.297 *298 ******************************************************************************/299 300static acpi_status301acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,302				      union acpi_operand_object **result_desc)303{304	union acpi_operand_object *return_desc;305	const char *type_string;306 307	type_string = acpi_ut_get_type_name(obj_desc->common.type);308 309	return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9));	/* 9 For "[ Object]" */310	if (!return_desc) {311		return (AE_NO_MEMORY);312	}313 314	strcpy(return_desc->string.pointer, "[");315	strcat(return_desc->string.pointer, type_string);316	strcat(return_desc->string.pointer, " Object]");317 318	*result_desc = return_desc;319	return (AE_OK);320}321 322/*******************************************************************************323 *324 * FUNCTION:    acpi_ex_concat_template325 *326 * PARAMETERS:  operand0            - First source object327 *              operand1            - Second source object328 *              actual_return_desc  - Where to place the return object329 *              walk_state          - Current walk state330 *331 * RETURN:      Status332 *333 * DESCRIPTION: Concatenate two resource templates334 *335 ******************************************************************************/336 337acpi_status338acpi_ex_concat_template(union acpi_operand_object *operand0,339			union acpi_operand_object *operand1,340			union acpi_operand_object **actual_return_desc,341			struct acpi_walk_state *walk_state)342{343	acpi_status status;344	union acpi_operand_object *return_desc;345	u8 *new_buf;346	u8 *end_tag;347	acpi_size length0;348	acpi_size length1;349	acpi_size new_length;350 351	ACPI_FUNCTION_TRACE(ex_concat_template);352 353	/*354	 * Find the end_tag descriptor in each resource template.355	 * Note1: returned pointers point TO the end_tag, not past it.356	 * Note2: zero-length buffers are allowed; treated like one end_tag357	 */358 359	/* Get the length of the first resource template */360 361	status = acpi_ut_get_resource_end_tag(operand0, &end_tag);362	if (ACPI_FAILURE(status)) {363		return_ACPI_STATUS(status);364	}365 366	length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);367 368	/* Get the length of the second resource template */369 370	status = acpi_ut_get_resource_end_tag(operand1, &end_tag);371	if (ACPI_FAILURE(status)) {372		return_ACPI_STATUS(status);373	}374 375	length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);376 377	/* Combine both lengths, minimum size will be 2 for end_tag */378 379	new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);380 381	/* Create a new buffer object for the result (with one end_tag) */382 383	return_desc = acpi_ut_create_buffer_object(new_length);384	if (!return_desc) {385		return_ACPI_STATUS(AE_NO_MEMORY);386	}387 388	/*389	 * Copy the templates to the new buffer, 0 first, then 1 follows. One390	 * end_tag descriptor is copied from Operand1.391	 */392	new_buf = return_desc->buffer.pointer;393	memcpy(new_buf, operand0->buffer.pointer, length0);394	memcpy(new_buf + length0, operand1->buffer.pointer, length1);395 396	/* Insert end_tag and set the checksum to zero, means "ignore checksum" */397 398	new_buf[new_length - 1] = 0;399	new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;400 401	/* Return the completed resource template */402 403	*actual_return_desc = return_desc;404	return_ACPI_STATUS(AE_OK);405}406