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