linux/drivers/acpi/acpica/exresolv.c
<<
>>
Prefs
   1
   2/******************************************************************************
   3 *
   4 * Module Name: exresolv - AML Interpreter object resolution
   5 *
   6 *****************************************************************************/
   7
   8/*
   9 * Copyright (C) 2000 - 2008, Intel Corp.
  10 * All rights reserved.
  11 *
  12 * Redistribution and use in source and binary forms, with or without
  13 * modification, are permitted provided that the following conditions
  14 * are met:
  15 * 1. Redistributions of source code must retain the above copyright
  16 *    notice, this list of conditions, and the following disclaimer,
  17 *    without modification.
  18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  19 *    substantially similar to the "NO WARRANTY" disclaimer below
  20 *    ("Disclaimer") and any redistribution must be conditioned upon
  21 *    including a substantially similar Disclaimer requirement for further
  22 *    binary redistribution.
  23 * 3. Neither the names of the above-listed copyright holders nor the names
  24 *    of any contributors may be used to endorse or promote products derived
  25 *    from this software without specific prior written permission.
  26 *
  27 * Alternatively, this software may be distributed under the terms of the
  28 * GNU General Public License ("GPL") version 2 as published by the Free
  29 * Software Foundation.
  30 *
  31 * NO WARRANTY
  32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42 * POSSIBILITY OF SUCH DAMAGES.
  43 */
  44
  45#include <acpi/acpi.h>
  46#include "accommon.h"
  47#include "amlcode.h"
  48#include "acdispat.h"
  49#include "acinterp.h"
  50#include "acnamesp.h"
  51
  52#define _COMPONENT          ACPI_EXECUTER
  53ACPI_MODULE_NAME("exresolv")
  54
  55/* Local prototypes */
  56static acpi_status
  57acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
  58                                struct acpi_walk_state *walk_state);
  59
  60/*******************************************************************************
  61 *
  62 * FUNCTION:    acpi_ex_resolve_to_value
  63 *
  64 * PARAMETERS:  **stack_ptr         - Points to entry on obj_stack, which can
  65 *                                    be either an (union acpi_operand_object *)
  66 *                                    or an acpi_handle.
  67 *              walk_state          - Current method state
  68 *
  69 * RETURN:      Status
  70 *
  71 * DESCRIPTION: Convert Reference objects to values
  72 *
  73 ******************************************************************************/
  74
  75acpi_status
  76acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr,
  77                         struct acpi_walk_state *walk_state)
  78{
  79        acpi_status status;
  80
  81        ACPI_FUNCTION_TRACE_PTR(ex_resolve_to_value, stack_ptr);
  82
  83        if (!stack_ptr || !*stack_ptr) {
  84                ACPI_ERROR((AE_INFO, "Internal - null pointer"));
  85                return_ACPI_STATUS(AE_AML_NO_OPERAND);
  86        }
  87
  88        /*
  89         * The entity pointed to by the stack_ptr can be either
  90         * 1) A valid union acpi_operand_object, or
  91         * 2) A struct acpi_namespace_node (named_obj)
  92         */
  93        if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_OPERAND) {
  94                status = acpi_ex_resolve_object_to_value(stack_ptr, walk_state);
  95                if (ACPI_FAILURE(status)) {
  96                        return_ACPI_STATUS(status);
  97                }
  98
  99                if (!*stack_ptr) {
 100                        ACPI_ERROR((AE_INFO, "Internal - null pointer"));
 101                        return_ACPI_STATUS(AE_AML_NO_OPERAND);
 102                }
 103        }
 104
 105        /*
 106         * Object on the stack may have changed if acpi_ex_resolve_object_to_value()
 107         * was called (i.e., we can't use an _else_ here.)
 108         */
 109        if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_NAMED) {
 110                status =
 111                    acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
 112                                                  (struct acpi_namespace_node,
 113                                                   stack_ptr), walk_state);
 114                if (ACPI_FAILURE(status)) {
 115                        return_ACPI_STATUS(status);
 116                }
 117        }
 118
 119        ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr));
 120        return_ACPI_STATUS(AE_OK);
 121}
 122
 123/*******************************************************************************
 124 *
 125 * FUNCTION:    acpi_ex_resolve_object_to_value
 126 *
 127 * PARAMETERS:  stack_ptr       - Pointer to an internal object
 128 *              walk_state      - Current method state
 129 *
 130 * RETURN:      Status
 131 *
 132 * DESCRIPTION: Retrieve the value from an internal object. The Reference type
 133 *              uses the associated AML opcode to determine the value.
 134 *
 135 ******************************************************************************/
 136
 137static acpi_status
 138acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
 139                                struct acpi_walk_state *walk_state)
 140{
 141        acpi_status status = AE_OK;
 142        union acpi_operand_object *stack_desc;
 143        union acpi_operand_object *obj_desc = NULL;
 144        u8 ref_type;
 145
 146        ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
 147
 148        stack_desc = *stack_ptr;
 149
 150        /* This is a union acpi_operand_object    */
 151
 152        switch (stack_desc->common.type) {
 153        case ACPI_TYPE_LOCAL_REFERENCE:
 154
 155                ref_type = stack_desc->reference.class;
 156
 157                switch (ref_type) {
 158                case ACPI_REFCLASS_LOCAL:
 159                case ACPI_REFCLASS_ARG:
 160
 161                        /*
 162                         * Get the local from the method's state info
 163                         * Note: this increments the local's object reference count
 164                         */
 165                        status = acpi_ds_method_data_get_value(ref_type,
 166                                                               stack_desc->
 167                                                               reference.value,
 168                                                               walk_state,
 169                                                               &obj_desc);
 170                        if (ACPI_FAILURE(status)) {
 171                                return_ACPI_STATUS(status);
 172                        }
 173
 174                        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 175                                          "[Arg/Local %X] ValueObj is %p\n",
 176                                          stack_desc->reference.value,
 177                                          obj_desc));
 178
 179                        /*
 180                         * Now we can delete the original Reference Object and
 181                         * replace it with the resolved value
 182                         */
 183                        acpi_ut_remove_reference(stack_desc);
 184                        *stack_ptr = obj_desc;
 185                        break;
 186
 187                case ACPI_REFCLASS_INDEX:
 188
 189                        switch (stack_desc->reference.target_type) {
 190                        case ACPI_TYPE_BUFFER_FIELD:
 191
 192                                /* Just return - do not dereference */
 193                                break;
 194
 195                        case ACPI_TYPE_PACKAGE:
 196
 197                                /* If method call or copy_object - do not dereference */
 198
 199                                if ((walk_state->opcode ==
 200                                     AML_INT_METHODCALL_OP)
 201                                    || (walk_state->opcode == AML_COPY_OP)) {
 202                                        break;
 203                                }
 204
 205                                /* Otherwise, dereference the package_index to a package element */
 206
 207                                obj_desc = *stack_desc->reference.where;
 208                                if (obj_desc) {
 209                                        /*
 210                                         * Valid object descriptor, copy pointer to return value
 211                                         * (i.e., dereference the package index)
 212                                         * Delete the ref object, increment the returned object
 213                                         */
 214                                        acpi_ut_remove_reference(stack_desc);
 215                                        acpi_ut_add_reference(obj_desc);
 216                                        *stack_ptr = obj_desc;
 217                                } else {
 218                                        /*
 219                                         * A NULL object descriptor means an uninitialized element of
 220                                         * the package, can't dereference it
 221                                         */
 222                                        ACPI_ERROR((AE_INFO,
 223                                                    "Attempt to dereference an Index to NULL package element Idx=%p",
 224                                                    stack_desc));
 225                                        status = AE_AML_UNINITIALIZED_ELEMENT;
 226                                }
 227                                break;
 228
 229                        default:
 230
 231                                /* Invalid reference object */
 232
 233                                ACPI_ERROR((AE_INFO,
 234                                            "Unknown TargetType %X in Index/Reference object %p",
 235                                            stack_desc->reference.target_type,
 236                                            stack_desc));
 237                                status = AE_AML_INTERNAL;
 238                                break;
 239                        }
 240                        break;
 241
 242                case ACPI_REFCLASS_REFOF:
 243                case ACPI_REFCLASS_DEBUG:
 244                case ACPI_REFCLASS_TABLE:
 245
 246                        /* Just leave the object as-is, do not dereference */
 247
 248                        break;
 249
 250                case ACPI_REFCLASS_NAME:        /* Reference to a named object */
 251
 252                        /* Dereference the name */
 253
 254                        if ((stack_desc->reference.node->type ==
 255                             ACPI_TYPE_DEVICE)
 256                            || (stack_desc->reference.node->type ==
 257                                ACPI_TYPE_THERMAL)) {
 258
 259                                /* These node types do not have 'real' subobjects */
 260
 261                                *stack_ptr = (void *)stack_desc->reference.node;
 262                        } else {
 263                                /* Get the object pointed to by the namespace node */
 264
 265                                *stack_ptr =
 266                                    (stack_desc->reference.node)->object;
 267                                acpi_ut_add_reference(*stack_ptr);
 268                        }
 269
 270                        acpi_ut_remove_reference(stack_desc);
 271                        break;
 272
 273                default:
 274
 275                        ACPI_ERROR((AE_INFO,
 276                                    "Unknown Reference type %X in %p", ref_type,
 277                                    stack_desc));
 278                        status = AE_AML_INTERNAL;
 279                        break;
 280                }
 281                break;
 282
 283        case ACPI_TYPE_BUFFER:
 284
 285                status = acpi_ds_get_buffer_arguments(stack_desc);
 286                break;
 287
 288        case ACPI_TYPE_PACKAGE:
 289
 290                status = acpi_ds_get_package_arguments(stack_desc);
 291                break;
 292
 293        case ACPI_TYPE_BUFFER_FIELD:
 294        case ACPI_TYPE_LOCAL_REGION_FIELD:
 295        case ACPI_TYPE_LOCAL_BANK_FIELD:
 296        case ACPI_TYPE_LOCAL_INDEX_FIELD:
 297
 298                ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 299                                  "FieldRead SourceDesc=%p Type=%X\n",
 300                                  stack_desc, stack_desc->common.type));
 301
 302                status =
 303                    acpi_ex_read_data_from_field(walk_state, stack_desc,
 304                                                 &obj_desc);
 305
 306                /* Remove a reference to the original operand, then override */
 307
 308                acpi_ut_remove_reference(*stack_ptr);
 309                *stack_ptr = (void *)obj_desc;
 310                break;
 311
 312        default:
 313                break;
 314        }
 315
 316        return_ACPI_STATUS(status);
 317}
 318
 319/*******************************************************************************
 320 *
 321 * FUNCTION:    acpi_ex_resolve_multiple
 322 *
 323 * PARAMETERS:  walk_state          - Current state (contains AML opcode)
 324 *              Operand             - Starting point for resolution
 325 *              return_type         - Where the object type is returned
 326 *              return_desc         - Where the resolved object is returned
 327 *
 328 * RETURN:      Status
 329 *
 330 * DESCRIPTION: Return the base object and type.  Traverse a reference list if
 331 *              necessary to get to the base object.
 332 *
 333 ******************************************************************************/
 334
 335acpi_status
 336acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
 337                         union acpi_operand_object *operand,
 338                         acpi_object_type * return_type,
 339                         union acpi_operand_object **return_desc)
 340{
 341        union acpi_operand_object *obj_desc = (void *)operand;
 342        struct acpi_namespace_node *node;
 343        acpi_object_type type;
 344        acpi_status status;
 345
 346        ACPI_FUNCTION_TRACE(acpi_ex_resolve_multiple);
 347
 348        /* Operand can be either a namespace node or an operand descriptor */
 349
 350        switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
 351        case ACPI_DESC_TYPE_OPERAND:
 352                type = obj_desc->common.type;
 353                break;
 354
 355        case ACPI_DESC_TYPE_NAMED:
 356                type = ((struct acpi_namespace_node *)obj_desc)->type;
 357                obj_desc =
 358                    acpi_ns_get_attached_object((struct acpi_namespace_node *)
 359                                                obj_desc);
 360
 361                /* If we had an Alias node, use the attached object for type info */
 362
 363                if (type == ACPI_TYPE_LOCAL_ALIAS) {
 364                        type = ((struct acpi_namespace_node *)obj_desc)->type;
 365                        obj_desc =
 366                            acpi_ns_get_attached_object((struct
 367                                                         acpi_namespace_node *)
 368                                                        obj_desc);
 369                }
 370                break;
 371
 372        default:
 373                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 374        }
 375
 376        /* If type is anything other than a reference, we are done */
 377
 378        if (type != ACPI_TYPE_LOCAL_REFERENCE) {
 379                goto exit;
 380        }
 381
 382        /*
 383         * For reference objects created via the ref_of, Index, or Load/load_table
 384         * operators, we need to get to the base object (as per the ACPI
 385         * specification of the object_type and size_of operators). This means
 386         * traversing the list of possibly many nested references.
 387         */
 388        while (obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
 389                switch (obj_desc->reference.class) {
 390                case ACPI_REFCLASS_REFOF:
 391                case ACPI_REFCLASS_NAME:
 392
 393                        /* Dereference the reference pointer */
 394
 395                        if (obj_desc->reference.class == ACPI_REFCLASS_REFOF) {
 396                                node = obj_desc->reference.object;
 397                        } else {        /* AML_INT_NAMEPATH_OP */
 398
 399                                node = obj_desc->reference.node;
 400                        }
 401
 402                        /* All "References" point to a NS node */
 403
 404                        if (ACPI_GET_DESCRIPTOR_TYPE(node) !=
 405                            ACPI_DESC_TYPE_NAMED) {
 406                                ACPI_ERROR((AE_INFO, "Not a NS node %p [%s]",
 407                                            node,
 408                                            acpi_ut_get_descriptor_name(node)));
 409                                return_ACPI_STATUS(AE_AML_INTERNAL);
 410                        }
 411
 412                        /* Get the attached object */
 413
 414                        obj_desc = acpi_ns_get_attached_object(node);
 415                        if (!obj_desc) {
 416
 417                                /* No object, use the NS node type */
 418
 419                                type = acpi_ns_get_type(node);
 420                                goto exit;
 421                        }
 422
 423                        /* Check for circular references */
 424
 425                        if (obj_desc == operand) {
 426                                return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE);
 427                        }
 428                        break;
 429
 430                case ACPI_REFCLASS_INDEX:
 431
 432                        /* Get the type of this reference (index into another object) */
 433
 434                        type = obj_desc->reference.target_type;
 435                        if (type != ACPI_TYPE_PACKAGE) {
 436                                goto exit;
 437                        }
 438
 439                        /*
 440                         * The main object is a package, we want to get the type
 441                         * of the individual package element that is referenced by
 442                         * the index.
 443                         *
 444                         * This could of course in turn be another reference object.
 445                         */
 446                        obj_desc = *(obj_desc->reference.where);
 447                        if (!obj_desc) {
 448
 449                                /* NULL package elements are allowed */
 450
 451                                type = 0;       /* Uninitialized */
 452                                goto exit;
 453                        }
 454                        break;
 455
 456                case ACPI_REFCLASS_TABLE:
 457
 458                        type = ACPI_TYPE_DDB_HANDLE;
 459                        goto exit;
 460
 461                case ACPI_REFCLASS_LOCAL:
 462                case ACPI_REFCLASS_ARG:
 463
 464                        if (return_desc) {
 465                                status =
 466                                    acpi_ds_method_data_get_value(obj_desc->
 467                                                                  reference.
 468                                                                  class,
 469                                                                  obj_desc->
 470                                                                  reference.
 471                                                                  value,
 472                                                                  walk_state,
 473                                                                  &obj_desc);
 474                                if (ACPI_FAILURE(status)) {
 475                                        return_ACPI_STATUS(status);
 476                                }
 477                                acpi_ut_remove_reference(obj_desc);
 478                        } else {
 479                                status =
 480                                    acpi_ds_method_data_get_node(obj_desc->
 481                                                                 reference.
 482                                                                 class,
 483                                                                 obj_desc->
 484                                                                 reference.
 485                                                                 value,
 486                                                                 walk_state,
 487                                                                 &node);
 488                                if (ACPI_FAILURE(status)) {
 489                                        return_ACPI_STATUS(status);
 490                                }
 491
 492                                obj_desc = acpi_ns_get_attached_object(node);
 493                                if (!obj_desc) {
 494                                        type = ACPI_TYPE_ANY;
 495                                        goto exit;
 496                                }
 497                        }
 498                        break;
 499
 500                case ACPI_REFCLASS_DEBUG:
 501
 502                        /* The Debug Object is of type "DebugObject" */
 503
 504                        type = ACPI_TYPE_DEBUG_OBJECT;
 505                        goto exit;
 506
 507                default:
 508
 509                        ACPI_ERROR((AE_INFO,
 510                                    "Unknown Reference Class %2.2X",
 511                                    obj_desc->reference.class));
 512                        return_ACPI_STATUS(AE_AML_INTERNAL);
 513                }
 514        }
 515
 516        /*
 517         * Now we are guaranteed to have an object that has not been created
 518         * via the ref_of or Index operators.
 519         */
 520        type = obj_desc->common.type;
 521
 522      exit:
 523        /* Convert internal types to external types */
 524
 525        switch (type) {
 526        case ACPI_TYPE_LOCAL_REGION_FIELD:
 527        case ACPI_TYPE_LOCAL_BANK_FIELD:
 528        case ACPI_TYPE_LOCAL_INDEX_FIELD:
 529
 530                type = ACPI_TYPE_FIELD_UNIT;
 531                break;
 532
 533        case ACPI_TYPE_LOCAL_SCOPE:
 534
 535                /* Per ACPI Specification, Scope is untyped */
 536
 537                type = ACPI_TYPE_ANY;
 538                break;
 539
 540        default:
 541                /* No change to Type required */
 542                break;
 543        }
 544
 545        *return_type = type;
 546        if (return_desc) {
 547                *return_desc = obj_desc;
 548        }
 549        return_ACPI_STATUS(AE_OK);
 550}
 551