linux/drivers/acpi/acpica/excreate.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: excreate - Named object creation
   5 *
   6 * Copyright (C) 2000 - 2018, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acinterp.h"
  13#include "amlcode.h"
  14#include "acnamesp.h"
  15
  16#define _COMPONENT          ACPI_EXECUTER
  17ACPI_MODULE_NAME("excreate")
  18#ifndef ACPI_NO_METHOD_EXECUTION
  19/*******************************************************************************
  20 *
  21 * FUNCTION:    acpi_ex_create_alias
  22 *
  23 * PARAMETERS:  walk_state           - Current state, contains operands
  24 *
  25 * RETURN:      Status
  26 *
  27 * DESCRIPTION: Create a new named alias
  28 *
  29 ******************************************************************************/
  30acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
  31{
  32        struct acpi_namespace_node *target_node;
  33        struct acpi_namespace_node *alias_node;
  34        acpi_status status = AE_OK;
  35
  36        ACPI_FUNCTION_TRACE(ex_create_alias);
  37
  38        /* Get the source/alias operands (both namespace nodes) */
  39
  40        alias_node = (struct acpi_namespace_node *)walk_state->operands[0];
  41        target_node = (struct acpi_namespace_node *)walk_state->operands[1];
  42
  43        if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) ||
  44            (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
  45                /*
  46                 * Dereference an existing alias so that we don't create a chain
  47                 * of aliases. With this code, we guarantee that an alias is
  48                 * always exactly one level of indirection away from the
  49                 * actual aliased name.
  50                 */
  51                target_node =
  52                    ACPI_CAST_PTR(struct acpi_namespace_node,
  53                                  target_node->object);
  54        }
  55
  56        /* Ensure that the target node is valid */
  57
  58        if (!target_node) {
  59                return_ACPI_STATUS(AE_NULL_OBJECT);
  60        }
  61
  62        /* Construct the alias object (a namespace node) */
  63
  64        switch (target_node->type) {
  65        case ACPI_TYPE_METHOD:
  66                /*
  67                 * Control method aliases need to be differentiated with
  68                 * a special type
  69                 */
  70                alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
  71                break;
  72
  73        default:
  74                /*
  75                 * All other object types.
  76                 *
  77                 * The new alias has the type ALIAS and points to the original
  78                 * NS node, not the object itself.
  79                 */
  80                alias_node->type = ACPI_TYPE_LOCAL_ALIAS;
  81                alias_node->object =
  82                    ACPI_CAST_PTR(union acpi_operand_object, target_node);
  83                break;
  84        }
  85
  86        /* Since both operands are Nodes, we don't need to delete them */
  87
  88        alias_node->object =
  89            ACPI_CAST_PTR(union acpi_operand_object, target_node);
  90        return_ACPI_STATUS(status);
  91}
  92
  93/*******************************************************************************
  94 *
  95 * FUNCTION:    acpi_ex_create_event
  96 *
  97 * PARAMETERS:  walk_state          - Current state
  98 *
  99 * RETURN:      Status
 100 *
 101 * DESCRIPTION: Create a new event object
 102 *
 103 ******************************************************************************/
 104
 105acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state)
 106{
 107        acpi_status status;
 108        union acpi_operand_object *obj_desc;
 109
 110        ACPI_FUNCTION_TRACE(ex_create_event);
 111
 112        obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_EVENT);
 113        if (!obj_desc) {
 114                status = AE_NO_MEMORY;
 115                goto cleanup;
 116        }
 117
 118        /*
 119         * Create the actual OS semaphore, with zero initial units -- meaning
 120         * that the event is created in an unsignalled state
 121         */
 122        status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0,
 123                                          &obj_desc->event.os_semaphore);
 124        if (ACPI_FAILURE(status)) {
 125                goto cleanup;
 126        }
 127
 128        /* Attach object to the Node */
 129
 130        status = acpi_ns_attach_object((struct acpi_namespace_node *)
 131                                       walk_state->operands[0], obj_desc,
 132                                       ACPI_TYPE_EVENT);
 133
 134cleanup:
 135        /*
 136         * Remove local reference to the object (on error, will cause deletion
 137         * of both object and semaphore if present.)
 138         */
 139        acpi_ut_remove_reference(obj_desc);
 140        return_ACPI_STATUS(status);
 141}
 142
 143/*******************************************************************************
 144 *
 145 * FUNCTION:    acpi_ex_create_mutex
 146 *
 147 * PARAMETERS:  walk_state          - Current state
 148 *
 149 * RETURN:      Status
 150 *
 151 * DESCRIPTION: Create a new mutex object
 152 *
 153 *              Mutex (Name[0], sync_level[1])
 154 *
 155 ******************************************************************************/
 156
 157acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state)
 158{
 159        acpi_status status = AE_OK;
 160        union acpi_operand_object *obj_desc;
 161
 162        ACPI_FUNCTION_TRACE_PTR(ex_create_mutex, ACPI_WALK_OPERANDS);
 163
 164        /* Create the new mutex object */
 165
 166        obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
 167        if (!obj_desc) {
 168                status = AE_NO_MEMORY;
 169                goto cleanup;
 170        }
 171
 172        /* Create the actual OS Mutex */
 173
 174        status = acpi_os_create_mutex(&obj_desc->mutex.os_mutex);
 175        if (ACPI_FAILURE(status)) {
 176                goto cleanup;
 177        }
 178
 179        /* Init object and attach to NS node */
 180
 181        obj_desc->mutex.sync_level = (u8)walk_state->operands[1]->integer.value;
 182        obj_desc->mutex.node =
 183            (struct acpi_namespace_node *)walk_state->operands[0];
 184
 185        status =
 186            acpi_ns_attach_object(obj_desc->mutex.node, obj_desc,
 187                                  ACPI_TYPE_MUTEX);
 188
 189cleanup:
 190        /*
 191         * Remove local reference to the object (on error, will cause deletion
 192         * of both object and semaphore if present.)
 193         */
 194        acpi_ut_remove_reference(obj_desc);
 195        return_ACPI_STATUS(status);
 196}
 197
 198/*******************************************************************************
 199 *
 200 * FUNCTION:    acpi_ex_create_region
 201 *
 202 * PARAMETERS:  aml_start           - Pointer to the region declaration AML
 203 *              aml_length          - Max length of the declaration AML
 204 *              space_id            - Address space ID for the region
 205 *              walk_state          - Current state
 206 *
 207 * RETURN:      Status
 208 *
 209 * DESCRIPTION: Create a new operation region object
 210 *
 211 ******************************************************************************/
 212
 213acpi_status
 214acpi_ex_create_region(u8 * aml_start,
 215                      u32 aml_length,
 216                      u8 space_id, struct acpi_walk_state *walk_state)
 217{
 218        acpi_status status;
 219        union acpi_operand_object *obj_desc;
 220        struct acpi_namespace_node *node;
 221        union acpi_operand_object *region_obj2;
 222
 223        ACPI_FUNCTION_TRACE(ex_create_region);
 224
 225        /* Get the Namespace Node */
 226
 227        node = walk_state->op->common.node;
 228
 229        /*
 230         * If the region object is already attached to this node,
 231         * just return
 232         */
 233        if (acpi_ns_get_attached_object(node)) {
 234                return_ACPI_STATUS(AE_OK);
 235        }
 236
 237        /*
 238         * Space ID must be one of the predefined IDs, or in the user-defined
 239         * range
 240         */
 241        if (!acpi_is_valid_space_id(space_id)) {
 242                /*
 243                 * Print an error message, but continue. We don't want to abort
 244                 * a table load for this exception. Instead, if the region is
 245                 * actually used at runtime, abort the executing method.
 246                 */
 247                ACPI_ERROR((AE_INFO,
 248                            "Invalid/unknown Address Space ID: 0x%2.2X",
 249                            space_id));
 250        }
 251
 252        ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n",
 253                          acpi_ut_get_region_name(space_id), space_id));
 254
 255        /* Create the region descriptor */
 256
 257        obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
 258        if (!obj_desc) {
 259                status = AE_NO_MEMORY;
 260                goto cleanup;
 261        }
 262
 263        /*
 264         * Remember location in AML stream of address & length
 265         * operands since they need to be evaluated at run time.
 266         */
 267        region_obj2 = acpi_ns_get_secondary_object(obj_desc);
 268        region_obj2->extra.aml_start = aml_start;
 269        region_obj2->extra.aml_length = aml_length;
 270        region_obj2->extra.method_REG = NULL;
 271        if (walk_state->scope_info) {
 272                region_obj2->extra.scope_node =
 273                    walk_state->scope_info->scope.node;
 274        } else {
 275                region_obj2->extra.scope_node = node;
 276        }
 277
 278        /* Init the region from the operands */
 279
 280        obj_desc->region.space_id = space_id;
 281        obj_desc->region.address = 0;
 282        obj_desc->region.length = 0;
 283        obj_desc->region.node = node;
 284        obj_desc->region.handler = NULL;
 285        obj_desc->common.flags &=
 286            ~(AOPOBJ_SETUP_COMPLETE | AOPOBJ_REG_CONNECTED |
 287              AOPOBJ_OBJECT_INITIALIZED);
 288
 289        /* Install the new region object in the parent Node */
 290
 291        status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION);
 292
 293cleanup:
 294
 295        /* Remove local reference to the object */
 296
 297        acpi_ut_remove_reference(obj_desc);
 298        return_ACPI_STATUS(status);
 299}
 300
 301/*******************************************************************************
 302 *
 303 * FUNCTION:    acpi_ex_create_processor
 304 *
 305 * PARAMETERS:  walk_state          - Current state
 306 *
 307 * RETURN:      Status
 308 *
 309 * DESCRIPTION: Create a new processor object and populate the fields
 310 *
 311 *              Processor (Name[0], cpu_ID[1], pblock_addr[2], pblock_length[3])
 312 *
 313 ******************************************************************************/
 314
 315acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state)
 316{
 317        union acpi_operand_object **operand = &walk_state->operands[0];
 318        union acpi_operand_object *obj_desc;
 319        acpi_status status;
 320
 321        ACPI_FUNCTION_TRACE_PTR(ex_create_processor, walk_state);
 322
 323        /* Create the processor object */
 324
 325        obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PROCESSOR);
 326        if (!obj_desc) {
 327                return_ACPI_STATUS(AE_NO_MEMORY);
 328        }
 329
 330        /* Initialize the processor object from the operands */
 331
 332        obj_desc->processor.proc_id = (u8) operand[1]->integer.value;
 333        obj_desc->processor.length = (u8) operand[3]->integer.value;
 334        obj_desc->processor.address =
 335            (acpi_io_address)operand[2]->integer.value;
 336
 337        /* Install the processor object in the parent Node */
 338
 339        status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0],
 340                                       obj_desc, ACPI_TYPE_PROCESSOR);
 341
 342        /* Remove local reference to the object */
 343
 344        acpi_ut_remove_reference(obj_desc);
 345        return_ACPI_STATUS(status);
 346}
 347
 348/*******************************************************************************
 349 *
 350 * FUNCTION:    acpi_ex_create_power_resource
 351 *
 352 * PARAMETERS:  walk_state          - Current state
 353 *
 354 * RETURN:      Status
 355 *
 356 * DESCRIPTION: Create a new power_resource object and populate the fields
 357 *
 358 *              power_resource (Name[0], system_level[1], resource_order[2])
 359 *
 360 ******************************************************************************/
 361
 362acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state)
 363{
 364        union acpi_operand_object **operand = &walk_state->operands[0];
 365        acpi_status status;
 366        union acpi_operand_object *obj_desc;
 367
 368        ACPI_FUNCTION_TRACE_PTR(ex_create_power_resource, walk_state);
 369
 370        /* Create the power resource object */
 371
 372        obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_POWER);
 373        if (!obj_desc) {
 374                return_ACPI_STATUS(AE_NO_MEMORY);
 375        }
 376
 377        /* Initialize the power object from the operands */
 378
 379        obj_desc->power_resource.system_level = (u8) operand[1]->integer.value;
 380        obj_desc->power_resource.resource_order =
 381            (u16) operand[2]->integer.value;
 382
 383        /* Install the  power resource object in the parent Node */
 384
 385        status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0],
 386                                       obj_desc, ACPI_TYPE_POWER);
 387
 388        /* Remove local reference to the object */
 389
 390        acpi_ut_remove_reference(obj_desc);
 391        return_ACPI_STATUS(status);
 392}
 393#endif
 394
 395/*******************************************************************************
 396 *
 397 * FUNCTION:    acpi_ex_create_method
 398 *
 399 * PARAMETERS:  aml_start       - First byte of the method's AML
 400 *              aml_length      - AML byte count for this method
 401 *              walk_state      - Current state
 402 *
 403 * RETURN:      Status
 404 *
 405 * DESCRIPTION: Create a new method object
 406 *
 407 ******************************************************************************/
 408
 409acpi_status
 410acpi_ex_create_method(u8 * aml_start,
 411                      u32 aml_length, struct acpi_walk_state *walk_state)
 412{
 413        union acpi_operand_object **operand = &walk_state->operands[0];
 414        union acpi_operand_object *obj_desc;
 415        acpi_status status;
 416        u8 method_flags;
 417
 418        ACPI_FUNCTION_TRACE_PTR(ex_create_method, walk_state);
 419
 420        /* Create a new method object */
 421
 422        obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
 423        if (!obj_desc) {
 424                status = AE_NO_MEMORY;
 425                goto exit;
 426        }
 427
 428        /* Save the method's AML pointer and length  */
 429
 430        obj_desc->method.aml_start = aml_start;
 431        obj_desc->method.aml_length = aml_length;
 432        obj_desc->method.node = operand[0];
 433
 434        /*
 435         * Disassemble the method flags. Split off the arg_count, Serialized
 436         * flag, and sync_level for efficiency.
 437         */
 438        method_flags = (u8)operand[1]->integer.value;
 439        obj_desc->method.param_count = (u8)
 440            (method_flags & AML_METHOD_ARG_COUNT);
 441
 442        /*
 443         * Get the sync_level. If method is serialized, a mutex will be
 444         * created for this method when it is parsed.
 445         */
 446        if (method_flags & AML_METHOD_SERIALIZED) {
 447                obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED;
 448
 449                /*
 450                 * ACPI 1.0: sync_level = 0
 451                 * ACPI 2.0: sync_level = sync_level in method declaration
 452                 */
 453                obj_desc->method.sync_level = (u8)
 454                    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
 455        }
 456
 457        /* Attach the new object to the method Node */
 458
 459        status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0],
 460                                       obj_desc, ACPI_TYPE_METHOD);
 461
 462        /* Remove local reference to the object */
 463
 464        acpi_ut_remove_reference(obj_desc);
 465
 466exit:
 467        /* Remove a reference to the operand */
 468
 469        acpi_ut_remove_reference(operand[1]);
 470        return_ACPI_STATUS(status);
 471}
 472