1 /******************************************************************************
3 * Module Name: dmextern - Support for External() ASL statements
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2012, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
52 * This module is used for application-level code (iASL disassembler) only.
54 * It contains the code to create and emit any necessary External() ASL
55 * statements for the module being disassembled.
57 #define _COMPONENT ACPI_CA_DISASSEMBLER
58 ACPI_MODULE_NAME ("dmextern")
62 * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
63 * ObjectTypeKeyword. Used to generate typed external declarations
65 static const char *AcpiGbl_DmTypeNames[] =
67 /* 00 */ "", /* Type ANY */
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"
90 /* Local prototypes */
93 AcpiDmGetObjectTypeName (
94 ACPI_OBJECT_TYPE Type);
97 AcpiDmNormalizeParentPrefix (
98 ACPI_PARSE_OBJECT *Op,
102 /*******************************************************************************
104 * FUNCTION: AcpiDmGetObjectTypeName
106 * PARAMETERS: Type - An ACPI_OBJECT_TYPE
108 * RETURN: Pointer to a string
110 * DESCRIPTION: Map an object type to the ASL object type string.
112 ******************************************************************************/
115 AcpiDmGetObjectTypeName (
116 ACPI_OBJECT_TYPE Type)
119 if (Type == ACPI_TYPE_LOCAL_SCOPE)
121 Type = ACPI_TYPE_DEVICE;
124 else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
129 return (AcpiGbl_DmTypeNames[Type]);
133 /*******************************************************************************
135 * FUNCTION: AcpiDmNormalizeParentPrefix
137 * PARAMETERS: Op - Parse op
138 * Path - Path with parent prefix
140 * RETURN: The full pathname to the object (from the namespace root)
142 * DESCRIPTION: Returns the full pathname of a path with parent prefix
143 * The caller must free the fullpath returned.
145 ******************************************************************************/
148 AcpiDmNormalizeParentPrefix (
149 ACPI_PARSE_OBJECT *Op,
152 ACPI_NAMESPACE_NODE *Node;
164 /* Search upwards in the parse tree until we reach the next namespace node */
166 Op = Op->Common.Parent;
174 Op = Op->Common.Parent;
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)
187 Node = Op->Common.Node;
188 while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
199 /* Get the full pathname for the parent node */
201 ParentPath = AcpiNsGetExternalPathname (Node);
207 Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1);
211 * If ParentPath is not just a simple '\', increment the length
212 * for the required dot separator (ParentPath.Path)
216 /* For External() statements, we do not want a leading '\' */
218 if (*ParentPath == AML_ROOT_PREFIX)
224 Fullpath = ACPI_ALLOCATE_ZEROED (Length);
231 * Concatenate parent fullpath and path. For example,
232 * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
234 * Copy the parent path
236 ACPI_STRCPY (Fullpath, &ParentPath[Index]);
240 * (don't need dot if parent fullpath is a single backslash)
244 ACPI_STRCAT (Fullpath, ".");
247 /* Copy child path (carat parent prefix(es) were skipped above) */
249 ACPI_STRCAT (Fullpath, Path);
252 ACPI_FREE (ParentPath);
257 /*******************************************************************************
259 * FUNCTION: AcpiDmAddToExternalFileList
261 * PARAMETERS: PathList - Single path or list separated by comma
265 * DESCRIPTION: Add external files to global list
267 ******************************************************************************/
270 AcpiDmAddToExternalFileList (
273 ACPI_EXTERNAL_FILE *ExternalFile;
283 Path = strtok (PathList, ",");
287 TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1);
290 return (AE_NO_MEMORY);
293 ACPI_STRCPY (TmpPath, Path);
295 ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
299 return (AE_NO_MEMORY);
302 ExternalFile->Path = TmpPath;
304 if (AcpiGbl_ExternalFileList)
306 ExternalFile->Next = AcpiGbl_ExternalFileList;
309 AcpiGbl_ExternalFileList = ExternalFile;
310 Path = strtok (NULL, ",");
317 /*******************************************************************************
319 * FUNCTION: AcpiDmClearExternalFileList
325 * DESCRIPTION: Clear the external file list
327 ******************************************************************************/
330 AcpiDmClearExternalFileList (
333 ACPI_EXTERNAL_FILE *NextExternal;
336 while (AcpiGbl_ExternalFileList)
338 NextExternal = AcpiGbl_ExternalFileList->Next;
339 ACPI_FREE (AcpiGbl_ExternalFileList->Path);
340 ACPI_FREE (AcpiGbl_ExternalFileList);
341 AcpiGbl_ExternalFileList = NextExternal;
346 /*******************************************************************************
348 * FUNCTION: AcpiDmAddToExternalList
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
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.
361 ******************************************************************************/
364 AcpiDmAddToExternalList (
365 ACPI_PARSE_OBJECT *Op,
371 char *Fullpath = NULL;
372 ACPI_EXTERNAL_LIST *NewExternal;
373 ACPI_EXTERNAL_LIST *NextExternal;
374 ACPI_EXTERNAL_LIST *PrevExternal = NULL;
384 * We don't want External() statements to contain a leading '\'.
385 * This prevents duplicate external statements of the form:
390 * This would cause a compile time error when the disassembled
391 * output file is recompiled.
393 if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
398 /* Externalize the ACPI pathname */
400 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
401 NULL, &ExternalPath);
402 if (ACPI_FAILURE (Status))
408 * Get the full pathname from the root if "Path" has one or more
409 * parent prefixes (^). Note: path will not contain a leading '\'.
411 if (*Path == (UINT8) AML_PARENT_PREFIX)
413 Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
416 /* Set new external path */
418 ACPI_FREE (ExternalPath);
419 ExternalPath = Fullpath;
423 /* Check all existing externals to ensure no duplicates */
425 NextExternal = AcpiGbl_ExternalList;
428 if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
430 /* Duplicate method, check that the Value (ArgCount) is the same */
432 if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
433 (NextExternal->Value != Value))
435 ACPI_ERROR ((AE_INFO,
436 "Argument count mismatch for method %s %u %u",
437 NextExternal->Path, NextExternal->Value, Value));
440 /* Allow upgrade of type from ANY */
442 else if (NextExternal->Type == ACPI_TYPE_ANY)
444 NextExternal->Type = Type;
445 NextExternal->Value = Value;
448 ACPI_FREE (ExternalPath);
452 NextExternal = NextExternal->Next;
455 /* Allocate and init a new External() descriptor */
457 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
460 ACPI_FREE (ExternalPath);
464 NewExternal->Path = ExternalPath;
465 NewExternal->Type = Type;
466 NewExternal->Value = Value;
467 NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
469 /* Was the external path with parent prefix normalized to a fullpath? */
471 if (Fullpath == ExternalPath)
473 /* Get new internal path */
475 Status = AcpiNsInternalizeName (ExternalPath, &Path);
476 if (ACPI_FAILURE (Status))
478 ACPI_FREE (ExternalPath);
479 ACPI_FREE (NewExternal);
483 /* Set flag to indicate External->InternalPath need to be freed */
485 NewExternal->Flags |= ACPI_IPATH_ALLOCATED;
488 NewExternal->InternalPath = Path;
490 /* Link the new descriptor into the global list, alphabetically ordered */
492 NextExternal = AcpiGbl_ExternalList;
495 if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
499 PrevExternal->Next = NewExternal;
503 AcpiGbl_ExternalList = NewExternal;
506 NewExternal->Next = NextExternal;
510 PrevExternal = NextExternal;
511 NextExternal = NextExternal->Next;
516 PrevExternal->Next = NewExternal;
520 AcpiGbl_ExternalList = NewExternal;
525 /*******************************************************************************
527 * FUNCTION: AcpiDmAddExternalsToNamespace
533 * DESCRIPTION: Add all externals to the namespace. Allows externals to be
536 ******************************************************************************/
539 AcpiDmAddExternalsToNamespace (
543 ACPI_NAMESPACE_NODE *Node;
544 ACPI_OPERAND_OBJECT *ObjDesc;
545 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList;
550 /* Add the external name (object) into the namespace */
552 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
553 ACPI_IMODE_LOAD_PASS1,
554 ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
557 if (ACPI_FAILURE (Status))
559 ACPI_EXCEPTION ((AE_INFO, Status,
560 "while adding external to namespace [%s]",
564 else switch (External->Type)
566 case ACPI_TYPE_METHOD:
568 /* For methods, we need to save the argument count */
570 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
571 ObjDesc->Method.ParamCount = (UINT8) External->Value;
572 Node->Object = ObjDesc;
575 case ACPI_TYPE_REGION:
577 /* Regions require a region sub-object */
579 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
580 ObjDesc->Region.Node = Node;
581 Node->Object = ObjDesc;
588 External = External->Next;
593 /*******************************************************************************
595 * FUNCTION: AcpiDmGetExternalMethodCount
599 * RETURN: The number of control method externals in the external list
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.
608 ******************************************************************************/
611 AcpiDmGetExternalMethodCount (
614 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList;
620 if (External->Type == ACPI_TYPE_METHOD)
625 External = External->Next;
632 /*******************************************************************************
634 * FUNCTION: AcpiDmClearExternalList
640 * DESCRIPTION: Free the entire External info list
642 ******************************************************************************/
645 AcpiDmClearExternalList (
648 ACPI_EXTERNAL_LIST *NextExternal;
651 while (AcpiGbl_ExternalList)
653 NextExternal = AcpiGbl_ExternalList->Next;
654 ACPI_FREE (AcpiGbl_ExternalList->Path);
655 ACPI_FREE (AcpiGbl_ExternalList);
656 AcpiGbl_ExternalList = NextExternal;
661 /*******************************************************************************
663 * FUNCTION: AcpiDmEmitExternals
669 * DESCRIPTION: Emit an External() ASL statement for each of the externals in
670 * the global external info list.
672 ******************************************************************************/
675 AcpiDmEmitExternals (
678 ACPI_EXTERNAL_LIST *NextExternal;
681 if (!AcpiGbl_ExternalList)
687 * Walk the list of externals (unresolved references)
688 * found during the AML parsing
690 while (AcpiGbl_ExternalList)
692 AcpiOsPrintf (" External (%s%s",
693 AcpiGbl_ExternalList->Path,
694 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
696 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
698 AcpiOsPrintf (") // %u Arguments\n",
699 AcpiGbl_ExternalList->Value);
703 AcpiOsPrintf (")\n");
706 /* Free this external info block and move on to next external */
708 NextExternal = AcpiGbl_ExternalList->Next;
709 if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED)
711 ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
714 ACPI_FREE (AcpiGbl_ExternalList->Path);
715 ACPI_FREE (AcpiGbl_ExternalList);
716 AcpiGbl_ExternalList = NextExternal;