1297044Sjkim/****************************************************************************** 2297044Sjkim * 3297044Sjkim * Module Name: exconcat - Concatenate-type AML operators 4297044Sjkim * 5297044Sjkim *****************************************************************************/ 6297044Sjkim 7297044Sjkim/* 8297044Sjkim * Copyright (C) 2000 - 2016, Intel Corp. 9297044Sjkim * All rights reserved. 10297044Sjkim * 11297044Sjkim * Redistribution and use in source and binary forms, with or without 12297044Sjkim * modification, are permitted provided that the following conditions 13297044Sjkim * are met: 14297044Sjkim * 1. Redistributions of source code must retain the above copyright 15297044Sjkim * notice, this list of conditions, and the following disclaimer, 16297044Sjkim * without modification. 17297044Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18297044Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19297044Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20297044Sjkim * including a substantially similar Disclaimer requirement for further 21297044Sjkim * binary redistribution. 22297044Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23297044Sjkim * of any contributors may be used to endorse or promote products derived 24297044Sjkim * from this software without specific prior written permission. 25297044Sjkim * 26297044Sjkim * Alternatively, this software may be distributed under the terms of the 27297044Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28297044Sjkim * Software Foundation. 29297044Sjkim * 30297044Sjkim * NO WARRANTY 31297044Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32297044Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33297044Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34297044Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35297044Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36297044Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37297044Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38297044Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39297044Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40297044Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41297044Sjkim * POSSIBILITY OF SUCH DAMAGES. 42297044Sjkim */ 43297044Sjkim 44298714Sjkim#include <contrib/dev/acpica/include/acpi.h> 45298714Sjkim#include <contrib/dev/acpica/include/accommon.h> 46298714Sjkim#include <contrib/dev/acpica/include/acinterp.h> 47298714Sjkim#include <contrib/dev/acpica/include/amlresrc.h> 48297044Sjkim 49297044Sjkim 50297044Sjkim#define _COMPONENT ACPI_EXECUTER 51297044Sjkim ACPI_MODULE_NAME ("exconcat") 52297044Sjkim 53297044Sjkim/* Local Prototypes */ 54297044Sjkim 55297044Sjkimstatic ACPI_STATUS 56297044SjkimAcpiExConvertToObjectTypeString ( 57297044Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 58297044Sjkim ACPI_OPERAND_OBJECT **ResultDesc); 59297044Sjkim 60297044Sjkim 61297044Sjkim/******************************************************************************* 62297044Sjkim * 63297044Sjkim * FUNCTION: AcpiExDoConcatenate 64297044Sjkim * 65297044Sjkim * PARAMETERS: Operand0 - First source object 66297044Sjkim * Operand1 - Second source object 67297044Sjkim * ActualReturnDesc - Where to place the return object 68297044Sjkim * WalkState - Current walk state 69297044Sjkim * 70297044Sjkim * RETURN: Status 71297044Sjkim * 72297044Sjkim * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion 73297044Sjkim * rules as necessary. 74297044Sjkim * NOTE: 75297044Sjkim * Per the ACPI spec (up to 6.1), Concatenate only supports Integer, 76297044Sjkim * String, and Buffer objects. However, we support all objects here 77297044Sjkim * as an extension. This improves the usefulness of both Concatenate 78297044Sjkim * and the Printf/Fprintf macros. The extension returns a string 79297044Sjkim * describing the object type for the other objects. 80297044Sjkim * 02/2016. 81297044Sjkim * 82297044Sjkim ******************************************************************************/ 83297044Sjkim 84297044SjkimACPI_STATUS 85297044SjkimAcpiExDoConcatenate ( 86297044Sjkim ACPI_OPERAND_OBJECT *Operand0, 87297044Sjkim ACPI_OPERAND_OBJECT *Operand1, 88297044Sjkim ACPI_OPERAND_OBJECT **ActualReturnDesc, 89297044Sjkim ACPI_WALK_STATE *WalkState) 90297044Sjkim{ 91297044Sjkim ACPI_OPERAND_OBJECT *LocalOperand0 = Operand0; 92297044Sjkim ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; 93297044Sjkim ACPI_OPERAND_OBJECT *TempOperand1 = NULL; 94297044Sjkim ACPI_OPERAND_OBJECT *ReturnDesc; 95297044Sjkim char *Buffer; 96297044Sjkim ACPI_OBJECT_TYPE Operand0Type; 97297044Sjkim ACPI_OBJECT_TYPE Operand1Type; 98297044Sjkim ACPI_STATUS Status; 99297044Sjkim 100297044Sjkim 101297044Sjkim ACPI_FUNCTION_TRACE (ExDoConcatenate); 102297044Sjkim 103297044Sjkim 104297044Sjkim /* Operand 0 preprocessing */ 105297044Sjkim 106297044Sjkim switch (Operand0->Common.Type) 107297044Sjkim { 108297044Sjkim case ACPI_TYPE_INTEGER: 109297044Sjkim case ACPI_TYPE_STRING: 110297044Sjkim case ACPI_TYPE_BUFFER: 111297044Sjkim 112297044Sjkim Operand0Type = Operand0->Common.Type; 113297044Sjkim break; 114297044Sjkim 115297044Sjkim default: 116297044Sjkim 117297044Sjkim /* For all other types, get the "object type" string */ 118297044Sjkim 119297044Sjkim Status = AcpiExConvertToObjectTypeString ( 120297044Sjkim Operand0, &LocalOperand0); 121297044Sjkim if (ACPI_FAILURE (Status)) 122297044Sjkim { 123297044Sjkim goto Cleanup; 124297044Sjkim } 125297044Sjkim 126297044Sjkim Operand0Type = ACPI_TYPE_STRING; 127297044Sjkim break; 128297044Sjkim } 129297044Sjkim 130297044Sjkim /* Operand 1 preprocessing */ 131297044Sjkim 132297044Sjkim switch (Operand1->Common.Type) 133297044Sjkim { 134297044Sjkim case ACPI_TYPE_INTEGER: 135297044Sjkim case ACPI_TYPE_STRING: 136297044Sjkim case ACPI_TYPE_BUFFER: 137297044Sjkim 138297044Sjkim Operand1Type = Operand1->Common.Type; 139297044Sjkim break; 140297044Sjkim 141297044Sjkim default: 142297044Sjkim 143297044Sjkim /* For all other types, get the "object type" string */ 144297044Sjkim 145297044Sjkim Status = AcpiExConvertToObjectTypeString ( 146297044Sjkim Operand1, &LocalOperand1); 147297044Sjkim if (ACPI_FAILURE (Status)) 148297044Sjkim { 149297044Sjkim goto Cleanup; 150297044Sjkim } 151297044Sjkim 152297044Sjkim Operand1Type = ACPI_TYPE_STRING; 153297044Sjkim break; 154297044Sjkim } 155297044Sjkim 156297044Sjkim /* 157297044Sjkim * Convert the second operand if necessary. The first operand (0) 158297044Sjkim * determines the type of the second operand (1) (See the Data Types 159297044Sjkim * section of the ACPI specification). Both object types are 160297044Sjkim * guaranteed to be either Integer/String/Buffer by the operand 161297044Sjkim * resolution mechanism. 162297044Sjkim */ 163297044Sjkim switch (Operand0Type) 164297044Sjkim { 165297044Sjkim case ACPI_TYPE_INTEGER: 166297044Sjkim 167297044Sjkim Status = AcpiExConvertToInteger (LocalOperand1, &TempOperand1, 16); 168297044Sjkim break; 169297044Sjkim 170297044Sjkim case ACPI_TYPE_BUFFER: 171297044Sjkim 172297044Sjkim Status = AcpiExConvertToBuffer (LocalOperand1, &TempOperand1); 173297044Sjkim break; 174297044Sjkim 175297044Sjkim case ACPI_TYPE_STRING: 176297044Sjkim 177297044Sjkim switch (Operand1Type) 178297044Sjkim { 179297044Sjkim case ACPI_TYPE_INTEGER: 180297044Sjkim case ACPI_TYPE_STRING: 181297044Sjkim case ACPI_TYPE_BUFFER: 182297044Sjkim 183297044Sjkim /* Other types have already been converted to string */ 184297044Sjkim 185297044Sjkim Status = AcpiExConvertToString ( 186297044Sjkim LocalOperand1, &TempOperand1, ACPI_IMPLICIT_CONVERT_HEX); 187297044Sjkim break; 188297044Sjkim 189297044Sjkim default: 190297044Sjkim 191297044Sjkim Status = AE_OK; 192297044Sjkim break; 193297044Sjkim } 194297044Sjkim break; 195297044Sjkim 196297044Sjkim default: 197297044Sjkim 198297044Sjkim ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", 199297044Sjkim Operand0->Common.Type)); 200297044Sjkim Status = AE_AML_INTERNAL; 201297044Sjkim } 202297044Sjkim 203297044Sjkim if (ACPI_FAILURE (Status)) 204297044Sjkim { 205297044Sjkim goto Cleanup; 206297044Sjkim } 207297044Sjkim 208297044Sjkim /* Take care with any newly created operand objects */ 209297044Sjkim 210297044Sjkim if ((LocalOperand1 != Operand1) && 211297044Sjkim (LocalOperand1 != TempOperand1)) 212297044Sjkim { 213297044Sjkim AcpiUtRemoveReference (LocalOperand1); 214297044Sjkim } 215297044Sjkim 216297044Sjkim LocalOperand1 = TempOperand1; 217297044Sjkim 218297044Sjkim /* 219297044Sjkim * Both operands are now known to be the same object type 220297044Sjkim * (Both are Integer, String, or Buffer), and we can now perform 221297044Sjkim * the concatenation. 222297044Sjkim * 223297044Sjkim * There are three cases to handle, as per the ACPI spec: 224297044Sjkim * 225297044Sjkim * 1) Two Integers concatenated to produce a new Buffer 226297044Sjkim * 2) Two Strings concatenated to produce a new String 227297044Sjkim * 3) Two Buffers concatenated to produce a new Buffer 228297044Sjkim */ 229297044Sjkim switch (Operand0Type) 230297044Sjkim { 231297044Sjkim case ACPI_TYPE_INTEGER: 232297044Sjkim 233297044Sjkim /* Result of two Integers is a Buffer */ 234297044Sjkim /* Need enough buffer space for two integers */ 235297044Sjkim 236297044Sjkim ReturnDesc = AcpiUtCreateBufferObject ( 237297044Sjkim (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth)); 238297044Sjkim if (!ReturnDesc) 239297044Sjkim { 240297044Sjkim Status = AE_NO_MEMORY; 241297044Sjkim goto Cleanup; 242297044Sjkim } 243297044Sjkim 244297044Sjkim Buffer = (char *) ReturnDesc->Buffer.Pointer; 245297044Sjkim 246297044Sjkim /* Copy the first integer, LSB first */ 247297044Sjkim 248297044Sjkim memcpy (Buffer, &Operand0->Integer.Value, 249297044Sjkim AcpiGbl_IntegerByteWidth); 250297044Sjkim 251297044Sjkim /* Copy the second integer (LSB first) after the first */ 252297044Sjkim 253297044Sjkim memcpy (Buffer + AcpiGbl_IntegerByteWidth, 254297044Sjkim &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth); 255297044Sjkim break; 256297044Sjkim 257297044Sjkim case ACPI_TYPE_STRING: 258297044Sjkim 259297044Sjkim /* Result of two Strings is a String */ 260297044Sjkim 261297044Sjkim ReturnDesc = AcpiUtCreateStringObject ( 262297044Sjkim ((ACPI_SIZE) LocalOperand0->String.Length + 263297044Sjkim LocalOperand1->String.Length)); 264297044Sjkim if (!ReturnDesc) 265297044Sjkim { 266297044Sjkim Status = AE_NO_MEMORY; 267297044Sjkim goto Cleanup; 268297044Sjkim } 269297044Sjkim 270297044Sjkim Buffer = ReturnDesc->String.Pointer; 271297044Sjkim 272297044Sjkim /* Concatenate the strings */ 273297044Sjkim 274297044Sjkim strcpy (Buffer, LocalOperand0->String.Pointer); 275297044Sjkim strcat (Buffer, LocalOperand1->String.Pointer); 276297044Sjkim break; 277297044Sjkim 278297044Sjkim case ACPI_TYPE_BUFFER: 279297044Sjkim 280297044Sjkim /* Result of two Buffers is a Buffer */ 281297044Sjkim 282297044Sjkim ReturnDesc = AcpiUtCreateBufferObject ( 283297044Sjkim ((ACPI_SIZE) Operand0->Buffer.Length + 284297044Sjkim LocalOperand1->Buffer.Length)); 285297044Sjkim if (!ReturnDesc) 286297044Sjkim { 287297044Sjkim Status = AE_NO_MEMORY; 288297044Sjkim goto Cleanup; 289297044Sjkim } 290297044Sjkim 291297044Sjkim Buffer = (char *) ReturnDesc->Buffer.Pointer; 292297044Sjkim 293297044Sjkim /* Concatenate the buffers */ 294297044Sjkim 295297044Sjkim memcpy (Buffer, Operand0->Buffer.Pointer, 296297044Sjkim Operand0->Buffer.Length); 297297044Sjkim memcpy (Buffer + Operand0->Buffer.Length, 298297044Sjkim LocalOperand1->Buffer.Pointer, 299297044Sjkim LocalOperand1->Buffer.Length); 300297044Sjkim break; 301297044Sjkim 302297044Sjkim default: 303297044Sjkim 304297044Sjkim /* Invalid object type, should not happen here */ 305297044Sjkim 306297044Sjkim ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", 307297044Sjkim Operand0->Common.Type)); 308297044Sjkim Status = AE_AML_INTERNAL; 309297044Sjkim goto Cleanup; 310297044Sjkim } 311297044Sjkim 312297044Sjkim *ActualReturnDesc = ReturnDesc; 313297044Sjkim 314297044SjkimCleanup: 315297044Sjkim if (LocalOperand0 != Operand0) 316297044Sjkim { 317297044Sjkim AcpiUtRemoveReference (LocalOperand0); 318297044Sjkim } 319297044Sjkim 320297044Sjkim if (LocalOperand1 != Operand1) 321297044Sjkim { 322297044Sjkim AcpiUtRemoveReference (LocalOperand1); 323297044Sjkim } 324297044Sjkim 325297044Sjkim return_ACPI_STATUS (Status); 326297044Sjkim} 327297044Sjkim 328297044Sjkim 329297044Sjkim/******************************************************************************* 330297044Sjkim * 331297044Sjkim * FUNCTION: AcpiExConvertToObjectTypeString 332297044Sjkim * 333297044Sjkim * PARAMETERS: ObjDesc - Object to be converted 334297044Sjkim * ReturnDesc - Where to place the return object 335297044Sjkim * 336297044Sjkim * RETURN: Status 337297044Sjkim * 338297044Sjkim * DESCRIPTION: Convert an object of arbitrary type to a string object that 339297044Sjkim * contains the namestring for the object. Used for the 340297044Sjkim * concatenate operator. 341297044Sjkim * 342297044Sjkim ******************************************************************************/ 343297044Sjkim 344297044Sjkimstatic ACPI_STATUS 345297044SjkimAcpiExConvertToObjectTypeString ( 346297044Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 347297044Sjkim ACPI_OPERAND_OBJECT **ResultDesc) 348297044Sjkim{ 349297044Sjkim ACPI_OPERAND_OBJECT *ReturnDesc; 350297044Sjkim const char *TypeString; 351297044Sjkim 352297044Sjkim 353297044Sjkim TypeString = AcpiUtGetTypeName (ObjDesc->Common.Type); 354297044Sjkim 355297044Sjkim ReturnDesc = AcpiUtCreateStringObject ( 356297044Sjkim ((ACPI_SIZE) strlen (TypeString) + 9)); /* 9 For "[ Object]" */ 357297044Sjkim if (!ReturnDesc) 358297044Sjkim { 359297044Sjkim return (AE_NO_MEMORY); 360297044Sjkim } 361297044Sjkim 362297044Sjkim strcpy (ReturnDesc->String.Pointer, "["); 363297044Sjkim strcat (ReturnDesc->String.Pointer, TypeString); 364297044Sjkim strcat (ReturnDesc->String.Pointer, " Object]"); 365297044Sjkim 366297044Sjkim *ResultDesc = ReturnDesc; 367297044Sjkim return (AE_OK); 368297044Sjkim} 369297044Sjkim 370297044Sjkim 371297044Sjkim/******************************************************************************* 372297044Sjkim * 373297044Sjkim * FUNCTION: AcpiExConcatTemplate 374297044Sjkim * 375297044Sjkim * PARAMETERS: Operand0 - First source object 376297044Sjkim * Operand1 - Second source object 377297044Sjkim * ActualReturnDesc - Where to place the return object 378297044Sjkim * WalkState - Current walk state 379297044Sjkim * 380297044Sjkim * RETURN: Status 381297044Sjkim * 382297044Sjkim * DESCRIPTION: Concatenate two resource templates 383297044Sjkim * 384297044Sjkim ******************************************************************************/ 385297044Sjkim 386297044SjkimACPI_STATUS 387297044SjkimAcpiExConcatTemplate ( 388297044Sjkim ACPI_OPERAND_OBJECT *Operand0, 389297044Sjkim ACPI_OPERAND_OBJECT *Operand1, 390297044Sjkim ACPI_OPERAND_OBJECT **ActualReturnDesc, 391297044Sjkim ACPI_WALK_STATE *WalkState) 392297044Sjkim{ 393297044Sjkim ACPI_STATUS Status; 394297044Sjkim ACPI_OPERAND_OBJECT *ReturnDesc; 395297044Sjkim UINT8 *NewBuf; 396297044Sjkim UINT8 *EndTag; 397297044Sjkim ACPI_SIZE Length0; 398297044Sjkim ACPI_SIZE Length1; 399297044Sjkim ACPI_SIZE NewLength; 400297044Sjkim 401297044Sjkim 402297044Sjkim ACPI_FUNCTION_TRACE (ExConcatTemplate); 403297044Sjkim 404297044Sjkim 405297044Sjkim /* 406297044Sjkim * Find the EndTag descriptor in each resource template. 407297044Sjkim * Note1: returned pointers point TO the EndTag, not past it. 408297044Sjkim * Note2: zero-length buffers are allowed; treated like one EndTag 409297044Sjkim */ 410297044Sjkim 411297044Sjkim /* Get the length of the first resource template */ 412297044Sjkim 413297044Sjkim Status = AcpiUtGetResourceEndTag (Operand0, &EndTag); 414297044Sjkim if (ACPI_FAILURE (Status)) 415297044Sjkim { 416297044Sjkim return_ACPI_STATUS (Status); 417297044Sjkim } 418297044Sjkim 419297044Sjkim Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer); 420297044Sjkim 421297044Sjkim /* Get the length of the second resource template */ 422297044Sjkim 423297044Sjkim Status = AcpiUtGetResourceEndTag (Operand1, &EndTag); 424297044Sjkim if (ACPI_FAILURE (Status)) 425297044Sjkim { 426297044Sjkim return_ACPI_STATUS (Status); 427297044Sjkim } 428297044Sjkim 429297044Sjkim Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer); 430297044Sjkim 431297044Sjkim /* Combine both lengths, minimum size will be 2 for EndTag */ 432297044Sjkim 433297044Sjkim NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG); 434297044Sjkim 435297044Sjkim /* Create a new buffer object for the result (with one EndTag) */ 436297044Sjkim 437297044Sjkim ReturnDesc = AcpiUtCreateBufferObject (NewLength); 438297044Sjkim if (!ReturnDesc) 439297044Sjkim { 440297044Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 441297044Sjkim } 442297044Sjkim 443297044Sjkim /* 444297044Sjkim * Copy the templates to the new buffer, 0 first, then 1 follows. One 445297044Sjkim * EndTag descriptor is copied from Operand1. 446297044Sjkim */ 447297044Sjkim NewBuf = ReturnDesc->Buffer.Pointer; 448297044Sjkim memcpy (NewBuf, Operand0->Buffer.Pointer, Length0); 449297044Sjkim memcpy (NewBuf + Length0, Operand1->Buffer.Pointer, Length1); 450297044Sjkim 451297044Sjkim /* Insert EndTag and set the checksum to zero, means "ignore checksum" */ 452297044Sjkim 453297044Sjkim NewBuf[NewLength - 1] = 0; 454297044Sjkim NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1; 455297044Sjkim 456297044Sjkim /* Return the completed resource template */ 457297044Sjkim 458297044Sjkim *ActualReturnDesc = ReturnDesc; 459297044Sjkim return_ACPI_STATUS (AE_OK); 460297044Sjkim} 461