linux/drivers/acpi/acpica/nsparse.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: nsparse - namespace interface to AML parser
   5 *
   6 * Copyright (C) 2000 - 2018, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acnamesp.h"
  13#include "acparser.h"
  14#include "acdispat.h"
  15#include "actables.h"
  16#include "acinterp.h"
  17
  18#define _COMPONENT          ACPI_NAMESPACE
  19ACPI_MODULE_NAME("nsparse")
  20
  21/*******************************************************************************
  22 *
  23 * FUNCTION:    ns_execute_table
  24 *
  25 * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
  26 *              start_node      - Where to enter the table into the namespace
  27 *
  28 * RETURN:      Status
  29 *
  30 * DESCRIPTION: Load ACPI/AML table by executing the entire table as a single
  31 *              large control method.
  32 *
  33 * NOTE: The point of this is to execute any module-level code in-place
  34 * as the table is parsed. Some AML code depends on this behavior.
  35 *
  36 * It is a run-time option at this time, but will eventually become
  37 * the default.
  38 *
  39 * Note: This causes the table to only have a single-pass parse.
  40 * However, this is compatible with other ACPI implementations.
  41 *
  42 ******************************************************************************/
  43acpi_status
  44acpi_ns_execute_table(u32 table_index, struct acpi_namespace_node *start_node)
  45{
  46        acpi_status status;
  47        struct acpi_table_header *table;
  48        acpi_owner_id owner_id;
  49        struct acpi_evaluate_info *info = NULL;
  50        u32 aml_length;
  51        u8 *aml_start;
  52        union acpi_operand_object *method_obj = NULL;
  53
  54        ACPI_FUNCTION_TRACE(ns_execute_table);
  55
  56        status = acpi_get_table_by_index(table_index, &table);
  57        if (ACPI_FAILURE(status)) {
  58                return_ACPI_STATUS(status);
  59        }
  60
  61        /* Table must consist of at least a complete header */
  62
  63        if (table->length < sizeof(struct acpi_table_header)) {
  64                return_ACPI_STATUS(AE_BAD_HEADER);
  65        }
  66
  67        aml_start = (u8 *)table + sizeof(struct acpi_table_header);
  68        aml_length = table->length - sizeof(struct acpi_table_header);
  69
  70        status = acpi_tb_get_owner_id(table_index, &owner_id);
  71        if (ACPI_FAILURE(status)) {
  72                return_ACPI_STATUS(status);
  73        }
  74
  75        /* Create, initialize, and link a new temporary method object */
  76
  77        method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
  78        if (!method_obj) {
  79                return_ACPI_STATUS(AE_NO_MEMORY);
  80        }
  81
  82        /* Allocate the evaluation information block */
  83
  84        info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
  85        if (!info) {
  86                status = AE_NO_MEMORY;
  87                goto cleanup;
  88        }
  89
  90        ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
  91                              "%s: Create table pseudo-method for [%4.4s] @%p, method %p\n",
  92                              ACPI_GET_FUNCTION_NAME, table->signature, table,
  93                              method_obj));
  94
  95        method_obj->method.aml_start = aml_start;
  96        method_obj->method.aml_length = aml_length;
  97        method_obj->method.owner_id = owner_id;
  98        method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL;
  99
 100        info->pass_number = ACPI_IMODE_EXECUTE;
 101        info->node = start_node;
 102        info->obj_desc = method_obj;
 103        info->node_flags = info->node->flags;
 104        info->full_pathname = acpi_ns_get_normalized_pathname(info->node, TRUE);
 105        if (!info->full_pathname) {
 106                status = AE_NO_MEMORY;
 107                goto cleanup;
 108        }
 109
 110        status = acpi_ps_execute_table(info);
 111
 112cleanup:
 113        if (info) {
 114                ACPI_FREE(info->full_pathname);
 115                info->full_pathname = NULL;
 116        }
 117        ACPI_FREE(info);
 118        acpi_ut_remove_reference(method_obj);
 119        return_ACPI_STATUS(status);
 120}
 121
 122/*******************************************************************************
 123 *
 124 * FUNCTION:    ns_one_complete_parse
 125 *
 126 * PARAMETERS:  pass_number             - 1 or 2
 127 *              table_desc              - The table to be parsed.
 128 *
 129 * RETURN:      Status
 130 *
 131 * DESCRIPTION: Perform one complete parse of an ACPI/AML table.
 132 *
 133 ******************************************************************************/
 134
 135acpi_status
 136acpi_ns_one_complete_parse(u32 pass_number,
 137                           u32 table_index,
 138                           struct acpi_namespace_node *start_node)
 139{
 140        union acpi_parse_object *parse_root;
 141        acpi_status status;
 142        u32 aml_length;
 143        u8 *aml_start;
 144        struct acpi_walk_state *walk_state;
 145        struct acpi_table_header *table;
 146        acpi_owner_id owner_id;
 147
 148        ACPI_FUNCTION_TRACE(ns_one_complete_parse);
 149
 150        status = acpi_get_table_by_index(table_index, &table);
 151        if (ACPI_FAILURE(status)) {
 152                return_ACPI_STATUS(status);
 153        }
 154
 155        /* Table must consist of at least a complete header */
 156
 157        if (table->length < sizeof(struct acpi_table_header)) {
 158                return_ACPI_STATUS(AE_BAD_HEADER);
 159        }
 160
 161        aml_start = (u8 *)table + sizeof(struct acpi_table_header);
 162        aml_length = table->length - sizeof(struct acpi_table_header);
 163
 164        status = acpi_tb_get_owner_id(table_index, &owner_id);
 165        if (ACPI_FAILURE(status)) {
 166                return_ACPI_STATUS(status);
 167        }
 168
 169        /* Create and init a Root Node */
 170
 171        parse_root = acpi_ps_create_scope_op(aml_start);
 172        if (!parse_root) {
 173                return_ACPI_STATUS(AE_NO_MEMORY);
 174        }
 175
 176        /* Create and initialize a new walk state */
 177
 178        walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
 179        if (!walk_state) {
 180                acpi_ps_free_op(parse_root);
 181                return_ACPI_STATUS(AE_NO_MEMORY);
 182        }
 183
 184        status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
 185                                       aml_start, aml_length, NULL,
 186                                       (u8)pass_number);
 187        if (ACPI_FAILURE(status)) {
 188                acpi_ds_delete_walk_state(walk_state);
 189                goto cleanup;
 190        }
 191
 192        /* Found OSDT table, enable the namespace override feature */
 193
 194        if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT) &&
 195            pass_number == ACPI_IMODE_LOAD_PASS1) {
 196                walk_state->namespace_override = TRUE;
 197        }
 198
 199        /* start_node is the default location to load the table */
 200
 201        if (start_node && start_node != acpi_gbl_root_node) {
 202                status =
 203                    acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
 204                                             walk_state);
 205                if (ACPI_FAILURE(status)) {
 206                        acpi_ds_delete_walk_state(walk_state);
 207                        goto cleanup;
 208                }
 209        }
 210
 211        /* Parse the AML */
 212
 213        ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
 214                          "*PARSE* pass %u parse\n", pass_number));
 215        acpi_ex_enter_interpreter();
 216        status = acpi_ps_parse_aml(walk_state);
 217        acpi_ex_exit_interpreter();
 218
 219cleanup:
 220        acpi_ps_delete_parse_tree(parse_root);
 221        return_ACPI_STATUS(status);
 222}
 223
 224/*******************************************************************************
 225 *
 226 * FUNCTION:    acpi_ns_parse_table
 227 *
 228 * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
 229 *              start_node      - Where to enter the table into the namespace
 230 *
 231 * RETURN:      Status
 232 *
 233 * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
 234 *
 235 ******************************************************************************/
 236
 237acpi_status
 238acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node)
 239{
 240        acpi_status status;
 241
 242        ACPI_FUNCTION_TRACE(ns_parse_table);
 243
 244        if (acpi_gbl_execute_tables_as_methods) {
 245                /*
 246                 * This case executes the AML table as one large control method.
 247                 * The point of this is to execute any module-level code in-place
 248                 * as the table is parsed. Some AML code depends on this behavior.
 249                 *
 250                 * It is a run-time option at this time, but will eventually become
 251                 * the default.
 252                 *
 253                 * Note: This causes the table to only have a single-pass parse.
 254                 * However, this is compatible with other ACPI implementations.
 255                 */
 256                ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
 257                                      "%s: **** Start table execution pass\n",
 258                                      ACPI_GET_FUNCTION_NAME));
 259
 260                status = acpi_ns_execute_table(table_index, start_node);
 261                if (ACPI_FAILURE(status)) {
 262                        return_ACPI_STATUS(status);
 263                }
 264        } else {
 265                /*
 266                 * AML Parse, pass 1
 267                 *
 268                 * In this pass, we load most of the namespace. Control methods
 269                 * are not parsed until later. A parse tree is not created.
 270                 * Instead, each Parser Op subtree is deleted when it is finished.
 271                 * This saves a great deal of memory, and allows a small cache of
 272                 * parse objects to service the entire parse. The second pass of
 273                 * the parse then performs another complete parse of the AML.
 274                 */
 275                ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
 276
 277                status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1,
 278                                                    table_index, start_node);
 279                if (ACPI_FAILURE(status)) {
 280                        return_ACPI_STATUS(status);
 281                }
 282
 283                /*
 284                 * AML Parse, pass 2
 285                 *
 286                 * In this pass, we resolve forward references and other things
 287                 * that could not be completed during the first pass.
 288                 * Another complete parse of the AML is performed, but the
 289                 * overhead of this is compensated for by the fact that the
 290                 * parse objects are all cached.
 291                 */
 292                ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
 293                status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2,
 294                                                    table_index, start_node);
 295                if (ACPI_FAILURE(status)) {
 296                        return_ACPI_STATUS(status);
 297                }
 298        }
 299
 300        return_ACPI_STATUS(status);
 301}
 302