732 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing5 * parents and siblings and Scope manipulation6 *7 * Copyright (C) 2000 - 2023, Intel Corp.8 *9 *****************************************************************************/10 11#include <acpi/acpi.h>12#include "accommon.h"13#include "acnamesp.h"14#include "amlcode.h"15 16#define _COMPONENT ACPI_NAMESPACE17ACPI_MODULE_NAME("nsutils")18 19/* Local prototypes */20#ifdef ACPI_OBSOLETE_FUNCTIONS21acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);22#endif23 24/*******************************************************************************25 *26 * FUNCTION: acpi_ns_print_node_pathname27 *28 * PARAMETERS: node - Object29 * message - Prefix message30 *31 * DESCRIPTION: Print an object's full namespace pathname32 * Manages allocation/freeing of a pathname buffer33 *34 ******************************************************************************/35 36void37acpi_ns_print_node_pathname(struct acpi_namespace_node *node,38 const char *message)39{40 struct acpi_buffer buffer;41 acpi_status status;42 43 if (!node) {44 acpi_os_printf("[NULL NAME]");45 return;46 }47 48 /* Convert handle to full pathname and print it (with supplied message) */49 50 buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;51 52 status = acpi_ns_handle_to_pathname(node, &buffer, TRUE);53 if (ACPI_SUCCESS(status)) {54 if (message) {55 acpi_os_printf("%s ", message);56 }57 58 acpi_os_printf("%s", (char *)buffer.pointer);59 ACPI_FREE(buffer.pointer);60 }61}62 63/*******************************************************************************64 *65 * FUNCTION: acpi_ns_get_type66 *67 * PARAMETERS: node - Parent Node to be examined68 *69 * RETURN: Type field from Node whose handle is passed70 *71 * DESCRIPTION: Return the type of a Namespace node72 *73 ******************************************************************************/74 75acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node)76{77 ACPI_FUNCTION_TRACE(ns_get_type);78 79 if (!node) {80 ACPI_WARNING((AE_INFO, "Null Node parameter"));81 return_UINT8(ACPI_TYPE_ANY);82 }83 84 return_UINT8(node->type);85}86 87/*******************************************************************************88 *89 * FUNCTION: acpi_ns_local90 *91 * PARAMETERS: type - A namespace object type92 *93 * RETURN: LOCAL if names must be found locally in objects of the94 * passed type, 0 if enclosing scopes should be searched95 *96 * DESCRIPTION: Returns scope rule for the given object type.97 *98 ******************************************************************************/99 100u32 acpi_ns_local(acpi_object_type type)101{102 ACPI_FUNCTION_TRACE(ns_local);103 104 if (!acpi_ut_valid_object_type(type)) {105 106 /* Type code out of range */107 108 ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));109 return_UINT32(ACPI_NS_NORMAL);110 }111 112 return_UINT32(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);113}114 115/*******************************************************************************116 *117 * FUNCTION: acpi_ns_get_internal_name_length118 *119 * PARAMETERS: info - Info struct initialized with the120 * external name pointer.121 *122 * RETURN: None123 *124 * DESCRIPTION: Calculate the length of the internal (AML) namestring125 * corresponding to the external (ASL) namestring.126 *127 ******************************************************************************/128 129void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info)130{131 const char *next_external_char;132 u32 i;133 134 ACPI_FUNCTION_ENTRY();135 136 next_external_char = info->external_name;137 info->num_carats = 0;138 info->num_segments = 0;139 info->fully_qualified = FALSE;140 141 /*142 * For the internal name, the required length is 4 bytes per segment,143 * plus 1 each for root_prefix, multi_name_prefix_op, segment count,144 * trailing null (which is not really needed, but no there's harm in145 * putting it there)146 *147 * strlen() + 1 covers the first name_seg, which has no path separator148 */149 if (ACPI_IS_ROOT_PREFIX(*next_external_char)) {150 info->fully_qualified = TRUE;151 next_external_char++;152 153 /* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */154 155 while (ACPI_IS_ROOT_PREFIX(*next_external_char)) {156 next_external_char++;157 }158 } else {159 /* Handle Carat prefixes */160 161 while (ACPI_IS_PARENT_PREFIX(*next_external_char)) {162 info->num_carats++;163 next_external_char++;164 }165 }166 167 /*168 * Determine the number of ACPI name "segments" by counting the number of169 * path separators within the string. Start with one segment since the170 * segment count is [(# separators) + 1], and zero separators is ok.171 */172 if (*next_external_char) {173 info->num_segments = 1;174 for (i = 0; next_external_char[i]; i++) {175 if (ACPI_IS_PATH_SEPARATOR(next_external_char[i])) {176 info->num_segments++;177 }178 }179 }180 181 info->length = (ACPI_NAMESEG_SIZE * info->num_segments) +182 4 + info->num_carats;183 184 info->next_external_char = next_external_char;185}186 187/*******************************************************************************188 *189 * FUNCTION: acpi_ns_build_internal_name190 *191 * PARAMETERS: info - Info struct fully initialized192 *193 * RETURN: Status194 *195 * DESCRIPTION: Construct the internal (AML) namestring196 * corresponding to the external (ASL) namestring.197 *198 ******************************************************************************/199 200acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)201{202 u32 num_segments = info->num_segments;203 char *internal_name = info->internal_name;204 const char *external_name = info->next_external_char;205 char *result = NULL;206 u32 i;207 208 ACPI_FUNCTION_TRACE(ns_build_internal_name);209 210 /* Setup the correct prefixes, counts, and pointers */211 212 if (info->fully_qualified) {213 internal_name[0] = AML_ROOT_PREFIX;214 215 if (num_segments <= 1) {216 result = &internal_name[1];217 } else if (num_segments == 2) {218 internal_name[1] = AML_DUAL_NAME_PREFIX;219 result = &internal_name[2];220 } else {221 internal_name[1] = AML_MULTI_NAME_PREFIX;222 internal_name[2] = (char)num_segments;223 result = &internal_name[3];224 }225 } else {226 /*227 * Not fully qualified.228 * Handle Carats first, then append the name segments229 */230 i = 0;231 if (info->num_carats) {232 for (i = 0; i < info->num_carats; i++) {233 internal_name[i] = AML_PARENT_PREFIX;234 }235 }236 237 if (num_segments <= 1) {238 result = &internal_name[i];239 } else if (num_segments == 2) {240 internal_name[i] = AML_DUAL_NAME_PREFIX;241 result = &internal_name[(acpi_size)i + 1];242 } else {243 internal_name[i] = AML_MULTI_NAME_PREFIX;244 internal_name[(acpi_size)i + 1] = (char)num_segments;245 result = &internal_name[(acpi_size)i + 2];246 }247 }248 249 /* Build the name (minus path separators) */250 251 for (; num_segments; num_segments--) {252 for (i = 0; i < ACPI_NAMESEG_SIZE; i++) {253 if (ACPI_IS_PATH_SEPARATOR(*external_name) ||254 (*external_name == 0)) {255 256 /* Pad the segment with underscore(s) if segment is short */257 258 result[i] = '_';259 } else {260 /* Convert the character to uppercase and save it */261 262 result[i] = (char)toupper((int)*external_name);263 external_name++;264 }265 }266 267 /* Now we must have a path separator, or the pathname is bad */268 269 if (!ACPI_IS_PATH_SEPARATOR(*external_name) &&270 (*external_name != 0)) {271 return_ACPI_STATUS(AE_BAD_PATHNAME);272 }273 274 /* Move on the next segment */275 276 external_name++;277 result += ACPI_NAMESEG_SIZE;278 }279 280 /* Terminate the string */281 282 *result = 0;283 284 if (info->fully_qualified) {285 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,286 "Returning [%p] (abs) \"\\%s\"\n",287 internal_name, internal_name));288 } else {289 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n",290 internal_name, internal_name));291 }292 293 return_ACPI_STATUS(AE_OK);294}295 296/*******************************************************************************297 *298 * FUNCTION: acpi_ns_internalize_name299 *300 * PARAMETERS: *external_name - External representation of name301 * **Converted name - Where to return the resulting302 * internal represention of the name303 *304 * RETURN: Status305 *306 * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")307 * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)308 *309 *******************************************************************************/310 311acpi_status312acpi_ns_internalize_name(const char *external_name, char **converted_name)313{314 char *internal_name;315 struct acpi_namestring_info info;316 acpi_status status;317 318 ACPI_FUNCTION_TRACE(ns_internalize_name);319 320 if ((!external_name) || (*external_name == 0) || (!converted_name)) {321 return_ACPI_STATUS(AE_BAD_PARAMETER);322 }323 324 /* Get the length of the new internal name */325 326 info.external_name = external_name;327 acpi_ns_get_internal_name_length(&info);328 329 /* We need a segment to store the internal name */330 331 internal_name = ACPI_ALLOCATE_ZEROED(info.length);332 if (!internal_name) {333 return_ACPI_STATUS(AE_NO_MEMORY);334 }335 336 /* Build the name */337 338 info.internal_name = internal_name;339 status = acpi_ns_build_internal_name(&info);340 if (ACPI_FAILURE(status)) {341 ACPI_FREE(internal_name);342 return_ACPI_STATUS(status);343 }344 345 *converted_name = internal_name;346 return_ACPI_STATUS(AE_OK);347}348 349/*******************************************************************************350 *351 * FUNCTION: acpi_ns_externalize_name352 *353 * PARAMETERS: internal_name_length - Length of the internal name below354 * internal_name - Internal representation of name355 * converted_name_length - Where the length is returned356 * converted_name - Where the resulting external name357 * is returned358 *359 * RETURN: Status360 *361 * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)362 * to its external (printable) form (e.g. "\_PR_.CPU0")363 *364 ******************************************************************************/365 366acpi_status367acpi_ns_externalize_name(u32 internal_name_length,368 const char *internal_name,369 u32 * converted_name_length, char **converted_name)370{371 u32 names_index = 0;372 u32 num_segments = 0;373 u32 required_length;374 u32 prefix_length = 0;375 u32 i = 0;376 u32 j = 0;377 378 ACPI_FUNCTION_TRACE(ns_externalize_name);379 380 if (!internal_name_length || !internal_name || !converted_name) {381 return_ACPI_STATUS(AE_BAD_PARAMETER);382 }383 384 /* Check for a prefix (one '\' | one or more '^') */385 386 switch (internal_name[0]) {387 case AML_ROOT_PREFIX:388 389 prefix_length = 1;390 break;391 392 case AML_PARENT_PREFIX:393 394 for (i = 0; i < internal_name_length; i++) {395 if (ACPI_IS_PARENT_PREFIX(internal_name[i])) {396 prefix_length = i + 1;397 } else {398 break;399 }400 }401 402 if (i == internal_name_length) {403 prefix_length = i;404 }405 406 break;407 408 default:409 410 break;411 }412 413 /*414 * Check for object names. Note that there could be 0-255 of these415 * 4-byte elements.416 */417 if (prefix_length < internal_name_length) {418 switch (internal_name[prefix_length]) {419 case AML_MULTI_NAME_PREFIX:420 421 /* <count> 4-byte names */422 423 names_index = prefix_length + 2;424 num_segments = (u8)425 internal_name[(acpi_size)prefix_length + 1];426 break;427 428 case AML_DUAL_NAME_PREFIX:429 430 /* Two 4-byte names */431 432 names_index = prefix_length + 1;433 num_segments = 2;434 break;435 436 case 0:437 438 /* null_name */439 440 names_index = 0;441 num_segments = 0;442 break;443 444 default:445 446 /* one 4-byte name */447 448 names_index = prefix_length;449 num_segments = 1;450 break;451 }452 }453 454 /*455 * Calculate the length of converted_name, which equals the length456 * of the prefix, length of all object names, length of any required457 * punctuation ('.') between object names, plus the NULL terminator.458 */459 required_length = prefix_length + (4 * num_segments) +460 ((num_segments > 0) ? (num_segments - 1) : 0) + 1;461 462 /*463 * Check to see if we're still in bounds. If not, there's a problem464 * with internal_name (invalid format).465 */466 if (required_length > internal_name_length) {467 ACPI_ERROR((AE_INFO, "Invalid internal name"));468 return_ACPI_STATUS(AE_BAD_PATHNAME);469 }470 471 /* Build the converted_name */472 473 *converted_name = ACPI_ALLOCATE_ZEROED(required_length);474 if (!(*converted_name)) {475 return_ACPI_STATUS(AE_NO_MEMORY);476 }477 478 j = 0;479 480 for (i = 0; i < prefix_length; i++) {481 (*converted_name)[j++] = internal_name[i];482 }483 484 if (num_segments > 0) {485 for (i = 0; i < num_segments; i++) {486 if (i > 0) {487 (*converted_name)[j++] = '.';488 }489 490 /* Copy and validate the 4-char name segment */491 492 ACPI_COPY_NAMESEG(&(*converted_name)[j],493 &internal_name[names_index]);494 acpi_ut_repair_name(&(*converted_name)[j]);495 496 j += ACPI_NAMESEG_SIZE;497 names_index += ACPI_NAMESEG_SIZE;498 }499 }500 501 if (converted_name_length) {502 *converted_name_length = (u32) required_length;503 }504 505 return_ACPI_STATUS(AE_OK);506}507 508/*******************************************************************************509 *510 * FUNCTION: acpi_ns_validate_handle511 *512 * PARAMETERS: handle - Handle to be validated and typecast to a513 * namespace node.514 *515 * RETURN: A pointer to a namespace node516 *517 * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special518 * cases for the root node.519 *520 * NOTE: Real integer handles would allow for more verification521 * and keep all pointers within this subsystem - however this introduces522 * more overhead and has not been necessary to this point. Drivers523 * holding handles are typically notified before a node becomes invalid524 * due to a table unload.525 *526 ******************************************************************************/527 528struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle)529{530 531 ACPI_FUNCTION_ENTRY();532 533 /* Parameter validation */534 535 if ((!handle) || (handle == ACPI_ROOT_OBJECT)) {536 return (acpi_gbl_root_node);537 }538 539 /* We can at least attempt to verify the handle */540 541 if (ACPI_GET_DESCRIPTOR_TYPE(handle) != ACPI_DESC_TYPE_NAMED) {542 return (NULL);543 }544 545 return (ACPI_CAST_PTR(struct acpi_namespace_node, handle));546}547 548/*******************************************************************************549 *550 * FUNCTION: acpi_ns_terminate551 *552 * PARAMETERS: none553 *554 * RETURN: none555 *556 * DESCRIPTION: free memory allocated for namespace and ACPI table storage.557 *558 ******************************************************************************/559 560void acpi_ns_terminate(void)561{562 acpi_status status;563 564 ACPI_FUNCTION_TRACE(ns_terminate);565 566 /*567 * Free the entire namespace -- all nodes and all objects568 * attached to the nodes569 */570 acpi_ns_delete_namespace_subtree(acpi_gbl_root_node);571 572 /* Delete any objects attached to the root node */573 574 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);575 if (ACPI_FAILURE(status)) {576 return_VOID;577 }578 579 acpi_ns_delete_node(acpi_gbl_root_node);580 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);581 582 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));583 return_VOID;584}585 586/*******************************************************************************587 *588 * FUNCTION: acpi_ns_opens_scope589 *590 * PARAMETERS: type - A valid namespace type591 *592 * RETURN: NEWSCOPE if the passed type "opens a name scope" according593 * to the ACPI specification, else 0594 *595 ******************************************************************************/596 597u32 acpi_ns_opens_scope(acpi_object_type type)598{599 ACPI_FUNCTION_ENTRY();600 601 if (type > ACPI_TYPE_LOCAL_MAX) {602 603 /* type code out of range */604 605 ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));606 return (ACPI_NS_NORMAL);607 }608 609 return (((u32)acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE);610}611 612/*******************************************************************************613 *614 * FUNCTION: acpi_ns_get_node_unlocked615 *616 * PARAMETERS: *pathname - Name to be found, in external (ASL) format. The617 * \ (backslash) and ^ (carat) prefixes, and the618 * . (period) to separate segments are supported.619 * prefix_node - Root of subtree to be searched, or NS_ALL for the620 * root of the name space. If Name is fully621 * qualified (first s8 is '\'), the passed value622 * of Scope will not be accessed.623 * flags - Used to indicate whether to perform upsearch or624 * not.625 * return_node - Where the Node is returned626 *627 * DESCRIPTION: Look up a name relative to a given scope and return the628 * corresponding Node. NOTE: Scope can be null.629 *630 * MUTEX: Doesn't locks namespace631 *632 ******************************************************************************/633 634acpi_status635acpi_ns_get_node_unlocked(struct acpi_namespace_node *prefix_node,636 const char *pathname,637 u32 flags, struct acpi_namespace_node **return_node)638{639 union acpi_generic_state scope_info;640 acpi_status status;641 char *internal_path;642 643 ACPI_FUNCTION_TRACE_PTR(ns_get_node_unlocked,644 ACPI_CAST_PTR(char, pathname));645 646 /* Simplest case is a null pathname */647 648 if (!pathname) {649 *return_node = prefix_node;650 if (!prefix_node) {651 *return_node = acpi_gbl_root_node;652 }653 654 return_ACPI_STATUS(AE_OK);655 }656 657 /* Quick check for a reference to the root */658 659 if (ACPI_IS_ROOT_PREFIX(pathname[0]) && (!pathname[1])) {660 *return_node = acpi_gbl_root_node;661 return_ACPI_STATUS(AE_OK);662 }663 664 /* Convert path to internal representation */665 666 status = acpi_ns_internalize_name(pathname, &internal_path);667 if (ACPI_FAILURE(status)) {668 return_ACPI_STATUS(status);669 }670 671 /* Setup lookup scope (search starting point) */672 673 scope_info.scope.node = prefix_node;674 675 /* Lookup the name in the namespace */676 677 status = acpi_ns_lookup(&scope_info, internal_path, ACPI_TYPE_ANY,678 ACPI_IMODE_EXECUTE,679 (flags | ACPI_NS_DONT_OPEN_SCOPE), NULL,680 return_node);681 if (ACPI_FAILURE(status)) {682 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s, %s\n",683 pathname, acpi_format_exception(status)));684 }685 686 ACPI_FREE(internal_path);687 return_ACPI_STATUS(status);688}689 690/*******************************************************************************691 *692 * FUNCTION: acpi_ns_get_node693 *694 * PARAMETERS: *pathname - Name to be found, in external (ASL) format. The695 * \ (backslash) and ^ (carat) prefixes, and the696 * . (period) to separate segments are supported.697 * prefix_node - Root of subtree to be searched, or NS_ALL for the698 * root of the name space. If Name is fully699 * qualified (first s8 is '\'), the passed value700 * of Scope will not be accessed.701 * flags - Used to indicate whether to perform upsearch or702 * not.703 * return_node - Where the Node is returned704 *705 * DESCRIPTION: Look up a name relative to a given scope and return the706 * corresponding Node. NOTE: Scope can be null.707 *708 * MUTEX: Locks namespace709 *710 ******************************************************************************/711 712acpi_status713acpi_ns_get_node(struct acpi_namespace_node *prefix_node,714 const char *pathname,715 u32 flags, struct acpi_namespace_node **return_node)716{717 acpi_status status;718 719 ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname));720 721 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);722 if (ACPI_FAILURE(status)) {723 return_ACPI_STATUS(status);724 }725 726 status = acpi_ns_get_node_unlocked(prefix_node, pathname,727 flags, return_node);728 729 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);730 return_ACPI_STATUS(status);731}732