399 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: exnames - interpreter/scanner name load/execute5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acinterp.h"13#include "amlcode.h"14 15#define _COMPONENT ACPI_EXECUTER16ACPI_MODULE_NAME("exnames")17 18/* Local prototypes */19static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs);20 21static acpi_status acpi_ex_name_segment(u8 **in_aml_address, char *name_string);22 23/*******************************************************************************24 *25 * FUNCTION: acpi_ex_allocate_name_string26 *27 * PARAMETERS: prefix_count - Count of parent levels. Special cases:28 * (-1)==root, 0==none29 * num_name_segs - count of 4-character name segments30 *31 * RETURN: A pointer to the allocated string segment. This segment must32 * be deleted by the caller.33 *34 * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name35 * string is long enough, and set up prefix if any.36 *37 ******************************************************************************/38 39static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs)40{41 char *temp_ptr;42 char *name_string;43 u32 size_needed;44 45 ACPI_FUNCTION_TRACE(ex_allocate_name_string);46 47 /*48 * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix.49 * Also, one byte for the null terminator.50 * This may actually be somewhat longer than needed.51 */52 if (prefix_count == ACPI_UINT32_MAX) {53 54 /* Special case for root */55 56 size_needed = 1 + (ACPI_NAMESEG_SIZE * num_name_segs) + 2 + 1;57 } else {58 size_needed =59 prefix_count + (ACPI_NAMESEG_SIZE * num_name_segs) + 2 + 1;60 }61 62 /*63 * Allocate a buffer for the name.64 * This buffer must be deleted by the caller!65 */66 name_string = ACPI_ALLOCATE(size_needed);67 if (!name_string) {68 ACPI_ERROR((AE_INFO,69 "Could not allocate size %u", size_needed));70 return_PTR(NULL);71 }72 73 temp_ptr = name_string;74 75 /* Set up Root or Parent prefixes if needed */76 77 if (prefix_count == ACPI_UINT32_MAX) {78 *temp_ptr++ = AML_ROOT_PREFIX;79 } else {80 while (prefix_count--) {81 *temp_ptr++ = AML_PARENT_PREFIX;82 }83 }84 85 /* Set up Dual or Multi prefixes if needed */86 87 if (num_name_segs > 2) {88 89 /* Set up multi prefixes */90 91 *temp_ptr++ = AML_MULTI_NAME_PREFIX;92 *temp_ptr++ = (char)num_name_segs;93 } else if (2 == num_name_segs) {94 95 /* Set up dual prefixes */96 97 *temp_ptr++ = AML_DUAL_NAME_PREFIX;98 }99 100 /*101 * Terminate string following prefixes. acpi_ex_name_segment() will102 * append the segment(s)103 */104 *temp_ptr = 0;105 106 return_PTR(name_string);107}108 109/*******************************************************************************110 *111 * FUNCTION: acpi_ex_name_segment112 *113 * PARAMETERS: in_aml_address - Pointer to the name in the AML code114 * name_string - Where to return the name. The name is appended115 * to any existing string to form a namepath116 *117 * RETURN: Status118 *119 * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream120 *121 ******************************************************************************/122 123static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string)124{125 char *aml_address = (void *)*in_aml_address;126 acpi_status status = AE_OK;127 u32 index;128 char char_buf[5];129 130 ACPI_FUNCTION_TRACE(ex_name_segment);131 132 /*133 * If first character is a digit, then we know that we aren't looking134 * at a valid name segment135 */136 char_buf[0] = *aml_address;137 138 if ('0' <= char_buf[0] && char_buf[0] <= '9') {139 ACPI_ERROR((AE_INFO, "Invalid leading digit: %c", char_buf[0]));140 return_ACPI_STATUS(AE_CTRL_PENDING);141 }142 143 for (index = 0;144 (index < ACPI_NAMESEG_SIZE)145 && (acpi_ut_valid_name_char(*aml_address, 0)); index++) {146 char_buf[index] = *aml_address++;147 }148 149 /* Valid name segment */150 151 if (index == 4) {152 153 /* Found 4 valid characters */154 155 char_buf[4] = '\0';156 157 if (name_string) {158 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,159 "Appending NameSeg %s\n", char_buf));160 strcat(name_string, char_buf);161 } else {162 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,163 "No Name string - %s\n", char_buf));164 }165 } else if (index == 0) {166 /*167 * First character was not a valid name character,168 * so we are looking at something other than a name.169 */170 ACPI_DEBUG_PRINT((ACPI_DB_INFO,171 "Leading character is not alpha: %02Xh (not a name)\n",172 char_buf[0]));173 status = AE_CTRL_PENDING;174 } else {175 /*176 * Segment started with one or more valid characters, but fewer than177 * the required 4178 */179 status = AE_AML_BAD_NAME;180 ACPI_ERROR((AE_INFO,181 "Bad character 0x%02x in name, at %p",182 *aml_address, aml_address));183 }184 185 *in_aml_address = ACPI_CAST_PTR(u8, aml_address);186 return_ACPI_STATUS(status);187}188 189/*******************************************************************************190 *191 * FUNCTION: acpi_ex_get_name_string192 *193 * PARAMETERS: data_type - Object type to be associated with this194 * name195 * in_aml_address - Pointer to the namestring in the AML code196 * out_name_string - Where the namestring is returned197 * out_name_length - Length of the returned string198 *199 * RETURN: Status, namestring and length200 *201 * DESCRIPTION: Extract a full namepath from the AML byte stream,202 * including any prefixes.203 *204 ******************************************************************************/205 206acpi_status207acpi_ex_get_name_string(acpi_object_type data_type,208 u8 * in_aml_address,209 char **out_name_string, u32 * out_name_length)210{211 acpi_status status = AE_OK;212 u8 *aml_address = in_aml_address;213 char *name_string = NULL;214 u32 num_segments;215 u32 prefix_count = 0;216 u8 has_prefix = FALSE;217 218 ACPI_FUNCTION_TRACE_PTR(ex_get_name_string, aml_address);219 220 if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type ||221 ACPI_TYPE_LOCAL_BANK_FIELD == data_type ||222 ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) {223 224 /* Disallow prefixes for types associated with field_unit names */225 226 name_string = acpi_ex_allocate_name_string(0, 1);227 if (!name_string) {228 status = AE_NO_MEMORY;229 } else {230 status =231 acpi_ex_name_segment(&aml_address, name_string);232 }233 } else {234 /*235 * data_type is not a field name.236 * Examine first character of name for root or parent prefix operators237 */238 switch (*aml_address) {239 case AML_ROOT_PREFIX:240 241 ACPI_DEBUG_PRINT((ACPI_DB_LOAD,242 "RootPrefix(\\) at %p\n",243 aml_address));244 245 /*246 * Remember that we have a root_prefix --247 * see comment in acpi_ex_allocate_name_string()248 */249 aml_address++;250 prefix_count = ACPI_UINT32_MAX;251 has_prefix = TRUE;252 break;253 254 case AML_PARENT_PREFIX:255 256 /* Increment past possibly multiple parent prefixes */257 258 do {259 ACPI_DEBUG_PRINT((ACPI_DB_LOAD,260 "ParentPrefix (^) at %p\n",261 aml_address));262 263 aml_address++;264 prefix_count++;265 266 } while (*aml_address == AML_PARENT_PREFIX);267 268 has_prefix = TRUE;269 break;270 271 default:272 273 /* Not a prefix character */274 275 break;276 }277 278 /* Examine first character of name for name segment prefix operator */279 280 switch (*aml_address) {281 case AML_DUAL_NAME_PREFIX:282 283 ACPI_DEBUG_PRINT((ACPI_DB_LOAD,284 "DualNamePrefix at %p\n",285 aml_address));286 287 aml_address++;288 name_string =289 acpi_ex_allocate_name_string(prefix_count, 2);290 if (!name_string) {291 status = AE_NO_MEMORY;292 break;293 }294 295 /* Indicate that we processed a prefix */296 297 has_prefix = TRUE;298 299 status =300 acpi_ex_name_segment(&aml_address, name_string);301 if (ACPI_SUCCESS(status)) {302 status =303 acpi_ex_name_segment(&aml_address,304 name_string);305 }306 break;307 308 case AML_MULTI_NAME_PREFIX:309 310 ACPI_DEBUG_PRINT((ACPI_DB_LOAD,311 "MultiNamePrefix at %p\n",312 aml_address));313 314 /* Fetch count of segments remaining in name path */315 316 aml_address++;317 num_segments = *aml_address;318 319 name_string =320 acpi_ex_allocate_name_string(prefix_count,321 num_segments);322 if (!name_string) {323 status = AE_NO_MEMORY;324 break;325 }326 327 /* Indicate that we processed a prefix */328 329 aml_address++;330 has_prefix = TRUE;331 332 while (num_segments &&333 (status =334 acpi_ex_name_segment(&aml_address,335 name_string)) == AE_OK) {336 num_segments--;337 }338 339 break;340 341 case 0:342 343 /* null_name valid as of 8-12-98 ASL/AML Grammar Update */344 345 if (prefix_count == ACPI_UINT32_MAX) {346 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,347 "NameSeg is \"\\\" followed by NULL\n"));348 }349 350 /* Consume the NULL byte */351 352 aml_address++;353 name_string =354 acpi_ex_allocate_name_string(prefix_count, 0);355 if (!name_string) {356 status = AE_NO_MEMORY;357 break;358 }359 360 break;361 362 default:363 364 /* Name segment string */365 366 name_string =367 acpi_ex_allocate_name_string(prefix_count, 1);368 if (!name_string) {369 status = AE_NO_MEMORY;370 break;371 }372 373 status =374 acpi_ex_name_segment(&aml_address, name_string);375 break;376 }377 }378 379 if (AE_CTRL_PENDING == status && has_prefix) {380 381 /* Ran out of segments after processing a prefix */382 383 ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string));384 status = AE_AML_BAD_NAME;385 }386 387 if (ACPI_FAILURE(status)) {388 if (name_string) {389 ACPI_FREE(name_string);390 }391 return_ACPI_STATUS(status);392 }393 394 *out_name_string = name_string;395 *out_name_length = (u32) (aml_address - in_aml_address);396 397 return_ACPI_STATUS(status);398}399