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 157 158 /* Search upwards in the parse tree until we reach a namespace node */ 159 160 while (Op) 161 { 162 if (Op->Common.Node) 163 { 164 break; 165 } 166 167 Op = Op->Common.Parent; 168 } 169 170 if (!Op) 171 { 172 return (NULL); 173 } 174 175 /* 176 * Find the actual parent node for the reference: 177 * Remove all carat prefixes from the input path. 178 * There may be multiple parent prefixes (For example, ^^^M000) 179 */ 180 Node = Op->Common.Node; 181 while (Node && (*Path == (UINT8) AML_PARENT_PREFIX)) 182 { 183 Node = Node->Parent; 184 Path++; 185 } 186 187 if (!Node) 188 { 189 return (NULL); 190 } 191 192 /* Get the full pathname for the parent node */ 193 194 ParentPath = AcpiNsGetExternalPathname (Node); 195 if (!ParentPath) 196 { 197 return (NULL); 198 } 199 200 Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1); 201 if (ParentPath[1]) 202 { 203 /* 204 * If ParentPath is not just a simple '\', increment the length 205 * for the required dot separator (ParentPath.Path) 206 */ 207 Length++; 208 } 209 210 Fullpath = ACPI_ALLOCATE_ZEROED (Length); 211 if (!Fullpath) 212 { 213 goto Cleanup; 214 } 215 216 /* 217 * Concatenate parent fullpath and path. For example, 218 * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT" 219 * 220 * Copy the parent path 221 */ 222 ACPI_STRCAT (Fullpath, ParentPath); 223 224 /* 225 * Add dot separator 226 * (don't need dot if parent fullpath is a single backslash) 227 */ 228 if (ParentPath[1]) 229 { 230 ACPI_STRCAT (Fullpath, "."); 231 } 232 233 /* Copy child path (carat parent prefix(es) were skipped above) */ 234 235 ACPI_STRCAT (Fullpath, Path); 236 237 Cleanup: 238 ACPI_FREE (ParentPath); 239 return (Fullpath); 240 } 241 242 243 /******************************************************************************* 244 * 245 * FUNCTION: AcpiDmAddToExternalFileList 246 * 247 * PARAMETERS: PathList - Single path or list separated by comma 248 * 249 * RETURN: None 250 * 251 * DESCRIPTION: Add external files to global list 252 * 253 ******************************************************************************/ 254 255 ACPI_STATUS 256 AcpiDmAddToExternalFileList ( 257 char *PathList) 258 { 259 ACPI_EXTERNAL_FILE *ExternalFile; 260 char *Path; 261 char *TmpPath; 262 263 264 if (!PathList) 265 { 266 return (AE_OK); 267 } 268 269 Path = strtok (PathList, ","); 270 271 while (Path) 272 { 273 TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1); 274 if (!TmpPath) 275 { 276 return (AE_NO_MEMORY); 277 } 278 279 ACPI_STRCPY (TmpPath, Path); 280 281 ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE)); 282 if (!ExternalFile) 283 { 284 ACPI_FREE (TmpPath); 285 return (AE_NO_MEMORY); 286 } 287 288 ExternalFile->Path = TmpPath; 289 290 if (AcpiGbl_ExternalFileList) 291 { 292 ExternalFile->Next = AcpiGbl_ExternalFileList; 293 } 294 295 AcpiGbl_ExternalFileList = ExternalFile; 296 Path = strtok (NULL, ","); 297 } 298 299 return (AE_OK); 300 } 301 302 303 /******************************************************************************* 304 * 305 * FUNCTION: AcpiDmClearExternalFileList 306 * 307 * PARAMETERS: None 308 * 309 * RETURN: None 310 * 311 * DESCRIPTION: Clear the external file list 312 * 313 ******************************************************************************/ 314 315 void 316 AcpiDmClearExternalFileList ( 317 void) 318 { 319 ACPI_EXTERNAL_FILE *NextExternal; 320 321 322 while (AcpiGbl_ExternalFileList) 323 { 324 NextExternal = AcpiGbl_ExternalFileList->Next; 325 ACPI_FREE (AcpiGbl_ExternalFileList->Path); 326 ACPI_FREE (AcpiGbl_ExternalFileList); 327 AcpiGbl_ExternalFileList = NextExternal; 328 } 329 } 330 331 332 /******************************************************************************* 333 * 334 * FUNCTION: AcpiDmAddToExternalList 335 * 336 * PARAMETERS: Op - Current parser Op 337 * Path - Internal (AML) path to the object 338 * Type - ACPI object type to be added 339 * Value - Arg count if adding a Method object 340 * 341 * RETURN: None 342 * 343 * DESCRIPTION: Insert a new name into the global list of Externals which 344 * will in turn be later emitted as an External() declaration 345 * in the disassembled output. 346 * 347 ******************************************************************************/ 348 349 void 350 AcpiDmAddToExternalList ( 351 ACPI_PARSE_OBJECT *Op, 352 char *Path, 353 UINT8 Type, 354 UINT32 Value) 355 { 356 char *ExternalPath; 357 char *Fullpath = NULL; 358 ACPI_EXTERNAL_LIST *NewExternal; 359 ACPI_EXTERNAL_LIST *NextExternal; 360 ACPI_EXTERNAL_LIST *PrevExternal = NULL; 361 ACPI_STATUS Status; 362 363 364 if (!Path) 365 { 366 return; 367 } 368 369 /* Externalize the ACPI path */ 370 371 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path, 372 NULL, &ExternalPath); 373 if (ACPI_FAILURE (Status)) 374 { 375 return; 376 } 377 378 /* Get the full pathname from root if "Path" has a parent prefix */ 379 380 if (*Path == (UINT8) AML_PARENT_PREFIX) 381 { 382 Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath); 383 if (Fullpath) 384 { 385 /* Set new external path */ 386 387 ACPI_FREE (ExternalPath); 388 ExternalPath = Fullpath; 389 } 390 } 391 392 /* Check all existing externals to ensure no duplicates */ 393 394 NextExternal = AcpiGbl_ExternalList; 395 while (NextExternal) 396 { 397 if (!ACPI_STRCMP (ExternalPath, NextExternal->Path)) 398 { 399 /* Duplicate method, check that the Value (ArgCount) is the same */ 400 401 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 402 (NextExternal->Value != Value)) 403 { 404 ACPI_ERROR ((AE_INFO, 405 "Argument count mismatch for method %s %u %u", 406 NextExternal->Path, NextExternal->Value, Value)); 407 } 408 409 /* Allow upgrade of type from ANY */ 410 411 else if (NextExternal->Type == ACPI_TYPE_ANY) 412 { 413 NextExternal->Type = Type; 414 NextExternal->Value = Value; 415 } 416 417 ACPI_FREE (ExternalPath); 418 return; 419 } 420 421 NextExternal = NextExternal->Next; 422 } 423 424 /* Allocate and init a new External() descriptor */ 425 426 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); 427 if (!NewExternal) 428 { 429 ACPI_FREE (ExternalPath); 430 return; 431 } 432 433 NewExternal->Path = ExternalPath; 434 NewExternal->Type = Type; 435 NewExternal->Value = Value; 436 NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath); 437 438 /* Was the external path with parent prefix normalized to a fullpath? */ 439 440 if (Fullpath == ExternalPath) 441 { 442 /* Get new internal path */ 443 444 Status = AcpiNsInternalizeName (ExternalPath, &Path); 445 if (ACPI_FAILURE (Status)) 446 { 447 ACPI_FREE (ExternalPath); 448 ACPI_FREE (NewExternal); 449 return; 450 } 451 452 /* Set flag to indicate External->InternalPath need to be freed */ 453 454 NewExternal->Flags |= ACPI_IPATH_ALLOCATED; 455 } 456 457 NewExternal->InternalPath = Path; 458 459 /* Link the new descriptor into the global list, alphabetically ordered */ 460 461 NextExternal = AcpiGbl_ExternalList; 462 while (NextExternal) 463 { 464 if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0) 465 { 466 if (PrevExternal) 467 { 468 PrevExternal->Next = NewExternal; 469 } 470 else 471 { 472 AcpiGbl_ExternalList = NewExternal; 473 } 474 475 NewExternal->Next = NextExternal; 476 return; 477 } 478 479 PrevExternal = NextExternal; 480 NextExternal = NextExternal->Next; 481 } 482 483 if (PrevExternal) 484 { 485 PrevExternal->Next = NewExternal; 486 } 487 else 488 { 489 AcpiGbl_ExternalList = NewExternal; 490 } 491 } 492 493 494 /******************************************************************************* 495 * 496 * FUNCTION: AcpiDmAddExternalsToNamespace 497 * 498 * PARAMETERS: None 499 * 500 * RETURN: None 501 * 502 * DESCRIPTION: Add all externals to the namespace. Allows externals to be 503 * "resolved". 504 * 505 ******************************************************************************/ 506 507 void 508 AcpiDmAddExternalsToNamespace ( 509 void) 510 { 511 ACPI_STATUS Status; 512 ACPI_NAMESPACE_NODE *Node; 513 ACPI_OPERAND_OBJECT *ObjDesc; 514 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 515 516 517 while (External) 518 { 519 /* Add the external name (object) into the namespace */ 520 521 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type, 522 ACPI_IMODE_LOAD_PASS1, 523 ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE, 524 NULL, &Node); 525 526 if (ACPI_FAILURE (Status)) 527 { 528 ACPI_EXCEPTION ((AE_INFO, Status, 529 "while adding external to namespace [%s]", 530 External->Path)); 531 } 532 533 else switch (External->Type) 534 { 535 case ACPI_TYPE_METHOD: 536 537 /* For methods, we need to save the argument count */ 538 539 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 540 ObjDesc->Method.ParamCount = (UINT8) External->Value; 541 Node->Object = ObjDesc; 542 break; 543 544 case ACPI_TYPE_REGION: 545 546 /* Regions require a region sub-object */ 547 548 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); 549 ObjDesc->Region.Node = Node; 550 Node->Object = ObjDesc; 551 break; 552 553 default: 554 break; 555 } 556 557 External = External->Next; 558 } 559 } 560 561 562 /******************************************************************************* 563 * 564 * FUNCTION: AcpiDmGetExternalMethodCount 565 * 566 * PARAMETERS: None 567 * 568 * RETURN: The number of control method externals in the external list 569 * 570 * DESCRIPTION: Return the number of method externals that have been generated. 571 * If any control method externals have been found, we must 572 * re-parse the entire definition block with the new information 573 * (number of arguments for the methods.) This is limitation of 574 * AML, we don't know the number of arguments from the control 575 * method invocation itself. 576 * 577 ******************************************************************************/ 578 579 UINT32 580 AcpiDmGetExternalMethodCount ( 581 void) 582 { 583 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 584 UINT32 Count = 0; 585 586 587 while (External) 588 { 589 if (External->Type == ACPI_TYPE_METHOD) 590 { 591 Count++; 592 } 593 594 External = External->Next; 595 } 596 597 return (Count); 598 } 599 600 601 /******************************************************************************* 602 * 603 * FUNCTION: AcpiDmClearExternalList 604 * 605 * PARAMETERS: None 606 * 607 * RETURN: None 608 * 609 * DESCRIPTION: Free the entire External info list 610 * 611 ******************************************************************************/ 612 613 void 614 AcpiDmClearExternalList ( 615 void) 616 { 617 ACPI_EXTERNAL_LIST *NextExternal; 618 619 620 while (AcpiGbl_ExternalList) 621 { 622 NextExternal = AcpiGbl_ExternalList->Next; 623 ACPI_FREE (AcpiGbl_ExternalList->Path); 624 ACPI_FREE (AcpiGbl_ExternalList); 625 AcpiGbl_ExternalList = NextExternal; 626 } 627 } 628 629 630 /******************************************************************************* 631 * 632 * FUNCTION: AcpiDmEmitExternals 633 * 634 * PARAMETERS: None 635 * 636 * RETURN: None 637 * 638 * DESCRIPTION: Emit an External() ASL statement for each of the externals in 639 * the global external info list. 640 * 641 ******************************************************************************/ 642 643 void 644 AcpiDmEmitExternals ( 645 void) 646 { 647 ACPI_EXTERNAL_LIST *NextExternal; 648 649 650 if (!AcpiGbl_ExternalList) 651 { 652 return; 653 } 654 655 /* 656 * Walk the list of externals (unresolved references) 657 * found during the AML parsing 658 */ 659 while (AcpiGbl_ExternalList) 660 { 661 AcpiOsPrintf (" External (%s%s", 662 AcpiGbl_ExternalList->Path, 663 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type)); 664 665 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) 666 { 667 AcpiOsPrintf (") // %u Arguments\n", 668 AcpiGbl_ExternalList->Value); 669 } 670 else 671 { 672 AcpiOsPrintf (")\n"); 673 } 674 675 /* Free this external info block and move on to next external */ 676 677 NextExternal = AcpiGbl_ExternalList->Next; 678 if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED) 679 { 680 ACPI_FREE (AcpiGbl_ExternalList->InternalPath); 681 } 682 683 ACPI_FREE (AcpiGbl_ExternalList->Path); 684 ACPI_FREE (AcpiGbl_ExternalList); 685 AcpiGbl_ExternalList = NextExternal; 686 } 687 688 AcpiOsPrintf ("\n"); 689 } 690 691