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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acinterp.h> 47 #include <contrib/dev/acpica/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, 168 ACPI_STRTOUL_BASE16); 169 break; 170 171 case ACPI_TYPE_BUFFER: 172 173 Status = AcpiExConvertToBuffer (LocalOperand1, &TempOperand1); 174 break; 175 176 case ACPI_TYPE_STRING: 177 178 switch (Operand1Type) 179 { 180 case ACPI_TYPE_INTEGER: 181 case ACPI_TYPE_STRING: 182 case ACPI_TYPE_BUFFER: 183 184 /* Other types have already been converted to string */ 185 186 Status = AcpiExConvertToString ( 187 LocalOperand1, &TempOperand1, ACPI_IMPLICIT_CONVERT_HEX); 188 break; 189 190 default: 191 192 Status = AE_OK; 193 break; 194 } 195 break; 196 197 default: 198 199 ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", 200 Operand0->Common.Type)); 201 Status = AE_AML_INTERNAL; 202 } 203 204 if (ACPI_FAILURE (Status)) 205 { 206 goto Cleanup; 207 } 208 209 /* Take care with any newly created operand objects */ 210 211 if ((LocalOperand1 != Operand1) && 212 (LocalOperand1 != TempOperand1)) 213 { 214 AcpiUtRemoveReference (LocalOperand1); 215 } 216 217 LocalOperand1 = TempOperand1; 218 219 /* 220 * Both operands are now known to be the same object type 221 * (Both are Integer, String, or Buffer), and we can now perform 222 * the concatenation. 223 * 224 * There are three cases to handle, as per the ACPI spec: 225 * 226 * 1) Two Integers concatenated to produce a new Buffer 227 * 2) Two Strings concatenated to produce a new String 228 * 3) Two Buffers concatenated to produce a new Buffer 229 */ 230 switch (Operand0Type) 231 { 232 case ACPI_TYPE_INTEGER: 233 234 /* Result of two Integers is a Buffer */ 235 /* Need enough buffer space for two integers */ 236 237 ReturnDesc = AcpiUtCreateBufferObject ( 238 (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth)); 239 if (!ReturnDesc) 240 { 241 Status = AE_NO_MEMORY; 242 goto Cleanup; 243 } 244 245 Buffer = (char *) ReturnDesc->Buffer.Pointer; 246 247 /* Copy the first integer, LSB first */ 248 249 memcpy (Buffer, &Operand0->Integer.Value, 250 AcpiGbl_IntegerByteWidth); 251 252 /* Copy the second integer (LSB first) after the first */ 253 254 memcpy (Buffer + AcpiGbl_IntegerByteWidth, 255 &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth); 256 break; 257 258 case ACPI_TYPE_STRING: 259 260 /* Result of two Strings is a String */ 261 262 ReturnDesc = AcpiUtCreateStringObject ( 263 ((ACPI_SIZE) LocalOperand0->String.Length + 264 LocalOperand1->String.Length)); 265 if (!ReturnDesc) 266 { 267 Status = AE_NO_MEMORY; 268 goto Cleanup; 269 } 270 271 Buffer = ReturnDesc->String.Pointer; 272 273 /* Concatenate the strings */ 274 275 strcpy (Buffer, LocalOperand0->String.Pointer); 276 strcat (Buffer, LocalOperand1->String.Pointer); 277 break; 278 279 case ACPI_TYPE_BUFFER: 280 281 /* Result of two Buffers is a Buffer */ 282 283 ReturnDesc = AcpiUtCreateBufferObject ( 284 ((ACPI_SIZE) Operand0->Buffer.Length + 285 LocalOperand1->Buffer.Length)); 286 if (!ReturnDesc) 287 { 288 Status = AE_NO_MEMORY; 289 goto Cleanup; 290 } 291 292 Buffer = (char *) ReturnDesc->Buffer.Pointer; 293 294 /* Concatenate the buffers */ 295 296 memcpy (Buffer, Operand0->Buffer.Pointer, 297 Operand0->Buffer.Length); 298 memcpy (Buffer + Operand0->Buffer.Length, 299 LocalOperand1->Buffer.Pointer, 300 LocalOperand1->Buffer.Length); 301 break; 302 303 default: 304 305 /* Invalid object type, should not happen here */ 306 307 ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", 308 Operand0->Common.Type)); 309 Status = AE_AML_INTERNAL; 310 goto Cleanup; 311 } 312 313 *ActualReturnDesc = ReturnDesc; 314 315 Cleanup: 316 if (LocalOperand0 != Operand0) 317 { 318 AcpiUtRemoveReference (LocalOperand0); 319 } 320 321 if (LocalOperand1 != Operand1) 322 { 323 AcpiUtRemoveReference (LocalOperand1); 324 } 325 326 return_ACPI_STATUS (Status); 327 } 328 329 330 /******************************************************************************* 331 * 332 * FUNCTION: AcpiExConvertToObjectTypeString 333 * 334 * PARAMETERS: ObjDesc - Object to be converted 335 * ReturnDesc - Where to place the return object 336 * 337 * RETURN: Status 338 * 339 * DESCRIPTION: Convert an object of arbitrary type to a string object that 340 * contains the namestring for the object. Used for the 341 * concatenate operator. 342 * 343 ******************************************************************************/ 344 345 static ACPI_STATUS 346 AcpiExConvertToObjectTypeString ( 347 ACPI_OPERAND_OBJECT *ObjDesc, 348 ACPI_OPERAND_OBJECT **ResultDesc) 349 { 350 ACPI_OPERAND_OBJECT *ReturnDesc; 351 const char *TypeString; 352 353 354 TypeString = AcpiUtGetTypeName (ObjDesc->Common.Type); 355 356 ReturnDesc = AcpiUtCreateStringObject ( 357 ((ACPI_SIZE) strlen (TypeString) + 9)); /* 9 For "[ Object]" */ 358 if (!ReturnDesc) 359 { 360 return (AE_NO_MEMORY); 361 } 362 363 strcpy (ReturnDesc->String.Pointer, "["); 364 strcat (ReturnDesc->String.Pointer, TypeString); 365 strcat (ReturnDesc->String.Pointer, " Object]"); 366 367 *ResultDesc = ReturnDesc; 368 return (AE_OK); 369 } 370 371 372 /******************************************************************************* 373 * 374 * FUNCTION: AcpiExConcatTemplate 375 * 376 * PARAMETERS: Operand0 - First source object 377 * Operand1 - Second source object 378 * ActualReturnDesc - Where to place the return object 379 * WalkState - Current walk state 380 * 381 * RETURN: Status 382 * 383 * DESCRIPTION: Concatenate two resource templates 384 * 385 ******************************************************************************/ 386 387 ACPI_STATUS 388 AcpiExConcatTemplate ( 389 ACPI_OPERAND_OBJECT *Operand0, 390 ACPI_OPERAND_OBJECT *Operand1, 391 ACPI_OPERAND_OBJECT **ActualReturnDesc, 392 ACPI_WALK_STATE *WalkState) 393 { 394 ACPI_STATUS Status; 395 ACPI_OPERAND_OBJECT *ReturnDesc; 396 UINT8 *NewBuf; 397 UINT8 *EndTag; 398 ACPI_SIZE Length0; 399 ACPI_SIZE Length1; 400 ACPI_SIZE NewLength; 401 402 403 ACPI_FUNCTION_TRACE (ExConcatTemplate); 404 405 406 /* 407 * Find the EndTag descriptor in each resource template. 408 * Note1: returned pointers point TO the EndTag, not past it. 409 * Note2: zero-length buffers are allowed; treated like one EndTag 410 */ 411 412 /* Get the length of the first resource template */ 413 414 Status = AcpiUtGetResourceEndTag (Operand0, &EndTag); 415 if (ACPI_FAILURE (Status)) 416 { 417 return_ACPI_STATUS (Status); 418 } 419 420 Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer); 421 422 /* Get the length of the second resource template */ 423 424 Status = AcpiUtGetResourceEndTag (Operand1, &EndTag); 425 if (ACPI_FAILURE (Status)) 426 { 427 return_ACPI_STATUS (Status); 428 } 429 430 Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer); 431 432 /* Combine both lengths, minimum size will be 2 for EndTag */ 433 434 NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG); 435 436 /* Create a new buffer object for the result (with one EndTag) */ 437 438 ReturnDesc = AcpiUtCreateBufferObject (NewLength); 439 if (!ReturnDesc) 440 { 441 return_ACPI_STATUS (AE_NO_MEMORY); 442 } 443 444 /* 445 * Copy the templates to the new buffer, 0 first, then 1 follows. One 446 * EndTag descriptor is copied from Operand1. 447 */ 448 NewBuf = ReturnDesc->Buffer.Pointer; 449 memcpy (NewBuf, Operand0->Buffer.Pointer, Length0); 450 memcpy (NewBuf + Length0, Operand1->Buffer.Pointer, Length1); 451 452 /* Insert EndTag and set the checksum to zero, means "ignore checksum" */ 453 454 NewBuf[NewLength - 1] = 0; 455 NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1; 456 457 /* Return the completed resource template */ 458 459 *ActualReturnDesc = ReturnDesc; 460 return_ACPI_STATUS (AE_OK); 461 } 462