1 /******************************************************************************
3 * Module Name: aslexternal - ASL External opcode compiler support
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2016, 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.
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
51 #define _COMPONENT ACPI_COMPILER
52 ACPI_MODULE_NAME ("aslexternal")
55 /* Local prototypes */
59 ACPI_PARSE_OBJECT *Op);
63 ACPI_PARSE_OBJECT *DefinitionBlockOp);
66 /*******************************************************************************
68 * FUNCTION: ExDoExternal
70 * PARAMETERS: Op - Current Parse node
74 * DESCRIPTION: Add an External() definition to the global list. This list
75 * is used to generate External opcodes.
77 ******************************************************************************/
81 ACPI_PARSE_OBJECT *Op)
83 ACPI_PARSE_OBJECT *ListOp;
84 ACPI_PARSE_OBJECT *Prev;
85 ACPI_PARSE_OBJECT *Next;
86 ACPI_PARSE_OBJECT *ArgCountOp;
89 ArgCountOp = Op->Asl.Child->Asl.Next->Asl.Next;
90 ArgCountOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
91 ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST;
92 ArgCountOp->Asl.Value.Integer = 0;
93 UtSetParseOpName (ArgCountOp);
95 /* Create new list node of arbitrary type */
97 ListOp = TrAllocateNode (PARSEOP_DEFAULT_ARG);
99 /* Store External node as child */
101 ListOp->Asl.Child = Op;
102 ListOp->Asl.Next = NULL;
104 if (Gbl_ExternalsListHead)
106 /* Link new External to end of list */
108 Prev = Gbl_ExternalsListHead;
113 Next = Next->Asl.Next;
116 Prev->Asl.Next = ListOp;
120 Gbl_ExternalsListHead = ListOp;
125 /*******************************************************************************
127 * FUNCTION: ExInsertArgCount
129 * PARAMETERS: Op - Op for a method invocation
133 * DESCRIPTION: Obtain the number of arguments for a control method -- from
134 * the actual invocation.
136 ******************************************************************************/
140 ACPI_PARSE_OBJECT *Op)
142 ACPI_PARSE_OBJECT *Next;
143 ACPI_PARSE_OBJECT *NameOp;
144 ACPI_PARSE_OBJECT *Child;
145 ACPI_PARSE_OBJECT *ArgCountOp;
152 CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
154 Next = Gbl_ExternalsListHead;
159 /* Skip if External node already handled */
161 if (Next->Asl.Child->Asl.CompileFlags & NODE_VISITED)
163 Next = Next->Asl.Next;
167 NameOp = Next->Asl.Child->Asl.Child;
168 ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE);
170 if (strcmp (CallName, ExternalName))
172 ACPI_FREE (ExternalName);
173 Next = Next->Asl.Next;
177 Next->Asl.Child->Asl.CompileFlags |= NODE_VISITED;
180 * Since we will reposition Externals to the Root, set Namepath
181 * to the fully qualified name and recalculate the aml length
183 Status = UtInternalizeName (ExternalName,
184 &NameOp->Asl.Value.String);
186 ACPI_FREE (ExternalName);
187 if (ACPI_FAILURE (Status))
189 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
190 NULL, "- Could not Internalize External");
194 NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String);
196 /* Get argument count */
198 Child = Op->Asl.Child;
202 Child = Child->Asl.Next;
205 /* Setup ArgCount operand */
207 ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next;
208 ArgCountOp->Asl.Value.Integer = ArgCount;
212 ACPI_FREE (CallName);
216 /*******************************************************************************
218 * FUNCTION: ExAmlExternalWalkBegin
220 * PARAMETERS: ASL_WALK_CALLBACK
224 * DESCRIPTION: Parse tree walk to create external opcode list for methods.
226 ******************************************************************************/
229 ExAmlExternalWalkBegin (
230 ACPI_PARSE_OBJECT *Op,
235 /* External list head saved in the definition block op */
237 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
239 Gbl_ExternalsListHead = Op->Asl.Value.Arg;
242 if (!Gbl_ExternalsListHead)
247 if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)
253 * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL
254 * by XfNamespaceLocateBegin(). Ignore these.
256 if (Op->Asl.Parent &&
257 Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL)
262 ExInsertArgCount (Op);
267 /*******************************************************************************
269 * FUNCTION: ExAmlExternalWalkEnd
271 * PARAMETERS: ASL_WALK_CALLBACK
275 * DESCRIPTION: Parse tree walk to create external opcode list for methods.
276 * Here, we just want to catch the case where a definition block
277 * has been completed. Then we move all of the externals into
278 * a single block in the parse tree and thus the AML code.
280 ******************************************************************************/
283 ExAmlExternalWalkEnd (
284 ACPI_PARSE_OBJECT *Op,
289 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
292 * Process any existing external list. (Support for
293 * multiple definition blocks in a single file/compile)
295 ExMoveExternals (Op);
296 Gbl_ExternalsListHead = NULL;
303 /*******************************************************************************
305 * FUNCTION: ExMoveExternals
307 * PARAMETERS: DefinitionBlockOp - Op for current definition block
311 * DESCRIPTION: Move all externals present in the source file into a single
312 * block of AML code, surrounded by an "If (0)" to prevent
313 * AML interpreters from attempting to execute the External
316 ******************************************************************************/
320 ACPI_PARSE_OBJECT *DefinitionBlockOp)
322 ACPI_PARSE_OBJECT *ParentOp;
323 ACPI_PARSE_OBJECT *ExternalOp;
324 ACPI_PARSE_OBJECT *PredicateOp;
325 ACPI_PARSE_OBJECT *NextOp;
326 ACPI_PARSE_OBJECT *Prev;
327 ACPI_PARSE_OBJECT *Next;
329 ACPI_OBJECT_TYPE ObjType;
333 if (!Gbl_ExternalsListHead)
338 /* Remove the External nodes from the tree */
340 NextOp = Gbl_ExternalsListHead;
344 * The External is stored in child pointer of each node in the
347 ExternalOp = NextOp->Asl.Child;
349 /* Get/set the fully qualified name */
351 ExternalName = AcpiNsGetNormalizedPathname (ExternalOp->Asl.Node, TRUE);
352 ExternalOp->Asl.ExternalName = ExternalName;
353 ExternalOp->Asl.Namepath = ExternalName;
355 /* Set line numbers (for listings, etc.) */
357 ExternalOp->Asl.LineNumber = 0;
358 ExternalOp->Asl.LogicalLineNumber = 0;
360 Next = ExternalOp->Asl.Child;
361 Next->Asl.LineNumber = 0;
362 Next->Asl.LogicalLineNumber = 0;
364 if (Next->Asl.ParseOpcode == PARSEOP_NAMESEG)
366 Next->Asl.ParseOpcode = PARSEOP_NAMESTRING;
368 Next->Asl.ExternalName = ExternalName;
369 UtInternalizeName (ExternalName, &Next->Asl.Value.String);
370 Next->Asl.AmlLength = strlen (Next->Asl.Value.String);
372 Next = Next->Asl.Next;
373 Next->Asl.LineNumber = 0;
374 Next->Asl.LogicalLineNumber = 0;
376 Next = Next->Asl.Next;
377 Next->Asl.LineNumber = 0;
378 Next->Asl.LogicalLineNumber = 0;
380 Next = Next->Asl.Next;
381 Next->Asl.LineNumber = 0;
382 Next->Asl.LogicalLineNumber = 0;
384 ParentOp = ExternalOp->Asl.Parent;
385 Prev = Next = ParentOp->Asl.Child;
387 /* Now find the External node's position in parse tree */
389 while (Next != ExternalOp)
392 Next = Next->Asl.Next;
395 /* Remove the External from the parse tree */
397 if (Prev == ExternalOp)
399 /* External was the first child node */
401 ParentOp->Asl.Child = ExternalOp->Asl.Next;
404 Prev->Asl.Next = ExternalOp->Asl.Next;
405 ExternalOp->Asl.Next = NULL;
406 ExternalOp->Asl.Parent = Gbl_ExternalsListHead;
408 /* Point the External to the next in the list */
410 if (NextOp->Asl.Next)
412 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
415 NextOp = NextOp->Asl.Next;
419 * Loop again to remove MethodObj Externals for which
420 * a MethodCall was not found (dead external reference)
422 Prev = Gbl_ExternalsListHead->Asl.Child;
426 ObjType = (ACPI_OBJECT_TYPE)
427 Next->Asl.Child->Asl.Next->Asl.Value.Integer;
429 if (ObjType == ACPI_TYPE_METHOD &&
430 !(Next->Asl.CompileFlags & NODE_VISITED))
434 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
435 Next->Asl.Next = NULL;
436 Prev = Gbl_ExternalsListHead->Asl.Child;
442 Prev->Asl.Next = Next->Asl.Next;
443 Next->Asl.Next = NULL;
444 Next = Prev->Asl.Next;
450 Next = Next->Asl.Next;
453 /* If list is now empty, don't bother to make If (0) block */
455 if (!Gbl_ExternalsListHead->Asl.Child)
460 /* Convert Gbl_ExternalsListHead parent to If(). */
462 Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
463 Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
464 Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE;
465 UtSetParseOpName (Gbl_ExternalsListHead);
467 /* Create a Zero op for the If predicate */
469 PredicateOp = TrAllocateNode (PARSEOP_ZERO);
470 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
472 PredicateOp->Asl.Parent = Gbl_ExternalsListHead;
473 PredicateOp->Asl.Child = NULL;
474 PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child;
475 Gbl_ExternalsListHead->Asl.Child = PredicateOp;
477 /* Set line numbers (for listings, etc.) */
479 Gbl_ExternalsListHead->Asl.LineNumber = 0;
480 Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
482 PredicateOp->Asl.LineNumber = 0;
483 PredicateOp->Asl.LogicalLineNumber = 0;
485 /* Insert block back in the list */
487 Prev = DefinitionBlockOp->Asl.Child;
490 /* Find last default arg */
492 for (i = 0; i < 6; i++)
495 Next = Prev->Asl.Next;
500 /* Definition Block is not empty */
502 Gbl_ExternalsListHead->Asl.Next = Next;
506 /* Definition Block is empty. */
508 Gbl_ExternalsListHead->Asl.Next = NULL;
511 Prev->Asl.Next = Gbl_ExternalsListHead;
512 Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;