1 /****************************************************************************** 2 * 3 * Module Name: exconcat - Concatenate-type AML operators 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include <acpi/acpi.h> 45 #include "accommon.h" 46 #include "acinterp.h" 47 #include "amlresrc.h" 48 49 #define _COMPONENT ACPI_EXECUTER 50 ACPI_MODULE_NAME("exconcat") 51 52 /* Local Prototypes */ 53 static acpi_status 54 acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc, 55 union acpi_operand_object **result_desc); 56 57 /******************************************************************************* 58 * 59 * FUNCTION: acpi_ex_do_concatenate 60 * 61 * PARAMETERS: operand0 - First source object 62 * operand1 - Second source object 63 * actual_return_desc - Where to place the return object 64 * walk_state - Current walk state 65 * 66 * RETURN: Status 67 * 68 * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion 69 * rules as necessary. 70 * NOTE: 71 * Per the ACPI spec (up to 6.1), Concatenate only supports Integer, 72 * String, and Buffer objects. However, we support all objects here 73 * as an extension. This improves the usefulness of both Concatenate 74 * and the Printf/Fprintf macros. The extension returns a string 75 * describing the object type for the other objects. 76 * 02/2016. 77 * 78 ******************************************************************************/ 79 80 acpi_status 81 acpi_ex_do_concatenate(union acpi_operand_object *operand0, 82 union acpi_operand_object *operand1, 83 union acpi_operand_object **actual_return_desc, 84 struct acpi_walk_state *walk_state) 85 { 86 union acpi_operand_object *local_operand0 = operand0; 87 union acpi_operand_object *local_operand1 = operand1; 88 union acpi_operand_object *temp_operand1 = NULL; 89 union acpi_operand_object *return_desc; 90 char *buffer; 91 acpi_object_type operand0_type; 92 acpi_object_type operand1_type; 93 acpi_status status; 94 95 ACPI_FUNCTION_TRACE(ex_do_concatenate); 96 97 /* Operand 0 preprocessing */ 98 99 switch (operand0->common.type) { 100 case ACPI_TYPE_INTEGER: 101 case ACPI_TYPE_STRING: 102 case ACPI_TYPE_BUFFER: 103 104 operand0_type = operand0->common.type; 105 break; 106 107 default: 108 109 /* For all other types, get the "object type" string */ 110 111 status = 112 acpi_ex_convert_to_object_type_string(operand0, 113 &local_operand0); 114 if (ACPI_FAILURE(status)) { 115 goto cleanup; 116 } 117 118 operand0_type = ACPI_TYPE_STRING; 119 break; 120 } 121 122 /* Operand 1 preprocessing */ 123 124 switch (operand1->common.type) { 125 case ACPI_TYPE_INTEGER: 126 case ACPI_TYPE_STRING: 127 case ACPI_TYPE_BUFFER: 128 129 operand1_type = operand1->common.type; 130 break; 131 132 default: 133 134 /* For all other types, get the "object type" string */ 135 136 status = 137 acpi_ex_convert_to_object_type_string(operand1, 138 &local_operand1); 139 if (ACPI_FAILURE(status)) { 140 goto cleanup; 141 } 142 143 operand1_type = ACPI_TYPE_STRING; 144 break; 145 } 146 147 /* 148 * Convert the second operand if necessary. The first operand (0) 149 * determines the type of the second operand (1) (See the Data Types 150 * section of the ACPI specification). Both object types are 151 * guaranteed to be either Integer/String/Buffer by the operand 152 * resolution mechanism. 153 */ 154 switch (operand0_type) { 155 case ACPI_TYPE_INTEGER: 156 157 status = 158 acpi_ex_convert_to_integer(local_operand1, &temp_operand1, 159 ACPI_STRTOUL_BASE16); 160 break; 161 162 case ACPI_TYPE_BUFFER: 163 164 status = 165 acpi_ex_convert_to_buffer(local_operand1, &temp_operand1); 166 break; 167 168 case ACPI_TYPE_STRING: 169 170 switch (operand1_type) { 171 case ACPI_TYPE_INTEGER: 172 case ACPI_TYPE_STRING: 173 case ACPI_TYPE_BUFFER: 174 175 /* Other types have already been converted to string */ 176 177 status = 178 acpi_ex_convert_to_string(local_operand1, 179 &temp_operand1, 180 ACPI_IMPLICIT_CONVERT_HEX); 181 break; 182 183 default: 184 185 status = AE_OK; 186 break; 187 } 188 break; 189 190 default: 191 192 ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", 193 operand0->common.type)); 194 status = AE_AML_INTERNAL; 195 } 196 197 if (ACPI_FAILURE(status)) { 198 goto cleanup; 199 } 200 201 /* Take care with any newly created operand objects */ 202 203 if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) { 204 acpi_ut_remove_reference(local_operand1); 205 } 206 207 local_operand1 = temp_operand1; 208 209 /* 210 * Both operands are now known to be the same object type 211 * (Both are Integer, String, or Buffer), and we can now perform 212 * the concatenation. 213 * 214 * There are three cases to handle, as per the ACPI spec: 215 * 216 * 1) Two Integers concatenated to produce a new Buffer 217 * 2) Two Strings concatenated to produce a new String 218 * 3) Two Buffers concatenated to produce a new Buffer 219 */ 220 switch (operand0_type) { 221 case ACPI_TYPE_INTEGER: 222 223 /* Result of two Integers is a Buffer */ 224 /* Need enough buffer space for two integers */ 225 226 return_desc = acpi_ut_create_buffer_object((acpi_size) 227 ACPI_MUL_2 228 (acpi_gbl_integer_byte_width)); 229 if (!return_desc) { 230 status = AE_NO_MEMORY; 231 goto cleanup; 232 } 233 234 buffer = (char *)return_desc->buffer.pointer; 235 236 /* Copy the first integer, LSB first */ 237 238 memcpy(buffer, &operand0->integer.value, 239 acpi_gbl_integer_byte_width); 240 241 /* Copy the second integer (LSB first) after the first */ 242 243 memcpy(buffer + acpi_gbl_integer_byte_width, 244 &local_operand1->integer.value, 245 acpi_gbl_integer_byte_width); 246 break; 247 248 case ACPI_TYPE_STRING: 249 250 /* Result of two Strings is a String */ 251 252 return_desc = acpi_ut_create_string_object(((acpi_size) 253 local_operand0-> 254 string.length + 255 local_operand1-> 256 string.length)); 257 if (!return_desc) { 258 status = AE_NO_MEMORY; 259 goto cleanup; 260 } 261 262 buffer = return_desc->string.pointer; 263 264 /* Concatenate the strings */ 265 266 strcpy(buffer, local_operand0->string.pointer); 267 strcat(buffer, local_operand1->string.pointer); 268 break; 269 270 case ACPI_TYPE_BUFFER: 271 272 /* Result of two Buffers is a Buffer */ 273 274 return_desc = acpi_ut_create_buffer_object(((acpi_size) 275 operand0->buffer. 276 length + 277 local_operand1-> 278 buffer.length)); 279 if (!return_desc) { 280 status = AE_NO_MEMORY; 281 goto cleanup; 282 } 283 284 buffer = (char *)return_desc->buffer.pointer; 285 286 /* Concatenate the buffers */ 287 288 memcpy(buffer, operand0->buffer.pointer, 289 operand0->buffer.length); 290 memcpy(buffer + operand0->buffer.length, 291 local_operand1->buffer.pointer, 292 local_operand1->buffer.length); 293 break; 294 295 default: 296 297 /* Invalid object type, should not happen here */ 298 299 ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", 300 operand0->common.type)); 301 status = AE_AML_INTERNAL; 302 goto cleanup; 303 } 304 305 *actual_return_desc = return_desc; 306 307 cleanup: 308 if (local_operand0 != operand0) { 309 acpi_ut_remove_reference(local_operand0); 310 } 311 312 if (local_operand1 != operand1) { 313 acpi_ut_remove_reference(local_operand1); 314 } 315 316 return_ACPI_STATUS(status); 317 } 318 319 /******************************************************************************* 320 * 321 * FUNCTION: acpi_ex_convert_to_object_type_string 322 * 323 * PARAMETERS: obj_desc - Object to be converted 324 * return_desc - Where to place the return object 325 * 326 * RETURN: Status 327 * 328 * DESCRIPTION: Convert an object of arbitrary type to a string object that 329 * contains the namestring for the object. Used for the 330 * concatenate operator. 331 * 332 ******************************************************************************/ 333 334 static acpi_status 335 acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc, 336 union acpi_operand_object **result_desc) 337 { 338 union acpi_operand_object *return_desc; 339 const char *type_string; 340 341 type_string = acpi_ut_get_type_name(obj_desc->common.type); 342 343 return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9)); /* 9 For "[ Object]" */ 344 if (!return_desc) { 345 return (AE_NO_MEMORY); 346 } 347 348 strcpy(return_desc->string.pointer, "["); 349 strcat(return_desc->string.pointer, type_string); 350 strcat(return_desc->string.pointer, " Object]"); 351 352 *result_desc = return_desc; 353 return (AE_OK); 354 } 355 356 /******************************************************************************* 357 * 358 * FUNCTION: acpi_ex_concat_template 359 * 360 * PARAMETERS: operand0 - First source object 361 * operand1 - Second source object 362 * actual_return_desc - Where to place the return object 363 * walk_state - Current walk state 364 * 365 * RETURN: Status 366 * 367 * DESCRIPTION: Concatenate two resource templates 368 * 369 ******************************************************************************/ 370 371 acpi_status 372 acpi_ex_concat_template(union acpi_operand_object *operand0, 373 union acpi_operand_object *operand1, 374 union acpi_operand_object **actual_return_desc, 375 struct acpi_walk_state *walk_state) 376 { 377 acpi_status status; 378 union acpi_operand_object *return_desc; 379 u8 *new_buf; 380 u8 *end_tag; 381 acpi_size length0; 382 acpi_size length1; 383 acpi_size new_length; 384 385 ACPI_FUNCTION_TRACE(ex_concat_template); 386 387 /* 388 * Find the end_tag descriptor in each resource template. 389 * Note1: returned pointers point TO the end_tag, not past it. 390 * Note2: zero-length buffers are allowed; treated like one end_tag 391 */ 392 393 /* Get the length of the first resource template */ 394 395 status = acpi_ut_get_resource_end_tag(operand0, &end_tag); 396 if (ACPI_FAILURE(status)) { 397 return_ACPI_STATUS(status); 398 } 399 400 length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer); 401 402 /* Get the length of the second resource template */ 403 404 status = acpi_ut_get_resource_end_tag(operand1, &end_tag); 405 if (ACPI_FAILURE(status)) { 406 return_ACPI_STATUS(status); 407 } 408 409 length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer); 410 411 /* Combine both lengths, minimum size will be 2 for end_tag */ 412 413 new_length = length0 + length1 + sizeof(struct aml_resource_end_tag); 414 415 /* Create a new buffer object for the result (with one end_tag) */ 416 417 return_desc = acpi_ut_create_buffer_object(new_length); 418 if (!return_desc) { 419 return_ACPI_STATUS(AE_NO_MEMORY); 420 } 421 422 /* 423 * Copy the templates to the new buffer, 0 first, then 1 follows. One 424 * end_tag descriptor is copied from Operand1. 425 */ 426 new_buf = return_desc->buffer.pointer; 427 memcpy(new_buf, operand0->buffer.pointer, length0); 428 memcpy(new_buf + length0, operand1->buffer.pointer, length1); 429 430 /* Insert end_tag and set the checksum to zero, means "ignore checksum" */ 431 432 new_buf[new_length - 1] = 0; 433 new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1; 434 435 /* Return the completed resource template */ 436 437 *actual_return_desc = return_desc; 438 return_ACPI_STATUS(AE_OK); 439 } 440