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