linux/drivers/acpi/acpica/nsconvert.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: nsconvert - Object conversions for objects returned by
   5 *                          predefined methods
   6 *
   7 * Copyright (C) 2000 - 2021, Intel Corp.
   8 *
   9 *****************************************************************************/
  10
  11#include <acpi/acpi.h>
  12#include "accommon.h"
  13#include "acnamesp.h"
  14#include "acinterp.h"
  15#include "acpredef.h"
  16#include "amlresrc.h"
  17
  18#define _COMPONENT          ACPI_NAMESPACE
  19ACPI_MODULE_NAME("nsconvert")
  20
  21/*******************************************************************************
  22 *
  23 * FUNCTION:    acpi_ns_convert_to_integer
  24 *
  25 * PARAMETERS:  original_object     - Object to be converted
  26 *              return_object       - Where the new converted object is returned
  27 *
  28 * RETURN:      Status. AE_OK if conversion was successful.
  29 *
  30 * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
  31 *
  32 ******************************************************************************/
  33acpi_status
  34acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
  35                           union acpi_operand_object **return_object)
  36{
  37        union acpi_operand_object *new_object;
  38        acpi_status status;
  39        u64 value = 0;
  40        u32 i;
  41
  42        switch (original_object->common.type) {
  43        case ACPI_TYPE_STRING:
  44
  45                /* String-to-Integer conversion */
  46
  47                status =
  48                    acpi_ut_strtoul64(original_object->string.pointer, &value);
  49                if (ACPI_FAILURE(status)) {
  50                        return (status);
  51                }
  52                break;
  53
  54        case ACPI_TYPE_BUFFER:
  55
  56                /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
  57
  58                if (original_object->buffer.length > 8) {
  59                        return (AE_AML_OPERAND_TYPE);
  60                }
  61
  62                /* Extract each buffer byte to create the integer */
  63
  64                for (i = 0; i < original_object->buffer.length; i++) {
  65                        value |= ((u64)
  66                                  original_object->buffer.pointer[i] << (i *
  67                                                                         8));
  68                }
  69                break;
  70
  71        default:
  72
  73                return (AE_AML_OPERAND_TYPE);
  74        }
  75
  76        new_object = acpi_ut_create_integer_object(value);
  77        if (!new_object) {
  78                return (AE_NO_MEMORY);
  79        }
  80
  81        *return_object = new_object;
  82        return (AE_OK);
  83}
  84
  85/*******************************************************************************
  86 *
  87 * FUNCTION:    acpi_ns_convert_to_string
  88 *
  89 * PARAMETERS:  original_object     - Object to be converted
  90 *              return_object       - Where the new converted object is returned
  91 *
  92 * RETURN:      Status. AE_OK if conversion was successful.
  93 *
  94 * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
  95 *
  96 ******************************************************************************/
  97
  98acpi_status
  99acpi_ns_convert_to_string(union acpi_operand_object *original_object,
 100                          union acpi_operand_object **return_object)
 101{
 102        union acpi_operand_object *new_object;
 103        acpi_size length;
 104        acpi_status status;
 105
 106        switch (original_object->common.type) {
 107        case ACPI_TYPE_INTEGER:
 108                /*
 109                 * Integer-to-String conversion. Commonly, convert
 110                 * an integer of value 0 to a NULL string. The last element of
 111                 * _BIF and _BIX packages occasionally need this fix.
 112                 */
 113                if (original_object->integer.value == 0) {
 114
 115                        /* Allocate a new NULL string object */
 116
 117                        new_object = acpi_ut_create_string_object(0);
 118                        if (!new_object) {
 119                                return (AE_NO_MEMORY);
 120                        }
 121                } else {
 122                        status = acpi_ex_convert_to_string(original_object,
 123                                                           &new_object,
 124                                                           ACPI_IMPLICIT_CONVERT_HEX);
 125                        if (ACPI_FAILURE(status)) {
 126                                return (status);
 127                        }
 128                }
 129                break;
 130
 131        case ACPI_TYPE_BUFFER:
 132                /*
 133                 * Buffer-to-String conversion. Use a to_string
 134                 * conversion, no transform performed on the buffer data. The best
 135                 * example of this is the _BIF method, where the string data from
 136                 * the battery is often (incorrectly) returned as buffer object(s).
 137                 */
 138                length = 0;
 139                while ((length < original_object->buffer.length) &&
 140                       (original_object->buffer.pointer[length])) {
 141                        length++;
 142                }
 143
 144                /* Allocate a new string object */
 145
 146                new_object = acpi_ut_create_string_object(length);
 147                if (!new_object) {
 148                        return (AE_NO_MEMORY);
 149                }
 150
 151                /*
 152                 * Copy the raw buffer data with no transform. String is already NULL
 153                 * terminated at Length+1.
 154                 */
 155                memcpy(new_object->string.pointer,
 156                       original_object->buffer.pointer, length);
 157                break;
 158
 159        default:
 160
 161                return (AE_AML_OPERAND_TYPE);
 162        }
 163
 164        *return_object = new_object;
 165        return (AE_OK);
 166}
 167
 168/*******************************************************************************
 169 *
 170 * FUNCTION:    acpi_ns_convert_to_buffer
 171 *
 172 * PARAMETERS:  original_object     - Object to be converted
 173 *              return_object       - Where the new converted object is returned
 174 *
 175 * RETURN:      Status. AE_OK if conversion was successful.
 176 *
 177 * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
 178 *
 179 ******************************************************************************/
 180
 181acpi_status
 182acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
 183                          union acpi_operand_object **return_object)
 184{
 185        union acpi_operand_object *new_object;
 186        acpi_status status;
 187        union acpi_operand_object **elements;
 188        u32 *dword_buffer;
 189        u32 count;
 190        u32 i;
 191
 192        switch (original_object->common.type) {
 193        case ACPI_TYPE_INTEGER:
 194                /*
 195                 * Integer-to-Buffer conversion.
 196                 * Convert the Integer to a packed-byte buffer. _MAT and other
 197                 * objects need this sometimes, if a read has been performed on a
 198                 * Field object that is less than or equal to the global integer
 199                 * size (32 or 64 bits).
 200                 */
 201                status =
 202                    acpi_ex_convert_to_buffer(original_object, &new_object);
 203                if (ACPI_FAILURE(status)) {
 204                        return (status);
 205                }
 206                break;
 207
 208        case ACPI_TYPE_STRING:
 209
 210                /* String-to-Buffer conversion. Simple data copy */
 211
 212                new_object = acpi_ut_create_buffer_object
 213                    (original_object->string.length);
 214                if (!new_object) {
 215                        return (AE_NO_MEMORY);
 216                }
 217
 218                memcpy(new_object->buffer.pointer,
 219                       original_object->string.pointer,
 220                       original_object->string.length);
 221                break;
 222
 223        case ACPI_TYPE_PACKAGE:
 224                /*
 225                 * This case is often seen for predefined names that must return a
 226                 * Buffer object with multiple DWORD integers within. For example,
 227                 * _FDE and _GTM. The Package can be converted to a Buffer.
 228                 */
 229
 230                /* All elements of the Package must be integers */
 231
 232                elements = original_object->package.elements;
 233                count = original_object->package.count;
 234
 235                for (i = 0; i < count; i++) {
 236                        if ((!*elements) ||
 237                            ((*elements)->common.type != ACPI_TYPE_INTEGER)) {
 238                                return (AE_AML_OPERAND_TYPE);
 239                        }
 240                        elements++;
 241                }
 242
 243                /* Create the new buffer object to replace the Package */
 244
 245                new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count));
 246                if (!new_object) {
 247                        return (AE_NO_MEMORY);
 248                }
 249
 250                /* Copy the package elements (integers) to the buffer as DWORDs */
 251
 252                elements = original_object->package.elements;
 253                dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer);
 254
 255                for (i = 0; i < count; i++) {
 256                        *dword_buffer = (u32)(*elements)->integer.value;
 257                        dword_buffer++;
 258                        elements++;
 259                }
 260                break;
 261
 262        default:
 263
 264                return (AE_AML_OPERAND_TYPE);
 265        }
 266
 267        *return_object = new_object;
 268        return (AE_OK);
 269}
 270
 271/*******************************************************************************
 272 *
 273 * FUNCTION:    acpi_ns_convert_to_unicode
 274 *
 275 * PARAMETERS:  scope               - Namespace node for the method/object
 276 *              original_object     - ASCII String Object to be converted
 277 *              return_object       - Where the new converted object is returned
 278 *
 279 * RETURN:      Status. AE_OK if conversion was successful.
 280 *
 281 * DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer.
 282 *
 283 ******************************************************************************/
 284
 285acpi_status
 286acpi_ns_convert_to_unicode(struct acpi_namespace_node *scope,
 287                           union acpi_operand_object *original_object,
 288                           union acpi_operand_object **return_object)
 289{
 290        union acpi_operand_object *new_object;
 291        char *ascii_string;
 292        u16 *unicode_buffer;
 293        u32 unicode_length;
 294        u32 i;
 295
 296        if (!original_object) {
 297                return (AE_OK);
 298        }
 299
 300        /* If a Buffer was returned, it must be at least two bytes long */
 301
 302        if (original_object->common.type == ACPI_TYPE_BUFFER) {
 303                if (original_object->buffer.length < 2) {
 304                        return (AE_AML_OPERAND_VALUE);
 305                }
 306
 307                *return_object = NULL;
 308                return (AE_OK);
 309        }
 310
 311        /*
 312         * The original object is an ASCII string. Convert this string to
 313         * a unicode buffer.
 314         */
 315        ascii_string = original_object->string.pointer;
 316        unicode_length = (original_object->string.length * 2) + 2;
 317
 318        /* Create a new buffer object for the Unicode data */
 319
 320        new_object = acpi_ut_create_buffer_object(unicode_length);
 321        if (!new_object) {
 322                return (AE_NO_MEMORY);
 323        }
 324
 325        unicode_buffer = ACPI_CAST_PTR(u16, new_object->buffer.pointer);
 326
 327        /* Convert ASCII to Unicode */
 328
 329        for (i = 0; i < original_object->string.length; i++) {
 330                unicode_buffer[i] = (u16)ascii_string[i];
 331        }
 332
 333        *return_object = new_object;
 334        return (AE_OK);
 335}
 336
 337/*******************************************************************************
 338 *
 339 * FUNCTION:    acpi_ns_convert_to_resource
 340 *
 341 * PARAMETERS:  scope               - Namespace node for the method/object
 342 *              original_object     - Object to be converted
 343 *              return_object       - Where the new converted object is returned
 344 *
 345 * RETURN:      Status. AE_OK if conversion was successful
 346 *
 347 * DESCRIPTION: Attempt to convert a Integer object to a resource_template
 348 *              Buffer.
 349 *
 350 ******************************************************************************/
 351
 352acpi_status
 353acpi_ns_convert_to_resource(struct acpi_namespace_node *scope,
 354                            union acpi_operand_object *original_object,
 355                            union acpi_operand_object **return_object)
 356{
 357        union acpi_operand_object *new_object;
 358        u8 *buffer;
 359
 360        /*
 361         * We can fix the following cases for an expected resource template:
 362         * 1. No return value (interpreter slack mode is disabled)
 363         * 2. A "Return (Zero)" statement
 364         * 3. A "Return empty buffer" statement
 365         *
 366         * We will return a buffer containing a single end_tag
 367         * resource descriptor.
 368         */
 369        if (original_object) {
 370                switch (original_object->common.type) {
 371                case ACPI_TYPE_INTEGER:
 372
 373                        /* We can only repair an Integer==0 */
 374
 375                        if (original_object->integer.value) {
 376                                return (AE_AML_OPERAND_TYPE);
 377                        }
 378                        break;
 379
 380                case ACPI_TYPE_BUFFER:
 381
 382                        if (original_object->buffer.length) {
 383
 384                                /* Additional checks can be added in the future */
 385
 386                                *return_object = NULL;
 387                                return (AE_OK);
 388                        }
 389                        break;
 390
 391                case ACPI_TYPE_STRING:
 392                default:
 393
 394                        return (AE_AML_OPERAND_TYPE);
 395                }
 396        }
 397
 398        /* Create the new buffer object for the resource descriptor */
 399
 400        new_object = acpi_ut_create_buffer_object(2);
 401        if (!new_object) {
 402                return (AE_NO_MEMORY);
 403        }
 404
 405        buffer = ACPI_CAST_PTR(u8, new_object->buffer.pointer);
 406
 407        /* Initialize the Buffer with a single end_tag descriptor */
 408
 409        buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE);
 410        buffer[1] = 0x00;
 411
 412        *return_object = new_object;
 413        return (AE_OK);
 414}
 415
 416/*******************************************************************************
 417 *
 418 * FUNCTION:    acpi_ns_convert_to_reference
 419 *
 420 * PARAMETERS:  scope               - Namespace node for the method/object
 421 *              original_object     - Object to be converted
 422 *              return_object       - Where the new converted object is returned
 423 *
 424 * RETURN:      Status. AE_OK if conversion was successful
 425 *
 426 * DESCRIPTION: Attempt to convert a Integer object to a object_reference.
 427 *              Buffer.
 428 *
 429 ******************************************************************************/
 430
 431acpi_status
 432acpi_ns_convert_to_reference(struct acpi_namespace_node *scope,
 433                             union acpi_operand_object *original_object,
 434                             union acpi_operand_object **return_object)
 435{
 436        union acpi_operand_object *new_object = NULL;
 437        acpi_status status;
 438        struct acpi_namespace_node *node;
 439        union acpi_generic_state scope_info;
 440        char *name;
 441
 442        ACPI_FUNCTION_NAME(ns_convert_to_reference);
 443
 444        /* Convert path into internal presentation */
 445
 446        status =
 447            acpi_ns_internalize_name(original_object->string.pointer, &name);
 448        if (ACPI_FAILURE(status)) {
 449                return_ACPI_STATUS(status);
 450        }
 451
 452        /* Find the namespace node */
 453
 454        scope_info.scope.node =
 455            ACPI_CAST_PTR(struct acpi_namespace_node, scope);
 456        status =
 457            acpi_ns_lookup(&scope_info, name, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
 458                           ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
 459                           NULL, &node);
 460        if (ACPI_FAILURE(status)) {
 461
 462                /* Check if we are resolving a named reference within a package */
 463
 464                ACPI_ERROR_NAMESPACE(&scope_info,
 465                                     original_object->string.pointer, status);
 466                goto error_exit;
 467        }
 468
 469        /* Create and init a new internal ACPI object */
 470
 471        new_object = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
 472        if (!new_object) {
 473                status = AE_NO_MEMORY;
 474                goto error_exit;
 475        }
 476        new_object->reference.node = node;
 477        new_object->reference.object = node->object;
 478        new_object->reference.class = ACPI_REFCLASS_NAME;
 479
 480        /*
 481         * Increase reference of the object if needed (the object is likely a
 482         * null for device nodes).
 483         */
 484        acpi_ut_add_reference(node->object);
 485
 486error_exit:
 487        ACPI_FREE(name);
 488        *return_object = new_object;
 489        return (status);
 490}
 491