1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: exconcat - Concatenate-type AML operators 5 * 6 * Copyright (C) 2000 - 2021, 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_EXECUTER 16 ACPI_MODULE_NAME("exconcat") 17 18 /* Local Prototypes */ 19 static acpi_status 20 acpi_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_concatenate 26 * 27 * PARAMETERS: operand0 - First source object 28 * operand1 - Second source object 29 * actual_return_desc - Where to place the return object 30 * walk_state - Current walk state 31 * 32 * RETURN: Status 33 * 34 * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion 35 * 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 here 39 * as an extension. This improves the usefulness of both Concatenate 40 * and the Printf/Fprintf macros. The extension returns a string 41 * describing the object type for the other objects. 42 * 02/2016. 43 * 44 ******************************************************************************/ 45 46 acpi_status 47 acpi_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 Types 116 * section of the ACPI specification). Both object types are 117 * guaranteed to be either Integer/String/Buffer by the operand 118 * 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 type 177 * (Both are Integer, String, or Buffer), and we can now perform 178 * 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 Buffer 183 * 2) Two Strings concatenated to produce a new String 184 * 3) Two Buffers concatenated to produce a new Buffer 185 */ 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_2 194 (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 273 cleanup: 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_string 288 * 289 * PARAMETERS: obj_desc - Object to be converted 290 * return_desc - Where to place the return object 291 * 292 * RETURN: Status 293 * 294 * DESCRIPTION: Convert an object of arbitrary type to a string object that 295 * contains the namestring for the object. Used for the 296 * concatenate operator. 297 * 298 ******************************************************************************/ 299 300 static acpi_status 301 acpi_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_template 325 * 326 * PARAMETERS: operand0 - First source object 327 * operand1 - Second source object 328 * actual_return_desc - Where to place the return object 329 * walk_state - Current walk state 330 * 331 * RETURN: Status 332 * 333 * DESCRIPTION: Concatenate two resource templates 334 * 335 ******************************************************************************/ 336 337 acpi_status 338 acpi_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_tag 357 */ 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. One 390 * 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