linux/drivers/acpi/acpica/exconcat.c
<<
>>
Prefs
   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
  50ACPI_MODULE_NAME("exconcat")
  51
  52/* Local Prototypes */
  53static acpi_status
  54acpi_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
  80acpi_status
  81acpi_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
 307cleanup:
 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
 334static acpi_status
 335acpi_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
 371acpi_status
 372acpi_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