1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: nsnames - Name manipulation and search 5 * 6 ******************************************************************************/ 7 8 #include <acpi/acpi.h> 9 #include "accommon.h" 10 #include "amlcode.h" 11 #include "acnamesp.h" 12 13 #define _COMPONENT ACPI_NAMESPACE 14 ACPI_MODULE_NAME("nsnames") 15 16 /* Local Prototypes */ 17 static void acpi_ns_normalize_pathname(char *original_path); 18 19 /******************************************************************************* 20 * 21 * FUNCTION: acpi_ns_get_external_pathname 22 * 23 * PARAMETERS: node - Namespace node whose pathname is needed 24 * 25 * RETURN: Pointer to storage containing the fully qualified name of 26 * the node, In external format (name segments separated by path 27 * separators.) 28 * 29 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually 30 * for error and debug statements. 31 * 32 ******************************************************************************/ 33 34 char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) 35 { 36 char *name_buffer; 37 38 ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node); 39 40 name_buffer = acpi_ns_get_normalized_pathname(node, FALSE); 41 return_PTR(name_buffer); 42 } 43 44 /******************************************************************************* 45 * 46 * FUNCTION: acpi_ns_get_pathname_length 47 * 48 * PARAMETERS: node - Namespace node 49 * 50 * RETURN: Length of path, including prefix 51 * 52 * DESCRIPTION: Get the length of the pathname string for this node 53 * 54 ******************************************************************************/ 55 56 acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) 57 { 58 acpi_size size; 59 60 /* Validate the Node */ 61 62 if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { 63 ACPI_ERROR((AE_INFO, 64 "Invalid/cached reference target node: %p, descriptor type %d", 65 node, ACPI_GET_DESCRIPTOR_TYPE(node))); 66 return (0); 67 } 68 69 size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE); 70 return (size); 71 } 72 73 /******************************************************************************* 74 * 75 * FUNCTION: acpi_ns_handle_to_name 76 * 77 * PARAMETERS: target_handle - Handle of named object whose name is 78 * to be found 79 * buffer - Where the name is returned 80 * 81 * RETURN: Status, Buffer is filled with name if status is AE_OK 82 * 83 * DESCRIPTION: Build and return a full namespace name 84 * 85 ******************************************************************************/ 86 87 acpi_status 88 acpi_ns_handle_to_name(acpi_handle target_handle, struct acpi_buffer *buffer) 89 { 90 acpi_status status; 91 struct acpi_namespace_node *node; 92 const char *node_name; 93 94 ACPI_FUNCTION_TRACE_PTR(ns_handle_to_name, target_handle); 95 96 node = acpi_ns_validate_handle(target_handle); 97 if (!node) { 98 return_ACPI_STATUS(AE_BAD_PARAMETER); 99 } 100 101 /* Validate/Allocate/Clear caller buffer */ 102 103 status = acpi_ut_initialize_buffer(buffer, ACPI_PATH_SEGMENT_LENGTH); 104 if (ACPI_FAILURE(status)) { 105 return_ACPI_STATUS(status); 106 } 107 108 /* Just copy the ACPI name from the Node and zero terminate it */ 109 110 node_name = acpi_ut_get_node_name(node); 111 ACPI_MOVE_NAME(buffer->pointer, node_name); 112 ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; 113 114 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%4.4s\n", (char *)buffer->pointer)); 115 return_ACPI_STATUS(AE_OK); 116 } 117 118 /******************************************************************************* 119 * 120 * FUNCTION: acpi_ns_handle_to_pathname 121 * 122 * PARAMETERS: target_handle - Handle of named object whose name is 123 * to be found 124 * buffer - Where the pathname is returned 125 * no_trailing - Remove trailing '_' for each name 126 * segment 127 * 128 * RETURN: Status, Buffer is filled with pathname if status is AE_OK 129 * 130 * DESCRIPTION: Build and return a full namespace pathname 131 * 132 ******************************************************************************/ 133 134 acpi_status 135 acpi_ns_handle_to_pathname(acpi_handle target_handle, 136 struct acpi_buffer *buffer, u8 no_trailing) 137 { 138 acpi_status status; 139 struct acpi_namespace_node *node; 140 acpi_size required_size; 141 142 ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); 143 144 node = acpi_ns_validate_handle(target_handle); 145 if (!node) { 146 return_ACPI_STATUS(AE_BAD_PARAMETER); 147 } 148 149 /* Determine size required for the caller buffer */ 150 151 required_size = 152 acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); 153 if (!required_size) { 154 return_ACPI_STATUS(AE_BAD_PARAMETER); 155 } 156 157 /* Validate/Allocate/Clear caller buffer */ 158 159 status = acpi_ut_initialize_buffer(buffer, required_size); 160 if (ACPI_FAILURE(status)) { 161 return_ACPI_STATUS(status); 162 } 163 164 /* Build the path in the caller buffer */ 165 166 (void)acpi_ns_build_normalized_path(node, buffer->pointer, 167 required_size, no_trailing); 168 169 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n", 170 (char *)buffer->pointer, (u32) required_size)); 171 return_ACPI_STATUS(AE_OK); 172 } 173 174 /******************************************************************************* 175 * 176 * FUNCTION: acpi_ns_build_normalized_path 177 * 178 * PARAMETERS: node - Namespace node 179 * full_path - Where the path name is returned 180 * path_size - Size of returned path name buffer 181 * no_trailing - Remove trailing '_' from each name segment 182 * 183 * RETURN: Return 1 if the AML path is empty, otherwise returning (length 184 * of pathname + 1) which means the 'FullPath' contains a trailing 185 * null. 186 * 187 * DESCRIPTION: Build and return a full namespace pathname. 188 * Note that if the size of 'FullPath' isn't large enough to 189 * contain the namespace node's path name, the actual required 190 * buffer length is returned, and it should be greater than 191 * 'PathSize'. So callers are able to check the returning value 192 * to determine the buffer size of 'FullPath'. 193 * 194 ******************************************************************************/ 195 196 u32 197 acpi_ns_build_normalized_path(struct acpi_namespace_node *node, 198 char *full_path, u32 path_size, u8 no_trailing) 199 { 200 u32 length = 0, i; 201 char name[ACPI_NAME_SIZE]; 202 u8 do_no_trailing; 203 char c, *left, *right; 204 struct acpi_namespace_node *next_node; 205 206 ACPI_FUNCTION_TRACE_PTR(ns_build_normalized_path, node); 207 208 #define ACPI_PATH_PUT8(path, size, byte, length) \ 209 do { \ 210 if ((length) < (size)) \ 211 { \ 212 (path)[(length)] = (byte); \ 213 } \ 214 (length)++; \ 215 } while (0) 216 217 /* 218 * Make sure the path_size is correct, so that we don't need to 219 * validate both full_path and path_size. 220 */ 221 if (!full_path) { 222 path_size = 0; 223 } 224 225 if (!node) { 226 goto build_trailing_null; 227 } 228 229 next_node = node; 230 while (next_node && next_node != acpi_gbl_root_node) { 231 if (next_node != node) { 232 ACPI_PATH_PUT8(full_path, path_size, 233 AML_DUAL_NAME_PREFIX, length); 234 } 235 236 ACPI_MOVE_32_TO_32(name, &next_node->name); 237 do_no_trailing = no_trailing; 238 for (i = 0; i < 4; i++) { 239 c = name[4 - i - 1]; 240 if (do_no_trailing && c != '_') { 241 do_no_trailing = FALSE; 242 } 243 if (!do_no_trailing) { 244 ACPI_PATH_PUT8(full_path, path_size, c, length); 245 } 246 } 247 248 next_node = next_node->parent; 249 } 250 251 ACPI_PATH_PUT8(full_path, path_size, AML_ROOT_PREFIX, length); 252 253 /* Reverse the path string */ 254 255 if (length <= path_size) { 256 left = full_path; 257 right = full_path + length - 1; 258 259 while (left < right) { 260 c = *left; 261 *left++ = *right; 262 *right-- = c; 263 } 264 } 265 266 /* Append the trailing null */ 267 268 build_trailing_null: 269 ACPI_PATH_PUT8(full_path, path_size, '\0', length); 270 271 #undef ACPI_PATH_PUT8 272 273 return_UINT32(length); 274 } 275 276 /******************************************************************************* 277 * 278 * FUNCTION: acpi_ns_get_normalized_pathname 279 * 280 * PARAMETERS: node - Namespace node whose pathname is needed 281 * no_trailing - Remove trailing '_' from each name segment 282 * 283 * RETURN: Pointer to storage containing the fully qualified name of 284 * the node, In external format (name segments separated by path 285 * separators.) 286 * 287 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually 288 * for error and debug statements. All trailing '_' will be 289 * removed from the full pathname if 'NoTrailing' is specified.. 290 * 291 ******************************************************************************/ 292 293 char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, 294 u8 no_trailing) 295 { 296 char *name_buffer; 297 acpi_size size; 298 299 ACPI_FUNCTION_TRACE_PTR(ns_get_normalized_pathname, node); 300 301 /* Calculate required buffer size based on depth below root */ 302 303 size = acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); 304 if (!size) { 305 return_PTR(NULL); 306 } 307 308 /* Allocate a buffer to be returned to caller */ 309 310 name_buffer = ACPI_ALLOCATE_ZEROED(size); 311 if (!name_buffer) { 312 ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); 313 return_PTR(NULL); 314 } 315 316 /* Build the path in the allocated buffer */ 317 318 (void)acpi_ns_build_normalized_path(node, name_buffer, size, 319 no_trailing); 320 321 ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, "%s: Path \"%s\"\n", 322 ACPI_GET_FUNCTION_NAME, name_buffer)); 323 324 return_PTR(name_buffer); 325 } 326 327 /******************************************************************************* 328 * 329 * FUNCTION: acpi_ns_build_prefixed_pathname 330 * 331 * PARAMETERS: prefix_scope - Scope/Path that prefixes the internal path 332 * internal_path - Name or path of the namespace node 333 * 334 * RETURN: None 335 * 336 * DESCRIPTION: Construct a fully qualified pathname from a concatenation of: 337 * 1) Path associated with the prefix_scope namespace node 338 * 2) External path representation of the Internal path 339 * 340 ******************************************************************************/ 341 342 char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope, 343 const char *internal_path) 344 { 345 acpi_status status; 346 char *full_path = NULL; 347 char *external_path = NULL; 348 char *prefix_path = NULL; 349 u32 prefix_path_length = 0; 350 351 /* If there is a prefix, get the pathname to it */ 352 353 if (prefix_scope && prefix_scope->scope.node) { 354 prefix_path = 355 acpi_ns_get_normalized_pathname(prefix_scope->scope.node, 356 TRUE); 357 if (prefix_path) { 358 prefix_path_length = strlen(prefix_path); 359 } 360 } 361 362 status = acpi_ns_externalize_name(ACPI_UINT32_MAX, internal_path, 363 NULL, &external_path); 364 if (ACPI_FAILURE(status)) { 365 goto cleanup; 366 } 367 368 /* Merge the prefix path and the path. 2 is for one dot and trailing null */ 369 370 full_path = 371 ACPI_ALLOCATE_ZEROED(prefix_path_length + strlen(external_path) + 372 2); 373 if (!full_path) { 374 goto cleanup; 375 } 376 377 /* Don't merge if the External path is already fully qualified */ 378 379 if (prefix_path && (*external_path != '\\') && (*external_path != '^')) { 380 strcat(full_path, prefix_path); 381 if (prefix_path[1]) { 382 strcat(full_path, "."); 383 } 384 } 385 386 acpi_ns_normalize_pathname(external_path); 387 strcat(full_path, external_path); 388 389 cleanup: 390 if (prefix_path) { 391 ACPI_FREE(prefix_path); 392 } 393 if (external_path) { 394 ACPI_FREE(external_path); 395 } 396 397 return (full_path); 398 } 399 400 /******************************************************************************* 401 * 402 * FUNCTION: acpi_ns_normalize_pathname 403 * 404 * PARAMETERS: original_path - Path to be normalized, in External format 405 * 406 * RETURN: The original path is processed in-place 407 * 408 * DESCRIPTION: Remove trailing underscores from each element of a path. 409 * 410 * For example: \A___.B___.C___ becomes \A.B.C 411 * 412 ******************************************************************************/ 413 414 static void acpi_ns_normalize_pathname(char *original_path) 415 { 416 char *input_path = original_path; 417 char *new_path_buffer; 418 char *new_path; 419 u32 i; 420 421 /* Allocate a temp buffer in which to construct the new path */ 422 423 new_path_buffer = ACPI_ALLOCATE_ZEROED(strlen(input_path) + 1); 424 new_path = new_path_buffer; 425 if (!new_path_buffer) { 426 return; 427 } 428 429 /* Special characters may appear at the beginning of the path */ 430 431 if (*input_path == '\\') { 432 *new_path = *input_path; 433 new_path++; 434 input_path++; 435 } 436 437 while (*input_path == '^') { 438 *new_path = *input_path; 439 new_path++; 440 input_path++; 441 } 442 443 /* Remainder of the path */ 444 445 while (*input_path) { 446 447 /* Do one nameseg at a time */ 448 449 for (i = 0; (i < ACPI_NAME_SIZE) && *input_path; i++) { 450 if ((i == 0) || (*input_path != '_')) { /* First char is allowed to be underscore */ 451 *new_path = *input_path; 452 new_path++; 453 } 454 455 input_path++; 456 } 457 458 /* Dot means that there are more namesegs to come */ 459 460 if (*input_path == '.') { 461 *new_path = *input_path; 462 new_path++; 463 input_path++; 464 } 465 } 466 467 *new_path = 0; 468 strcpy(original_path, new_path_buffer); 469 ACPI_FREE(new_path_buffer); 470 } 471