1 /****************************************************************************** 2 * 3 * Module Name: exconcat - Concatenate-type AML operators 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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.h" 45 #include "accommon.h" 46 #include "acinterp.h" 47 #include "amlresrc.h" 48 49 50 #define _COMPONENT ACPI_EXECUTER 51 ACPI_MODULE_NAME ("exconcat") 52 53 /* Local Prototypes */ 54 55 static ACPI_STATUS 56 AcpiExConvertToObjectTypeString ( 57 ACPI_OPERAND_OBJECT *ObjDesc, 58 ACPI_OPERAND_OBJECT **ResultDesc); 59 60 61 /******************************************************************************* 62 * 63 * FUNCTION: AcpiExDoConcatenate 64 * 65 * PARAMETERS: Operand0 - First source object 66 * Operand1 - Second source object 67 * ActualReturnDesc - Where to place the return object 68 * WalkState - Current walk state 69 * 70 * RETURN: Status 71 * 72 * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion 73 * rules as necessary. 74 * NOTE: 75 * Per the ACPI spec (up to 6.1), Concatenate only supports Integer, 76 * String, and Buffer objects. However, we support all objects here 77 * as an extension. This improves the usefulness of both Concatenate 78 * and the Printf/Fprintf macros. The extension returns a string 79 * describing the object type for the other objects. 80 * 02/2016. 81 * 82 ******************************************************************************/ 83 84 ACPI_STATUS 85 AcpiExDoConcatenate ( 86 ACPI_OPERAND_OBJECT *Operand0, 87 ACPI_OPERAND_OBJECT *Operand1, 88 ACPI_OPERAND_OBJECT **ActualReturnDesc, 89 ACPI_WALK_STATE *WalkState) 90 { 91 ACPI_OPERAND_OBJECT *LocalOperand0 = Operand0; 92 ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; 93 ACPI_OPERAND_OBJECT *TempOperand1 = NULL; 94 ACPI_OPERAND_OBJECT *ReturnDesc; 95 char *Buffer; 96 ACPI_OBJECT_TYPE Operand0Type; 97 ACPI_OBJECT_TYPE Operand1Type; 98 ACPI_STATUS Status; 99 100 101 ACPI_FUNCTION_TRACE (ExDoConcatenate); 102 103 104 /* Operand 0 preprocessing */ 105 106 switch (Operand0->Common.Type) 107 { 108 case ACPI_TYPE_INTEGER: 109 case ACPI_TYPE_STRING: 110 case ACPI_TYPE_BUFFER: 111 112 Operand0Type = Operand0->Common.Type; 113 break; 114 115 default: 116 117 /* For all other types, get the "object type" string */ 118 119 Status = AcpiExConvertToObjectTypeString ( 120 Operand0, &LocalOperand0); 121 if (ACPI_FAILURE (Status)) 122 { 123 goto Cleanup; 124 } 125 126 Operand0Type = ACPI_TYPE_STRING; 127 break; 128 } 129 130 /* Operand 1 preprocessing */ 131 132 switch (Operand1->Common.Type) 133 { 134 case ACPI_TYPE_INTEGER: 135 case ACPI_TYPE_STRING: 136 case ACPI_TYPE_BUFFER: 137 138 Operand1Type = Operand1->Common.Type; 139 break; 140 141 default: 142 143 /* For all other types, get the "object type" string */ 144 145 Status = AcpiExConvertToObjectTypeString ( 146 Operand1, &LocalOperand1); 147 if (ACPI_FAILURE (Status)) 148 { 149 goto Cleanup; 150 } 151 152 Operand1Type = ACPI_TYPE_STRING; 153 break; 154 } 155 156 /* 157 * Convert the second operand if necessary. The first operand (0) 158 * determines the type of the second operand (1) (See the Data Types 159 * section of the ACPI specification). Both object types are 160 * guaranteed to be either Integer/String/Buffer by the operand 161 * resolution mechanism. 162 */ 163 switch (Operand0Type) 164 { 165 case ACPI_TYPE_INTEGER: 166 167 Status = AcpiExConvertToInteger (LocalOperand1, &TempOperand1, 16); 168 break; 169 170 case ACPI_TYPE_BUFFER: 171 172 Status = AcpiExConvertToBuffer (LocalOperand1, &TempOperand1); 173 break; 174 175 case ACPI_TYPE_STRING: 176 177 switch (Operand1Type) 178 { 179 case ACPI_TYPE_INTEGER: 180 case ACPI_TYPE_STRING: 181 case ACPI_TYPE_BUFFER: 182 183 /* Other types have already been converted to string */ 184 185 Status = AcpiExConvertToString ( 186 LocalOperand1, &TempOperand1, ACPI_IMPLICIT_CONVERT_HEX); 187 break; 188 189 default: 190 191 Status = AE_OK; 192 break; 193 } 194 break; 195 196 default: 197 198 ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", 199 Operand0->Common.Type)); 200 Status = AE_AML_INTERNAL; 201 } 202 203 if (ACPI_FAILURE (Status)) 204 { 205 goto Cleanup; 206 } 207 208 /* Take care with any newly created operand objects */ 209 210 if ((LocalOperand1 != Operand1) && 211 (LocalOperand1 != TempOperand1)) 212 { 213 AcpiUtRemoveReference (LocalOperand1); 214 } 215 216 LocalOperand1 = TempOperand1; 217 218 /* 219 * Both operands are now known to be the same object type 220 * (Both are Integer, String, or Buffer), and we can now perform 221 * the concatenation. 222 * 223 * There are three cases to handle, as per the ACPI spec: 224 * 225 * 1) Two Integers concatenated to produce a new Buffer 226 * 2) Two Strings concatenated to produce a new String 227 * 3) Two Buffers concatenated to produce a new Buffer 228 */ 229 switch (Operand0Type) 230 { 231 case ACPI_TYPE_INTEGER: 232 233 /* Result of two Integers is a Buffer */ 234 /* Need enough buffer space for two integers */ 235 236 ReturnDesc = AcpiUtCreateBufferObject ( 237 (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth)); 238 if (!ReturnDesc) 239 { 240 Status = AE_NO_MEMORY; 241 goto Cleanup; 242 } 243 244 Buffer = (char *) ReturnDesc->Buffer.Pointer; 245 246 /* Copy the first integer, LSB first */ 247 248 memcpy (Buffer, &Operand0->Integer.Value, 249 AcpiGbl_IntegerByteWidth); 250 251 /* Copy the second integer (LSB first) after the first */ 252 253 memcpy (Buffer + AcpiGbl_IntegerByteWidth, 254 &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth); 255 break; 256 257 case ACPI_TYPE_STRING: 258 259 /* Result of two Strings is a String */ 260 261 ReturnDesc = AcpiUtCreateStringObject ( 262 ((ACPI_SIZE) LocalOperand0->String.Length + 263 LocalOperand1->String.Length)); 264 if (!ReturnDesc) 265 { 266 Status = AE_NO_MEMORY; 267 goto Cleanup; 268 } 269 270 Buffer = ReturnDesc->String.Pointer; 271 272 /* Concatenate the strings */ 273 274 strcpy (Buffer, LocalOperand0->String.Pointer); 275 strcat (Buffer, LocalOperand1->String.Pointer); 276 break; 277 278 case ACPI_TYPE_BUFFER: 279 280 /* Result of two Buffers is a Buffer */ 281 282 ReturnDesc = AcpiUtCreateBufferObject ( 283 ((ACPI_SIZE) Operand0->Buffer.Length + 284 LocalOperand1->Buffer.Length)); 285 if (!ReturnDesc) 286 { 287 Status = AE_NO_MEMORY; 288 goto Cleanup; 289 } 290 291 Buffer = (char *) ReturnDesc->Buffer.Pointer; 292 293 /* Concatenate the buffers */ 294 295 memcpy (Buffer, Operand0->Buffer.Pointer, 296 Operand0->Buffer.Length); 297 memcpy (Buffer + Operand0->Buffer.Length, 298 LocalOperand1->Buffer.Pointer, 299 LocalOperand1->Buffer.Length); 300 break; 301 302 default: 303 304 /* Invalid object type, should not happen here */ 305 306 ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", 307 Operand0->Common.Type)); 308 Status = AE_AML_INTERNAL; 309 goto Cleanup; 310 } 311 312 *ActualReturnDesc = ReturnDesc; 313 314 Cleanup: 315 if (LocalOperand0 != Operand0) 316 { 317 AcpiUtRemoveReference (LocalOperand0); 318 } 319 320 if (LocalOperand1 != Operand1) 321 { 322 AcpiUtRemoveReference (LocalOperand1); 323 } 324 325 return_ACPI_STATUS (Status); 326 } 327 328 329 /******************************************************************************* 330 * 331 * FUNCTION: AcpiExConvertToObjectTypeString 332 * 333 * PARAMETERS: ObjDesc - Object to be converted 334 * ReturnDesc - Where to place the return object 335 * 336 * RETURN: Status 337 * 338 * DESCRIPTION: Convert an object of arbitrary type to a string object that 339 * contains the namestring for the object. Used for the 340 * concatenate operator. 341 * 342 ******************************************************************************/ 343 344 static ACPI_STATUS 345 AcpiExConvertToObjectTypeString ( 346 ACPI_OPERAND_OBJECT *ObjDesc, 347 ACPI_OPERAND_OBJECT **ResultDesc) 348 { 349 ACPI_OPERAND_OBJECT *ReturnDesc; 350 const char *TypeString; 351 352 353 TypeString = AcpiUtGetTypeName (ObjDesc->Common.Type); 354 355 ReturnDesc = AcpiUtCreateStringObject ( 356 ((ACPI_SIZE) strlen (TypeString) + 9)); /* 9 For "[ Object]" */ 357 if (!ReturnDesc) 358 { 359 return (AE_NO_MEMORY); 360 } 361 362 strcpy (ReturnDesc->String.Pointer, "["); 363 strcat (ReturnDesc->String.Pointer, TypeString); 364 strcat (ReturnDesc->String.Pointer, " Object]"); 365 366 *ResultDesc = ReturnDesc; 367 return (AE_OK); 368 } 369 370 371 /******************************************************************************* 372 * 373 * FUNCTION: AcpiExConcatTemplate 374 * 375 * PARAMETERS: Operand0 - First source object 376 * Operand1 - Second source object 377 * ActualReturnDesc - Where to place the return object 378 * WalkState - Current walk state 379 * 380 * RETURN: Status 381 * 382 * DESCRIPTION: Concatenate two resource templates 383 * 384 ******************************************************************************/ 385 386 ACPI_STATUS 387 AcpiExConcatTemplate ( 388 ACPI_OPERAND_OBJECT *Operand0, 389 ACPI_OPERAND_OBJECT *Operand1, 390 ACPI_OPERAND_OBJECT **ActualReturnDesc, 391 ACPI_WALK_STATE *WalkState) 392 { 393 ACPI_STATUS Status; 394 ACPI_OPERAND_OBJECT *ReturnDesc; 395 UINT8 *NewBuf; 396 UINT8 *EndTag; 397 ACPI_SIZE Length0; 398 ACPI_SIZE Length1; 399 ACPI_SIZE NewLength; 400 401 402 ACPI_FUNCTION_TRACE (ExConcatTemplate); 403 404 405 /* 406 * Find the EndTag descriptor in each resource template. 407 * Note1: returned pointers point TO the EndTag, not past it. 408 * Note2: zero-length buffers are allowed; treated like one EndTag 409 */ 410 411 /* Get the length of the first resource template */ 412 413 Status = AcpiUtGetResourceEndTag (Operand0, &EndTag); 414 if (ACPI_FAILURE (Status)) 415 { 416 return_ACPI_STATUS (Status); 417 } 418 419 Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer); 420 421 /* Get the length of the second resource template */ 422 423 Status = AcpiUtGetResourceEndTag (Operand1, &EndTag); 424 if (ACPI_FAILURE (Status)) 425 { 426 return_ACPI_STATUS (Status); 427 } 428 429 Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer); 430 431 /* Combine both lengths, minimum size will be 2 for EndTag */ 432 433 NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG); 434 435 /* Create a new buffer object for the result (with one EndTag) */ 436 437 ReturnDesc = AcpiUtCreateBufferObject (NewLength); 438 if (!ReturnDesc) 439 { 440 return_ACPI_STATUS (AE_NO_MEMORY); 441 } 442 443 /* 444 * Copy the templates to the new buffer, 0 first, then 1 follows. One 445 * EndTag descriptor is copied from Operand1. 446 */ 447 NewBuf = ReturnDesc->Buffer.Pointer; 448 memcpy (NewBuf, Operand0->Buffer.Pointer, Length0); 449 memcpy (NewBuf + Length0, Operand1->Buffer.Pointer, Length1); 450 451 /* Insert EndTag and set the checksum to zero, means "ignore checksum" */ 452 453 NewBuf[NewLength - 1] = 0; 454 NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1; 455 456 /* Return the completed resource template */ 457 458 *ActualReturnDesc = ReturnDesc; 459 return_ACPI_STATUS (AE_OK); 460 } 461