1 /******************************************************************************* 2 * 3 * Module Name: nsnames - Name manipulation and search 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2026, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "acpi.h" 45 #include "accommon.h" 46 #include "amlcode.h" 47 #include "acnamesp.h" 48 49 50 #define _COMPONENT ACPI_NAMESPACE 51 ACPI_MODULE_NAME ("nsnames") 52 53 54 /******************************************************************************* 55 * 56 * FUNCTION: AcpiNsGetExternalPathname 57 * 58 * PARAMETERS: Node - Namespace node whose pathname is needed 59 * 60 * RETURN: Pointer to storage containing the fully qualified name of 61 * the node, In external format (name segments separated by path 62 * separators.) 63 * 64 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually 65 * for error and debug statements. 66 * 67 ******************************************************************************/ 68 69 char * 70 AcpiNsGetExternalPathname ( 71 ACPI_NAMESPACE_NODE *Node) 72 { 73 char *NameBuffer; 74 75 76 ACPI_FUNCTION_TRACE_PTR (NsGetExternalPathname, Node); 77 78 79 NameBuffer = AcpiNsGetNormalizedPathname (Node, FALSE); 80 return_PTR (NameBuffer); 81 } 82 83 84 /******************************************************************************* 85 * 86 * FUNCTION: AcpiNsGetPathnameLength 87 * 88 * PARAMETERS: Node - Namespace node 89 * 90 * RETURN: Length of path, including prefix 91 * 92 * DESCRIPTION: Get the length of the pathname string for this node 93 * 94 ******************************************************************************/ 95 96 ACPI_SIZE 97 AcpiNsGetPathnameLength ( 98 ACPI_NAMESPACE_NODE *Node) 99 { 100 ACPI_SIZE Size; 101 102 103 /* Validate the Node */ 104 105 if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED) 106 { 107 ACPI_ERROR ((AE_INFO, 108 "Invalid/cached reference target node: %p, descriptor type %d", 109 Node, ACPI_GET_DESCRIPTOR_TYPE (Node))); 110 return (0); 111 } 112 113 Size = AcpiNsBuildNormalizedPath (Node, NULL, 0, FALSE); 114 return (Size); 115 } 116 117 118 /******************************************************************************* 119 * 120 * FUNCTION: AcpiNsHandleToName 121 * 122 * PARAMETERS: TargetHandle - Handle of named object whose name is 123 * to be found 124 * Buffer - Where the name is returned 125 * 126 * RETURN: Status, Buffer is filled with name if status is AE_OK 127 * 128 * DESCRIPTION: Build and return a full namespace name 129 * 130 ******************************************************************************/ 131 132 ACPI_STATUS 133 AcpiNsHandleToName ( 134 ACPI_HANDLE TargetHandle, 135 ACPI_BUFFER *Buffer) 136 { 137 ACPI_STATUS Status; 138 ACPI_NAMESPACE_NODE *Node; 139 const char *NodeName; 140 141 142 ACPI_FUNCTION_TRACE_PTR (NsHandleToName, TargetHandle); 143 144 145 Node = AcpiNsValidateHandle (TargetHandle); 146 if (!Node) 147 { 148 return_ACPI_STATUS (AE_BAD_PARAMETER); 149 } 150 151 /* Validate/Allocate/Clear caller buffer */ 152 153 Status = AcpiUtInitializeBuffer (Buffer, ACPI_PATH_SEGMENT_LENGTH); 154 if (ACPI_FAILURE (Status)) 155 { 156 return_ACPI_STATUS (Status); 157 } 158 159 /* Just copy the ACPI name from the Node and zero terminate it */ 160 161 NodeName = AcpiUtGetNodeName (Node); 162 ACPI_COPY_NAMESEG (Buffer->Pointer, NodeName); 163 ((char *) Buffer->Pointer) [ACPI_NAMESEG_SIZE] = 0; 164 165 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%4.4s\n", (char *) Buffer->Pointer)); 166 return_ACPI_STATUS (AE_OK); 167 } 168 169 170 /******************************************************************************* 171 * 172 * FUNCTION: AcpiNsHandleToPathname 173 * 174 * PARAMETERS: TargetHandle - Handle of named object whose name is 175 * to be found 176 * Buffer - Where the pathname is returned 177 * NoTrailing - Remove trailing '_' for each name 178 * segment 179 * 180 * RETURN: Status, Buffer is filled with pathname if status is AE_OK 181 * 182 * DESCRIPTION: Build and return a full namespace pathname 183 * 184 ******************************************************************************/ 185 186 ACPI_STATUS 187 AcpiNsHandleToPathname ( 188 ACPI_HANDLE TargetHandle, 189 ACPI_BUFFER *Buffer, 190 BOOLEAN NoTrailing) 191 { 192 ACPI_STATUS Status; 193 ACPI_NAMESPACE_NODE *Node; 194 ACPI_SIZE RequiredSize; 195 196 197 ACPI_FUNCTION_TRACE_PTR (NsHandleToPathname, TargetHandle); 198 199 200 Node = AcpiNsValidateHandle (TargetHandle); 201 if (!Node) 202 { 203 return_ACPI_STATUS (AE_BAD_PARAMETER); 204 } 205 206 /* Determine size required for the caller buffer */ 207 208 RequiredSize = AcpiNsBuildNormalizedPath (Node, NULL, 0, NoTrailing); 209 if (!RequiredSize) 210 { 211 return_ACPI_STATUS (AE_BAD_PARAMETER); 212 } 213 214 /* Validate/Allocate/Clear caller buffer */ 215 216 Status = AcpiUtInitializeBuffer (Buffer, RequiredSize); 217 if (ACPI_FAILURE (Status)) 218 { 219 return_ACPI_STATUS (Status); 220 } 221 222 /* Build the path in the caller buffer */ 223 224 (void) AcpiNsBuildNormalizedPath (Node, Buffer->Pointer, 225 (UINT32) RequiredSize, NoTrailing); 226 227 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%X]\n", 228 (char *) Buffer->Pointer, (UINT32) RequiredSize)); 229 return_ACPI_STATUS (AE_OK); 230 } 231 232 233 /******************************************************************************* 234 * 235 * FUNCTION: AcpiNsBuildNormalizedPath 236 * 237 * PARAMETERS: Node - Namespace node 238 * FullPath - Where the path name is returned 239 * PathSize - Size of returned path name buffer 240 * NoTrailing - Remove trailing '_' from each name segment 241 * 242 * RETURN: Return 1 if the AML path is empty, otherwise returning (length 243 * of pathname + 1) which means the 'FullPath' contains a trailing 244 * null. 245 * 246 * DESCRIPTION: Build and return a full namespace pathname. 247 * Note that if the size of 'FullPath' isn't large enough to 248 * contain the namespace node's path name, the actual required 249 * buffer length is returned, and it should be greater than 250 * 'PathSize'. So callers are able to check the returning value 251 * to determine the buffer size of 'FullPath'. 252 * 253 ******************************************************************************/ 254 255 UINT32 256 AcpiNsBuildNormalizedPath ( 257 ACPI_NAMESPACE_NODE *Node, 258 char *FullPath, 259 UINT32 PathSize, 260 BOOLEAN NoTrailing) 261 { 262 UINT32 Length = 0, i; 263 char Name[ACPI_NAMESEG_SIZE] ACPI_NONSTRING; 264 BOOLEAN DoNoTrailing; 265 char c, *Left, *Right; 266 ACPI_NAMESPACE_NODE *NextNode; 267 268 269 ACPI_FUNCTION_TRACE_PTR (NsBuildNormalizedPath, Node); 270 271 272 #define ACPI_PATH_PUT8(Path, Size, Byte, Length) \ 273 do { \ 274 if ((Length) < (Size)) \ 275 { \ 276 (Path)[(Length)] = (Byte); \ 277 } \ 278 (Length)++; \ 279 } while (0) 280 281 /* 282 * Make sure the PathSize is correct, so that we don't need to 283 * validate both FullPath and PathSize. 284 */ 285 if (!FullPath) 286 { 287 PathSize = 0; 288 } 289 290 if (!Node) 291 { 292 goto BuildTrailingNull; 293 } 294 295 /* Validate the Node to avoid use-after-free vulnerabilities */ 296 297 if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED) 298 { 299 goto BuildTrailingNull; 300 } 301 302 NextNode = Node; 303 while (NextNode && NextNode != AcpiGbl_RootNode) 304 { 305 if (NextNode != Node) 306 { 307 ACPI_PATH_PUT8(FullPath, PathSize, AML_DUAL_NAME_PREFIX, Length); 308 } 309 310 ACPI_MOVE_32_TO_32 (Name, &NextNode->Name); 311 DoNoTrailing = NoTrailing; 312 for (i = 0; i < 4; i++) 313 { 314 c = Name[4-i-1]; 315 if (DoNoTrailing && c != '_') 316 { 317 DoNoTrailing = FALSE; 318 } 319 if (!DoNoTrailing) 320 { 321 ACPI_PATH_PUT8(FullPath, PathSize, c, Length); 322 } 323 } 324 325 NextNode = NextNode->Parent; 326 } 327 328 ACPI_PATH_PUT8(FullPath, PathSize, AML_ROOT_PREFIX, Length); 329 330 /* Reverse the path string */ 331 332 if (Length <= PathSize) 333 { 334 Left = FullPath; 335 Right = FullPath+Length - 1; 336 337 while (Left < Right) 338 { 339 c = *Left; 340 *Left++ = *Right; 341 *Right-- = c; 342 } 343 } 344 345 /* Append the trailing null */ 346 347 BuildTrailingNull: 348 ACPI_PATH_PUT8 (FullPath, PathSize, '\0', Length); 349 350 #undef ACPI_PATH_PUT8 351 352 return_UINT32 (Length); 353 } 354 355 356 /******************************************************************************* 357 * 358 * FUNCTION: AcpiNsGetNormalizedPathname 359 * 360 * PARAMETERS: Node - Namespace node whose pathname is needed 361 * NoTrailing - Remove trailing '_' from each name segment 362 * 363 * RETURN: Pointer to storage containing the fully qualified name of 364 * the node, In external format (name segments separated by path 365 * separators.) 366 * 367 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually 368 * for error and debug statements. All trailing '_' will be 369 * removed from the full pathname if 'NoTrailing' is specified.. 370 * 371 ******************************************************************************/ 372 373 char * 374 AcpiNsGetNormalizedPathname ( 375 ACPI_NAMESPACE_NODE *Node, 376 BOOLEAN NoTrailing) 377 { 378 char *NameBuffer; 379 ACPI_SIZE Size; 380 381 382 ACPI_FUNCTION_TRACE_PTR (NsGetNormalizedPathname, Node); 383 384 385 /* Calculate required buffer size based on depth below root */ 386 387 Size = AcpiNsBuildNormalizedPath (Node, NULL, 0, NoTrailing); 388 if (!Size) 389 { 390 return_PTR (NULL); 391 } 392 393 /* Allocate a buffer to be returned to caller */ 394 395 NameBuffer = ACPI_ALLOCATE_ZEROED (Size); 396 if (!NameBuffer) 397 { 398 ACPI_ERROR ((AE_INFO, 399 "Could not allocate %u bytes", (UINT32) Size)); 400 return_PTR (NULL); 401 } 402 403 /* Build the path in the allocated buffer */ 404 405 (void) AcpiNsBuildNormalizedPath (Node, NameBuffer, (UINT32) Size, NoTrailing); 406 407 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES, "%s: Path \"%s\"\n", 408 ACPI_GET_FUNCTION_NAME, NameBuffer)); 409 410 return_PTR (NameBuffer); 411 } 412 413 414 /******************************************************************************* 415 * 416 * FUNCTION: AcpiNsBuildPrefixedPathname 417 * 418 * PARAMETERS: PrefixScope - Scope/Path that prefixes the internal path 419 * InternalPath - Name or path of the namespace node 420 * 421 * RETURN: None 422 * 423 * DESCRIPTION: Construct a fully qualified pathname from a concatenation of: 424 * 1) Path associated with the PrefixScope namespace node 425 * 2) External path representation of the Internal path 426 * 427 ******************************************************************************/ 428 429 char * 430 AcpiNsBuildPrefixedPathname ( 431 ACPI_GENERIC_STATE *PrefixScope, 432 const char *InternalPath) 433 { 434 ACPI_STATUS Status; 435 char *FullPath = NULL; 436 char *ExternalPath = NULL; 437 char *PrefixPath = NULL; 438 ACPI_SIZE PrefixPathLength = 0; 439 440 441 /* If there is a prefix, get the pathname to it */ 442 443 if (PrefixScope && PrefixScope->Scope.Node) 444 { 445 PrefixPath = AcpiNsGetNormalizedPathname (PrefixScope->Scope.Node, TRUE); 446 if (PrefixPath) 447 { 448 PrefixPathLength = strlen (PrefixPath); 449 } 450 } 451 452 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath, 453 NULL, &ExternalPath); 454 if (ACPI_FAILURE (Status)) 455 { 456 goto Cleanup; 457 } 458 459 /* Merge the prefix path and the path. 2 is for one dot and trailing null */ 460 461 FullPath = ACPI_ALLOCATE_ZEROED ( 462 PrefixPathLength + strlen (ExternalPath) + 2); 463 if (!FullPath) 464 { 465 goto Cleanup; 466 } 467 468 /* Don't merge if the External path is already fully qualified */ 469 470 if (PrefixPath && 471 (*ExternalPath != '\\') && 472 (*ExternalPath != '^')) 473 { 474 strcat (FullPath, PrefixPath); 475 if (PrefixPath[1]) 476 { 477 strcat (FullPath, "."); 478 } 479 } 480 481 AcpiNsNormalizePathname (ExternalPath); 482 strcat (FullPath, ExternalPath); 483 484 Cleanup: 485 if (PrefixPath) 486 { 487 ACPI_FREE (PrefixPath); 488 } 489 if (ExternalPath) 490 { 491 ACPI_FREE (ExternalPath); 492 } 493 494 return (FullPath); 495 } 496 497 498 /******************************************************************************* 499 * 500 * FUNCTION: AcpiNsNormalizePathname 501 * 502 * PARAMETERS: OriginalPath - Path to be normalized, in External format 503 * 504 * RETURN: The original path is processed in-place 505 * 506 * DESCRIPTION: Remove trailing underscores from each element of a path. 507 * 508 * For example: \A___.B___.C___ becomes \A.B.C 509 * 510 ******************************************************************************/ 511 512 void 513 AcpiNsNormalizePathname ( 514 char *OriginalPath) 515 { 516 char *InputPath = OriginalPath; 517 char *NewPathBuffer; 518 char *NewPath; 519 UINT32 i; 520 521 522 /* Allocate a temp buffer in which to construct the new path */ 523 524 NewPathBuffer = ACPI_ALLOCATE_ZEROED (strlen (InputPath) + 1); 525 NewPath = NewPathBuffer; 526 if (!NewPathBuffer) 527 { 528 return; 529 } 530 531 /* Special characters may appear at the beginning of the path */ 532 533 if (*InputPath == '\\') 534 { 535 *NewPath = *InputPath; 536 NewPath++; 537 InputPath++; 538 } 539 540 while (*InputPath == '^') 541 { 542 *NewPath = *InputPath; 543 NewPath++; 544 InputPath++; 545 } 546 547 /* Remainder of the path */ 548 549 while (*InputPath) 550 { 551 /* Do one nameseg at a time */ 552 553 for (i = 0; (i < ACPI_NAMESEG_SIZE) && *InputPath; i++) 554 { 555 if ((i == 0) || (*InputPath != '_')) /* First char is allowed to be underscore */ 556 { 557 *NewPath = *InputPath; 558 NewPath++; 559 } 560 561 InputPath++; 562 } 563 564 /* Dot means that there are more namesegs to come */ 565 566 if (*InputPath == '.') 567 { 568 *NewPath = *InputPath; 569 NewPath++; 570 InputPath++; 571 } 572 } 573 574 *NewPath = 0; 575 strcpy (OriginalPath, NewPathBuffer); 576 ACPI_FREE (NewPathBuffer); 577 } 578