1 /****************************************************************************** 2 * 3 * Module Name: dmextern - Support for External() ASL statements 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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 MERCHANTIBILITY 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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/amlcode.h> 47 #include <contrib/dev/acpica/include/acnamesp.h> 48 #include <contrib/dev/acpica/include/acdisasm.h> 49 50 51 /* 52 * This module is used for application-level code (iASL disassembler) only. 53 * 54 * It contains the code to create and emit any necessary External() ASL 55 * statements for the module being disassembled. 56 */ 57 #define _COMPONENT ACPI_CA_DISASSEMBLER 58 ACPI_MODULE_NAME ("dmextern") 59 60 61 /* 62 * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL 63 * ObjectTypeKeyword. Used to generate typed external declarations 64 */ 65 static const char *AcpiGbl_DmTypeNames[] = 66 { 67 /* 00 */ "", /* Type ANY */ 68 /* 01 */ ", IntObj", 69 /* 02 */ ", StrObj", 70 /* 03 */ ", BuffObj", 71 /* 04 */ ", PkgObj", 72 /* 05 */ ", FieldUnitObj", 73 /* 06 */ ", DeviceObj", 74 /* 07 */ ", EventObj", 75 /* 08 */ ", MethodObj", 76 /* 09 */ ", MutexObj", 77 /* 10 */ ", OpRegionObj", 78 /* 11 */ ", PowerResObj", 79 /* 12 */ ", ProcessorObj", 80 /* 13 */ ", ThermalZoneObj", 81 /* 14 */ ", BuffFieldObj", 82 /* 15 */ ", DDBHandleObj", 83 /* 16 */ "", /* Debug object */ 84 /* 17 */ ", FieldUnitObj", 85 /* 18 */ ", FieldUnitObj", 86 /* 19 */ ", FieldUnitObj" 87 }; 88 89 90 /* Local prototypes */ 91 92 static const char * 93 AcpiDmGetObjectTypeName ( 94 ACPI_OBJECT_TYPE Type); 95 96 static char * 97 AcpiDmNormalizeParentPrefix ( 98 ACPI_PARSE_OBJECT *Op, 99 char *Path); 100 101 102 /******************************************************************************* 103 * 104 * FUNCTION: AcpiDmGetObjectTypeName 105 * 106 * PARAMETERS: Type - An ACPI_OBJECT_TYPE 107 * 108 * RETURN: Pointer to a string 109 * 110 * DESCRIPTION: Map an object type to the ASL object type string. 111 * 112 ******************************************************************************/ 113 114 static const char * 115 AcpiDmGetObjectTypeName ( 116 ACPI_OBJECT_TYPE Type) 117 { 118 119 if (Type == ACPI_TYPE_LOCAL_SCOPE) 120 { 121 Type = ACPI_TYPE_DEVICE; 122 } 123 124 else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD) 125 { 126 return (""); 127 } 128 129 return (AcpiGbl_DmTypeNames[Type]); 130 } 131 132 133 /******************************************************************************* 134 * 135 * FUNCTION: AcpiDmNormalizeParentPrefix 136 * 137 * PARAMETERS: Op - Parse op 138 * Path - Path with parent prefix 139 * 140 * RETURN: The full pathname to the object (from the namespace root) 141 * 142 * DESCRIPTION: Returns the full pathname of a path with parent prefix 143 * The caller must free the fullpath returned. 144 * 145 ******************************************************************************/ 146 147 static char * 148 AcpiDmNormalizeParentPrefix ( 149 ACPI_PARSE_OBJECT *Op, 150 char *Path) 151 { 152 ACPI_NAMESPACE_NODE *Node; 153 char *Fullpath; 154 char *ParentPath; 155 ACPI_SIZE Length; 156 UINT32 Index = 0; 157 158 159 if (!Op) 160 { 161 return (NULL); 162 } 163 164 /* Search upwards in the parse tree until we reach the next namespace node */ 165 166 Op = Op->Common.Parent; 167 while (Op) 168 { 169 if (Op->Common.Node) 170 { 171 break; 172 } 173 174 Op = Op->Common.Parent; 175 } 176 177 if (!Op) 178 { 179 return (NULL); 180 } 181 182 /* 183 * Find the actual parent node for the reference: 184 * Remove all carat prefixes from the input path. 185 * There may be multiple parent prefixes (For example, ^^^M000) 186 */ 187 Node = Op->Common.Node; 188 while (Node && (*Path == (UINT8) AML_PARENT_PREFIX)) 189 { 190 Node = Node->Parent; 191 Path++; 192 } 193 194 if (!Node) 195 { 196 return (NULL); 197 } 198 199 /* Get the full pathname for the parent node */ 200 201 ParentPath = AcpiNsGetExternalPathname (Node); 202 if (!ParentPath) 203 { 204 return (NULL); 205 } 206 207 Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1); 208 if (ParentPath[1]) 209 { 210 /* 211 * If ParentPath is not just a simple '\', increment the length 212 * for the required dot separator (ParentPath.Path) 213 */ 214 Length++; 215 216 /* For External() statements, we do not want a leading '\' */ 217 218 if (*ParentPath == AML_ROOT_PREFIX) 219 { 220 Index = 1; 221 } 222 } 223 224 Fullpath = ACPI_ALLOCATE_ZEROED (Length); 225 if (!Fullpath) 226 { 227 goto Cleanup; 228 } 229 230 /* 231 * Concatenate parent fullpath and path. For example, 232 * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT" 233 * 234 * Copy the parent path 235 */ 236 ACPI_STRCPY (Fullpath, &ParentPath[Index]); 237 238 /* 239 * Add dot separator 240 * (don't need dot if parent fullpath is a single backslash) 241 */ 242 if (ParentPath[1]) 243 { 244 ACPI_STRCAT (Fullpath, "."); 245 } 246 247 /* Copy child path (carat parent prefix(es) were skipped above) */ 248 249 ACPI_STRCAT (Fullpath, Path); 250 251 Cleanup: 252 ACPI_FREE (ParentPath); 253 return (Fullpath); 254 } 255 256 257 /******************************************************************************* 258 * 259 * FUNCTION: AcpiDmAddToExternalFileList 260 * 261 * PARAMETERS: PathList - Single path or list separated by comma 262 * 263 * RETURN: None 264 * 265 * DESCRIPTION: Add external files to global list 266 * 267 ******************************************************************************/ 268 269 ACPI_STATUS 270 AcpiDmAddToExternalFileList ( 271 char *PathList) 272 { 273 ACPI_EXTERNAL_FILE *ExternalFile; 274 char *Path; 275 char *TmpPath; 276 277 278 if (!PathList) 279 { 280 return (AE_OK); 281 } 282 283 Path = strtok (PathList, ","); 284 285 while (Path) 286 { 287 TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1); 288 if (!TmpPath) 289 { 290 return (AE_NO_MEMORY); 291 } 292 293 ACPI_STRCPY (TmpPath, Path); 294 295 ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE)); 296 if (!ExternalFile) 297 { 298 ACPI_FREE (TmpPath); 299 return (AE_NO_MEMORY); 300 } 301 302 ExternalFile->Path = TmpPath; 303 304 if (AcpiGbl_ExternalFileList) 305 { 306 ExternalFile->Next = AcpiGbl_ExternalFileList; 307 } 308 309 AcpiGbl_ExternalFileList = ExternalFile; 310 Path = strtok (NULL, ","); 311 } 312 313 return (AE_OK); 314 } 315 316 317 /******************************************************************************* 318 * 319 * FUNCTION: AcpiDmClearExternalFileList 320 * 321 * PARAMETERS: None 322 * 323 * RETURN: None 324 * 325 * DESCRIPTION: Clear the external file list 326 * 327 ******************************************************************************/ 328 329 void 330 AcpiDmClearExternalFileList ( 331 void) 332 { 333 ACPI_EXTERNAL_FILE *NextExternal; 334 335 336 while (AcpiGbl_ExternalFileList) 337 { 338 NextExternal = AcpiGbl_ExternalFileList->Next; 339 ACPI_FREE (AcpiGbl_ExternalFileList->Path); 340 ACPI_FREE (AcpiGbl_ExternalFileList); 341 AcpiGbl_ExternalFileList = NextExternal; 342 } 343 } 344 345 346 /******************************************************************************* 347 * 348 * FUNCTION: AcpiDmAddToExternalList 349 * 350 * PARAMETERS: Op - Current parser Op 351 * Path - Internal (AML) path to the object 352 * Type - ACPI object type to be added 353 * Value - Arg count if adding a Method object 354 * 355 * RETURN: None 356 * 357 * DESCRIPTION: Insert a new name into the global list of Externals which 358 * will in turn be later emitted as an External() declaration 359 * in the disassembled output. 360 * 361 ******************************************************************************/ 362 363 void 364 AcpiDmAddToExternalList ( 365 ACPI_PARSE_OBJECT *Op, 366 char *Path, 367 UINT8 Type, 368 UINT32 Value) 369 { 370 char *ExternalPath; 371 char *Fullpath = NULL; 372 ACPI_EXTERNAL_LIST *NewExternal; 373 ACPI_EXTERNAL_LIST *NextExternal; 374 ACPI_EXTERNAL_LIST *PrevExternal = NULL; 375 ACPI_STATUS Status; 376 377 378 if (!Path) 379 { 380 return; 381 } 382 383 /* 384 * We don't want External() statements to contain a leading '\'. 385 * This prevents duplicate external statements of the form: 386 * 387 * External (\ABCD) 388 * External (ABCD) 389 * 390 * This would cause a compile time error when the disassembled 391 * output file is recompiled. 392 */ 393 if ((*Path == AML_ROOT_PREFIX) && (Path[1])) 394 { 395 Path++; 396 } 397 398 /* Externalize the ACPI pathname */ 399 400 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path, 401 NULL, &ExternalPath); 402 if (ACPI_FAILURE (Status)) 403 { 404 return; 405 } 406 407 /* 408 * Get the full pathname from the root if "Path" has one or more 409 * parent prefixes (^). Note: path will not contain a leading '\'. 410 */ 411 if (*Path == (UINT8) AML_PARENT_PREFIX) 412 { 413 Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath); 414 if (Fullpath) 415 { 416 /* Set new external path */ 417 418 ACPI_FREE (ExternalPath); 419 ExternalPath = Fullpath; 420 } 421 } 422 423 /* Check all existing externals to ensure no duplicates */ 424 425 NextExternal = AcpiGbl_ExternalList; 426 while (NextExternal) 427 { 428 if (!ACPI_STRCMP (ExternalPath, NextExternal->Path)) 429 { 430 /* Duplicate method, check that the Value (ArgCount) is the same */ 431 432 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 433 (NextExternal->Value != Value)) 434 { 435 ACPI_ERROR ((AE_INFO, 436 "Argument count mismatch for method %s %u %u", 437 NextExternal->Path, NextExternal->Value, Value)); 438 } 439 440 /* Allow upgrade of type from ANY */ 441 442 else if (NextExternal->Type == ACPI_TYPE_ANY) 443 { 444 NextExternal->Type = Type; 445 NextExternal->Value = Value; 446 } 447 448 ACPI_FREE (ExternalPath); 449 return; 450 } 451 452 NextExternal = NextExternal->Next; 453 } 454 455 /* Allocate and init a new External() descriptor */ 456 457 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); 458 if (!NewExternal) 459 { 460 ACPI_FREE (ExternalPath); 461 return; 462 } 463 464 NewExternal->Path = ExternalPath; 465 NewExternal->Type = Type; 466 NewExternal->Value = Value; 467 NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath); 468 469 /* Was the external path with parent prefix normalized to a fullpath? */ 470 471 if (Fullpath == ExternalPath) 472 { 473 /* Get new internal path */ 474 475 Status = AcpiNsInternalizeName (ExternalPath, &Path); 476 if (ACPI_FAILURE (Status)) 477 { 478 ACPI_FREE (ExternalPath); 479 ACPI_FREE (NewExternal); 480 return; 481 } 482 483 /* Set flag to indicate External->InternalPath need to be freed */ 484 485 NewExternal->Flags |= ACPI_IPATH_ALLOCATED; 486 } 487 488 NewExternal->InternalPath = Path; 489 490 /* Link the new descriptor into the global list, alphabetically ordered */ 491 492 NextExternal = AcpiGbl_ExternalList; 493 while (NextExternal) 494 { 495 if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0) 496 { 497 if (PrevExternal) 498 { 499 PrevExternal->Next = NewExternal; 500 } 501 else 502 { 503 AcpiGbl_ExternalList = NewExternal; 504 } 505 506 NewExternal->Next = NextExternal; 507 return; 508 } 509 510 PrevExternal = NextExternal; 511 NextExternal = NextExternal->Next; 512 } 513 514 if (PrevExternal) 515 { 516 PrevExternal->Next = NewExternal; 517 } 518 else 519 { 520 AcpiGbl_ExternalList = NewExternal; 521 } 522 } 523 524 525 /******************************************************************************* 526 * 527 * FUNCTION: AcpiDmAddExternalsToNamespace 528 * 529 * PARAMETERS: None 530 * 531 * RETURN: None 532 * 533 * DESCRIPTION: Add all externals to the namespace. Allows externals to be 534 * "resolved". 535 * 536 ******************************************************************************/ 537 538 void 539 AcpiDmAddExternalsToNamespace ( 540 void) 541 { 542 ACPI_STATUS Status; 543 ACPI_NAMESPACE_NODE *Node; 544 ACPI_OPERAND_OBJECT *ObjDesc; 545 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 546 547 548 while (External) 549 { 550 /* Add the external name (object) into the namespace */ 551 552 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type, 553 ACPI_IMODE_LOAD_PASS1, 554 ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE, 555 NULL, &Node); 556 557 if (ACPI_FAILURE (Status)) 558 { 559 ACPI_EXCEPTION ((AE_INFO, Status, 560 "while adding external to namespace [%s]", 561 External->Path)); 562 } 563 564 else switch (External->Type) 565 { 566 case ACPI_TYPE_METHOD: 567 568 /* For methods, we need to save the argument count */ 569 570 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 571 ObjDesc->Method.ParamCount = (UINT8) External->Value; 572 Node->Object = ObjDesc; 573 break; 574 575 case ACPI_TYPE_REGION: 576 577 /* Regions require a region sub-object */ 578 579 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); 580 ObjDesc->Region.Node = Node; 581 Node->Object = ObjDesc; 582 break; 583 584 default: 585 break; 586 } 587 588 External = External->Next; 589 } 590 } 591 592 593 /******************************************************************************* 594 * 595 * FUNCTION: AcpiDmGetExternalMethodCount 596 * 597 * PARAMETERS: None 598 * 599 * RETURN: The number of control method externals in the external list 600 * 601 * DESCRIPTION: Return the number of method externals that have been generated. 602 * If any control method externals have been found, we must 603 * re-parse the entire definition block with the new information 604 * (number of arguments for the methods.) This is limitation of 605 * AML, we don't know the number of arguments from the control 606 * method invocation itself. 607 * 608 ******************************************************************************/ 609 610 UINT32 611 AcpiDmGetExternalMethodCount ( 612 void) 613 { 614 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 615 UINT32 Count = 0; 616 617 618 while (External) 619 { 620 if (External->Type == ACPI_TYPE_METHOD) 621 { 622 Count++; 623 } 624 625 External = External->Next; 626 } 627 628 return (Count); 629 } 630 631 632 /******************************************************************************* 633 * 634 * FUNCTION: AcpiDmClearExternalList 635 * 636 * PARAMETERS: None 637 * 638 * RETURN: None 639 * 640 * DESCRIPTION: Free the entire External info list 641 * 642 ******************************************************************************/ 643 644 void 645 AcpiDmClearExternalList ( 646 void) 647 { 648 ACPI_EXTERNAL_LIST *NextExternal; 649 650 651 while (AcpiGbl_ExternalList) 652 { 653 NextExternal = AcpiGbl_ExternalList->Next; 654 ACPI_FREE (AcpiGbl_ExternalList->Path); 655 ACPI_FREE (AcpiGbl_ExternalList); 656 AcpiGbl_ExternalList = NextExternal; 657 } 658 } 659 660 661 /******************************************************************************* 662 * 663 * FUNCTION: AcpiDmEmitExternals 664 * 665 * PARAMETERS: None 666 * 667 * RETURN: None 668 * 669 * DESCRIPTION: Emit an External() ASL statement for each of the externals in 670 * the global external info list. 671 * 672 ******************************************************************************/ 673 674 void 675 AcpiDmEmitExternals ( 676 void) 677 { 678 ACPI_EXTERNAL_LIST *NextExternal; 679 680 681 if (!AcpiGbl_ExternalList) 682 { 683 return; 684 } 685 686 /* 687 * Walk the list of externals (unresolved references) 688 * found during the AML parsing 689 */ 690 while (AcpiGbl_ExternalList) 691 { 692 AcpiOsPrintf (" External (%s%s", 693 AcpiGbl_ExternalList->Path, 694 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type)); 695 696 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) 697 { 698 AcpiOsPrintf (") // %u Arguments\n", 699 AcpiGbl_ExternalList->Value); 700 } 701 else 702 { 703 AcpiOsPrintf (")\n"); 704 } 705 706 /* Free this external info block and move on to next external */ 707 708 NextExternal = AcpiGbl_ExternalList->Next; 709 if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED) 710 { 711 ACPI_FREE (AcpiGbl_ExternalList->InternalPath); 712 } 713 714 ACPI_FREE (AcpiGbl_ExternalList->Path); 715 ACPI_FREE (AcpiGbl_ExternalList); 716 AcpiGbl_ExternalList = NextExternal; 717 } 718 719 AcpiOsPrintf ("\n"); 720 } 721