linux/drivers/acpi/acpica/exconcat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: exconcat - Concatenate-type AML operators
   5 *
   6 * Copyright (C) 2000 - 2019, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acinterp.h"
  13#include "amlresrc.h"
  14
  15#define _COMPONENT          ACPI_EXECUTER
  16ACPI_MODULE_NAME("exconcat")
  17
  18/* Local Prototypes */
  19static acpi_status
  20acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
  21                                      union acpi_operand_object **result_desc);
  22
  23/*******************************************************************************
  24 *
  25 * FUNCTION:    acpi_ex_do_concatenate
  26 *
  27 * PARAMETERS:  operand0            - First source object
  28 *              operand1            - Second source object
  29 *              actual_return_desc  - Where to place the return object
  30 *              walk_state          - Current walk state
  31 *
  32 * RETURN:      Status
  33 *
  34 * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
  35 *              rules as necessary.
  36 * NOTE:
  37 * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
  38 * String, and Buffer objects. However, we support all objects here
  39 * as an extension. This improves the usefulness of both Concatenate
  40 * and the Printf/Fprintf macros. The extension returns a string
  41 * describing the object type for the other objects.
  42 * 02/2016.
  43 *
  44 ******************************************************************************/
  45
  46acpi_status
  47acpi_ex_do_concatenate(union acpi_operand_object *operand0,
  48                       union acpi_operand_object *operand1,
  49                       union acpi_operand_object **actual_return_desc,
  50                       struct acpi_walk_state *walk_state)
  51{
  52        union acpi_operand_object *local_operand0 = operand0;
  53        union acpi_operand_object *local_operand1 = operand1;
  54        union acpi_operand_object *temp_operand1 = NULL;
  55        union acpi_operand_object *return_desc;
  56        char *buffer;
  57        acpi_object_type operand0_type;
  58        acpi_object_type operand1_type;
  59        acpi_status status;
  60
  61        ACPI_FUNCTION_TRACE(ex_do_concatenate);
  62
  63        /* Operand 0 preprocessing */
  64
  65        switch (operand0->common.type) {
  66        case ACPI_TYPE_INTEGER:
  67        case ACPI_TYPE_STRING:
  68        case ACPI_TYPE_BUFFER:
  69
  70                operand0_type = operand0->common.type;
  71                break;
  72
  73        default:
  74
  75                /* For all other types, get the "object type" string */
  76
  77                status =
  78                    acpi_ex_convert_to_object_type_string(operand0,
  79                                                          &local_operand0);
  80                if (ACPI_FAILURE(status)) {
  81                        goto cleanup;
  82                }
  83
  84                operand0_type = ACPI_TYPE_STRING;
  85                break;
  86        }
  87
  88        /* Operand 1 preprocessing */
  89
  90        switch (operand1->common.type) {
  91        case ACPI_TYPE_INTEGER:
  92        case ACPI_TYPE_STRING:
  93        case ACPI_TYPE_BUFFER:
  94
  95                operand1_type = operand1->common.type;
  96                break;
  97
  98        default:
  99
 100                /* For all other types, get the "object type" string */
 101
 102                status =
 103                    acpi_ex_convert_to_object_type_string(operand1,
 104                                                          &local_operand1);
 105                if (ACPI_FAILURE(status)) {
 106                        goto cleanup;
 107                }
 108
 109                operand1_type = ACPI_TYPE_STRING;
 110                break;
 111        }
 112
 113        /*
 114         * Convert the second operand if necessary. The first operand (0)
 115         * determines the type of the second operand (1) (See the Data Types
 116         * section of the ACPI specification). Both object types are
 117         * guaranteed to be either Integer/String/Buffer by the operand
 118         * resolution mechanism.
 119         */
 120        switch (operand0_type) {
 121        case ACPI_TYPE_INTEGER:
 122
 123                status =
 124                    acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
 125                                               ACPI_IMPLICIT_CONVERSION);
 126                break;
 127
 128        case ACPI_TYPE_BUFFER:
 129
 130                status =
 131                    acpi_ex_convert_to_buffer(local_operand1, &temp_operand1);
 132                break;
 133
 134        case ACPI_TYPE_STRING:
 135
 136                switch (operand1_type) {
 137                case ACPI_TYPE_INTEGER:
 138                case ACPI_TYPE_STRING:
 139                case ACPI_TYPE_BUFFER:
 140
 141                        /* Other types have already been converted to string */
 142
 143                        status =
 144                            acpi_ex_convert_to_string(local_operand1,
 145                                                      &temp_operand1,
 146                                                      ACPI_IMPLICIT_CONVERT_HEX);
 147                        break;
 148
 149                default:
 150
 151                        status = AE_OK;
 152                        break;
 153                }
 154                break;
 155
 156        default:
 157
 158                ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
 159                            operand0->common.type));
 160                status = AE_AML_INTERNAL;
 161        }
 162
 163        if (ACPI_FAILURE(status)) {
 164                goto cleanup;
 165        }
 166
 167        /* Take care with any newly created operand objects */
 168
 169        if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) {
 170                acpi_ut_remove_reference(local_operand1);
 171        }
 172
 173        local_operand1 = temp_operand1;
 174
 175        /*
 176         * Both operands are now known to be the same object type
 177         * (Both are Integer, String, or Buffer), and we can now perform
 178         * the concatenation.
 179         *
 180         * There are three cases to handle, as per the ACPI spec:
 181         *
 182         * 1) Two Integers concatenated to produce a new Buffer
 183         * 2) Two Strings concatenated to produce a new String
 184         * 3) Two Buffers concatenated to produce a new Buffer
 185         */
 186        switch (operand0_type) {
 187        case ACPI_TYPE_INTEGER:
 188
 189                /* Result of two Integers is a Buffer */
 190                /* Need enough buffer space for two integers */
 191
 192                return_desc = acpi_ut_create_buffer_object((acpi_size)
 193                                                           ACPI_MUL_2
 194                                                           (acpi_gbl_integer_byte_width));
 195                if (!return_desc) {
 196                        status = AE_NO_MEMORY;
 197                        goto cleanup;
 198                }
 199
 200                buffer = (char *)return_desc->buffer.pointer;
 201
 202                /* Copy the first integer, LSB first */
 203
 204                memcpy(buffer, &operand0->integer.value,
 205                       acpi_gbl_integer_byte_width);
 206
 207                /* Copy the second integer (LSB first) after the first */
 208
 209                memcpy(buffer + acpi_gbl_integer_byte_width,
 210                       &local_operand1->integer.value,
 211                       acpi_gbl_integer_byte_width);
 212                break;
 213
 214        case ACPI_TYPE_STRING:
 215
 216                /* Result of two Strings is a String */
 217
 218                return_desc = acpi_ut_create_string_object(((acpi_size)
 219                                                            local_operand0->
 220                                                            string.length +
 221                                                            local_operand1->
 222                                                            string.length));
 223                if (!return_desc) {
 224                        status = AE_NO_MEMORY;
 225                        goto cleanup;
 226                }
 227
 228                buffer = return_desc->string.pointer;
 229
 230                /* Concatenate the strings */
 231
 232                strcpy(buffer, local_operand0->string.pointer);
 233                strcat(buffer, local_operand1->string.pointer);
 234                break;
 235
 236        case ACPI_TYPE_BUFFER:
 237
 238                /* Result of two Buffers is a Buffer */
 239
 240                return_desc = acpi_ut_create_buffer_object(((acpi_size)
 241                                                            operand0->buffer.
 242                                                            length +
 243                                                            local_operand1->
 244                                                            buffer.length));
 245                if (!return_desc) {
 246                        status = AE_NO_MEMORY;
 247                        goto cleanup;
 248                }
 249
 250                buffer = (char *)return_desc->buffer.pointer;
 251
 252                /* Concatenate the buffers */
 253
 254                memcpy(buffer, operand0->buffer.pointer,
 255                       operand0->buffer.length);
 256                memcpy(buffer + operand0->buffer.length,
 257                       local_operand1->buffer.pointer,
 258                       local_operand1->buffer.length);
 259                break;
 260
 261        default:
 262
 263                /* Invalid object type, should not happen here */
 264
 265                ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
 266                            operand0->common.type));
 267                status = AE_AML_INTERNAL;
 268                goto cleanup;
 269        }
 270
 271        *actual_return_desc = return_desc;
 272
 273cleanup:
 274        if (local_operand0 != operand0) {
 275                acpi_ut_remove_reference(local_operand0);
 276        }
 277
 278        if (local_operand1 != operand1) {
 279                acpi_ut_remove_reference(local_operand1);
 280        }
 281
 282        return_ACPI_STATUS(status);
 283}
 284
 285/*******************************************************************************
 286 *
 287 * FUNCTION:    acpi_ex_convert_to_object_type_string
 288 *
 289 * PARAMETERS:  obj_desc            - Object to be converted
 290 *              return_desc         - Where to place the return object
 291 *
 292 * RETURN:      Status
 293 *
 294 * DESCRIPTION: Convert an object of arbitrary type to a string object that
 295 *              contains the namestring for the object. Used for the
 296 *              concatenate operator.
 297 *
 298 ******************************************************************************/
 299
 300static acpi_status
 301acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
 302                                      union acpi_operand_object **result_desc)
 303{
 304        union acpi_operand_object *return_desc;
 305        const char *type_string;
 306
 307        type_string = acpi_ut_get_type_name(obj_desc->common.type);
 308
 309        return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9));       /* 9 For "[ Object]" */
 310        if (!return_desc) {
 311                return (AE_NO_MEMORY);
 312        }
 313
 314        strcpy(return_desc->string.pointer, "[");
 315        strcat(return_desc->string.pointer, type_string);
 316        strcat(return_desc->string.pointer, " Object]");
 317
 318        *result_desc = return_desc;
 319        return (AE_OK);
 320}
 321
 322/*******************************************************************************
 323 *
 324 * FUNCTION:    acpi_ex_concat_template
 325 *
 326 * PARAMETERS:  operand0            - First source object
 327 *              operand1            - Second source object
 328 *              actual_return_desc  - Where to place the return object
 329 *              walk_state          - Current walk state
 330 *
 331 * RETURN:      Status
 332 *
 333 * DESCRIPTION: Concatenate two resource templates
 334 *
 335 ******************************************************************************/
 336
 337acpi_status
 338acpi_ex_concat_template(union acpi_operand_object *operand0,
 339                        union acpi_operand_object *operand1,
 340                        union acpi_operand_object **actual_return_desc,
 341                        struct acpi_walk_state *walk_state)
 342{
 343        acpi_status status;
 344        union acpi_operand_object *return_desc;
 345        u8 *new_buf;
 346        u8 *end_tag;
 347        acpi_size length0;
 348        acpi_size length1;
 349        acpi_size new_length;
 350
 351        ACPI_FUNCTION_TRACE(ex_concat_template);
 352
 353        /*
 354         * Find the end_tag descriptor in each resource template.
 355         * Note1: returned pointers point TO the end_tag, not past it.
 356         * Note2: zero-length buffers are allowed; treated like one end_tag
 357         */
 358
 359        /* Get the length of the first resource template */
 360
 361        status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
 362        if (ACPI_FAILURE(status)) {
 363                return_ACPI_STATUS(status);
 364        }
 365
 366        length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
 367
 368        /* Get the length of the second resource template */
 369
 370        status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
 371        if (ACPI_FAILURE(status)) {
 372                return_ACPI_STATUS(status);
 373        }
 374
 375        length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
 376
 377        /* Combine both lengths, minimum size will be 2 for end_tag */
 378
 379        new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);
 380
 381        /* Create a new buffer object for the result (with one end_tag) */
 382
 383        return_desc = acpi_ut_create_buffer_object(new_length);
 384        if (!return_desc) {
 385                return_ACPI_STATUS(AE_NO_MEMORY);
 386        }
 387
 388        /*
 389         * Copy the templates to the new buffer, 0 first, then 1 follows. One
 390         * end_tag descriptor is copied from Operand1.
 391         */
 392        new_buf = return_desc->buffer.pointer;
 393        memcpy(new_buf, operand0->buffer.pointer, length0);
 394        memcpy(new_buf + length0, operand1->buffer.pointer, length1);
 395
 396        /* Insert end_tag and set the checksum to zero, means "ignore checksum" */
 397
 398        new_buf[new_length - 1] = 0;
 399        new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
 400
 401        /* Return the completed resource template */
 402
 403        *actual_return_desc = return_desc;
 404        return_ACPI_STATUS(AE_OK);
 405}
 406