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 - 2020, 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        /* Optional object evaluation log */
 111
 112        ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
 113                              "%-26s:  (Definition Block level)\n",
 114                              "Module-level evaluation"));
 115
 116        status = acpi_ps_execute_table(info);
 117
 118        /* Optional object evaluation log */
 119
 120        ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
 121                              "%-26s:  (Definition Block level)\n",
 122                              "Module-level complete"));
 123
 124cleanup:
 125        if (info) {
 126                ACPI_FREE(info->full_pathname);
 127                info->full_pathname = NULL;
 128        }
 129        ACPI_FREE(info);
 130        acpi_ut_remove_reference(method_obj);
 131        return_ACPI_STATUS(status);
 132}
 133
 134/*******************************************************************************
 135 *
 136 * FUNCTION:    ns_one_complete_parse
 137 *
 138 * PARAMETERS:  pass_number             - 1 or 2
 139 *              table_desc              - The table to be parsed.
 140 *
 141 * RETURN:      Status
 142 *
 143 * DESCRIPTION: Perform one complete parse of an ACPI/AML table.
 144 *
 145 ******************************************************************************/
 146
 147acpi_status
 148acpi_ns_one_complete_parse(u32 pass_number,
 149                           u32 table_index,
 150                           struct acpi_namespace_node *start_node)
 151{
 152        union acpi_parse_object *parse_root;
 153        acpi_status status;
 154        u32 aml_length;
 155        u8 *aml_start;
 156        struct acpi_walk_state *walk_state;
 157        struct acpi_table_header *table;
 158        acpi_owner_id owner_id;
 159
 160        ACPI_FUNCTION_TRACE(ns_one_complete_parse);
 161
 162        status = acpi_get_table_by_index(table_index, &table);
 163        if (ACPI_FAILURE(status)) {
 164                return_ACPI_STATUS(status);
 165        }
 166
 167        /* Table must consist of at least a complete header */
 168
 169        if (table->length < sizeof(struct acpi_table_header)) {
 170                return_ACPI_STATUS(AE_BAD_HEADER);
 171        }
 172
 173        aml_start = (u8 *)table + sizeof(struct acpi_table_header);
 174        aml_length = table->length - sizeof(struct acpi_table_header);
 175
 176        status = acpi_tb_get_owner_id(table_index, &owner_id);
 177        if (ACPI_FAILURE(status)) {
 178                return_ACPI_STATUS(status);
 179        }
 180
 181        /* Create and init a Root Node */
 182
 183        parse_root = acpi_ps_create_scope_op(aml_start);
 184        if (!parse_root) {
 185                return_ACPI_STATUS(AE_NO_MEMORY);
 186        }
 187
 188        /* Create and initialize a new walk state */
 189
 190        walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
 191        if (!walk_state) {
 192                acpi_ps_free_op(parse_root);
 193                return_ACPI_STATUS(AE_NO_MEMORY);
 194        }
 195
 196        status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
 197                                       aml_start, aml_length, NULL,
 198                                       (u8)pass_number);
 199        if (ACPI_FAILURE(status)) {
 200                acpi_ds_delete_walk_state(walk_state);
 201                goto cleanup;
 202        }
 203
 204        /* Found OSDT table, enable the namespace override feature */
 205
 206        if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_OSDT) &&
 207            pass_number == ACPI_IMODE_LOAD_PASS1) {
 208                walk_state->namespace_override = TRUE;
 209        }
 210
 211        /* start_node is the default location to load the table */
 212
 213        if (start_node && start_node != acpi_gbl_root_node) {
 214                status =
 215                    acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
 216                                             walk_state);
 217                if (ACPI_FAILURE(status)) {
 218                        acpi_ds_delete_walk_state(walk_state);
 219                        goto cleanup;
 220                }
 221        }
 222
 223        /* Parse the AML */
 224
 225        ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
 226                          "*PARSE* pass %u parse\n", pass_number));
 227        acpi_ex_enter_interpreter();
 228        status = acpi_ps_parse_aml(walk_state);
 229        acpi_ex_exit_interpreter();
 230
 231cleanup:
 232        acpi_ps_delete_parse_tree(parse_root);
 233        return_ACPI_STATUS(status);
 234}
 235
 236/*******************************************************************************
 237 *
 238 * FUNCTION:    acpi_ns_parse_table
 239 *
 240 * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
 241 *              start_node      - Where to enter the table into the namespace
 242 *
 243 * RETURN:      Status
 244 *
 245 * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
 246 *
 247 ******************************************************************************/
 248
 249acpi_status
 250acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node)
 251{
 252        acpi_status status;
 253
 254        ACPI_FUNCTION_TRACE(ns_parse_table);
 255
 256        /*
 257         * Executes the AML table as one large control method.
 258         * The point of this is to execute any module-level code in-place
 259         * as the table is parsed. Some AML code depends on this behavior.
 260         *
 261         * Note: This causes the table to only have a single-pass parse.
 262         * However, this is compatible with other ACPI implementations.
 263         */
 264        ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
 265                              "%s: **** Start table execution pass\n",
 266                              ACPI_GET_FUNCTION_NAME));
 267
 268        status = acpi_ns_execute_table(table_index, start_node);
 269
 270        return_ACPI_STATUS(status);
 271}
 272