1 /******************************************************************************
2  *
3  * Module Name: aslexternal - ASL External opcode compiler support
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "acparser.h"
47 #include "amlcode.h"
48 #include "acnamesp.h"
49 
50 
51 #define _COMPONENT          ACPI_COMPILER
52         ACPI_MODULE_NAME    ("aslexternal")
53 
54 
55 /* Local prototypes */
56 
57 static void
58 ExInsertArgCount (
59     ACPI_PARSE_OBJECT       *Op);
60 
61 static void
62 ExMoveExternals (
63     ACPI_PARSE_OBJECT       *DefinitionBlockOp);
64 
65 
66 /*******************************************************************************
67  *
68  * FUNCTION:    ExDoExternal
69  *
70  * PARAMETERS:  Op                  - Current Parse node
71  *
72  * RETURN:      None
73  *
74  * DESCRIPTION: Add an External() definition to the global list. This list
75  *              is used to generate External opcodes.
76  *
77  ******************************************************************************/
78 
79 void
80 ExDoExternal (
81     ACPI_PARSE_OBJECT       *Op)
82 {
83     ACPI_PARSE_OBJECT       *ListOp;
84     ACPI_PARSE_OBJECT       *Prev;
85     ACPI_PARSE_OBJECT       *Next;
86     ACPI_PARSE_OBJECT       *ArgCountOp;
87 
88 
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);
94 
95     /* Create new list node of arbitrary type */
96 
97     ListOp = TrAllocateNode (PARSEOP_DEFAULT_ARG);
98 
99     /* Store External node as child */
100 
101     ListOp->Asl.Child = Op;
102     ListOp->Asl.Next = NULL;
103 
104     if (Gbl_ExternalsListHead)
105     {
106         /* Link new External to end of list */
107 
108         Prev = Gbl_ExternalsListHead;
109         Next = Prev;
110         while (Next)
111         {
112             Prev = Next;
113             Next = Next->Asl.Next;
114         }
115 
116         Prev->Asl.Next = ListOp;
117     }
118     else
119     {
120         Gbl_ExternalsListHead = ListOp;
121     }
122 }
123 
124 
125 /*******************************************************************************
126  *
127  * FUNCTION:    ExInsertArgCount
128  *
129  * PARAMETERS:  Op              - Op for a method invocation
130  *
131  * RETURN:      None
132  *
133  * DESCRIPTION: Obtain the number of arguments for a control method -- from
134  *              the actual invocation.
135  *
136  ******************************************************************************/
137 
138 static void
139 ExInsertArgCount (
140     ACPI_PARSE_OBJECT       *Op)
141 {
142     ACPI_PARSE_OBJECT       *Next;
143     ACPI_PARSE_OBJECT       *NameOp;
144     ACPI_PARSE_OBJECT       *Child;
145     ACPI_PARSE_OBJECT       *ArgCountOp;
146     char *                  ExternalName;
147     char *                  CallName;
148     UINT16                  ArgCount = 0;
149 
150 
151     CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
152 
153     Next = Gbl_ExternalsListHead;
154     while (Next)
155     {
156         ArgCount = 0;
157 
158         /* Skip if External node already handled */
159 
160         if (Next->Asl.Child->Asl.CompileFlags & NODE_VISITED)
161         {
162             Next = Next->Asl.Next;
163             continue;
164         }
165 
166         NameOp = Next->Asl.Child->Asl.Child;
167         ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE);
168 
169         if (!strcmp (CallName, ExternalName))
170         {
171             Next->Asl.Child->Asl.CompileFlags |= NODE_VISITED;
172 
173             /*
174              * Since we will reposition Externals to the Root, set Namepath
175              * to the fully qualified name and recalculate the aml length
176              */
177             if (ACPI_FAILURE (UtInternalizeName (
178                 ExternalName, &NameOp->Asl.Value.String)))
179             {
180                 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
181                     NULL, "- Could not Internalize External");
182 
183                 break;
184             }
185 
186             NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String);
187 
188             /* Get argument count */
189 
190             Child = Op->Asl.Child;
191             while (Child)
192             {
193                 ArgCount++;
194                 Child = Child->Asl.Next;
195             }
196 
197             /* Setup ArgCount operand */
198 
199             ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next;
200             ArgCountOp->Asl.Value.Integer = ArgCount;
201             break;
202         }
203 
204         Next = Next->Asl.Next;
205     }
206 }
207 
208 
209 /*******************************************************************************
210  *
211  * FUNCTION:    ExAmlExternalWalkBegin
212  *
213  * PARAMETERS:  ASL_WALK_CALLBACK
214  *
215  * RETURN:      None
216  *
217  * DESCRIPTION: Parse tree walk to create external opcode list for methods.
218  *
219  ******************************************************************************/
220 
221 ACPI_STATUS
222 ExAmlExternalWalkBegin (
223     ACPI_PARSE_OBJECT       *Op,
224     UINT32                  Level,
225     void                    *Context)
226 {
227 
228     /* External list head saved in the definition block op */
229 
230     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
231     {
232         Gbl_ExternalsListHead = Op->Asl.Value.Arg;
233     }
234 
235     if (!Gbl_ExternalsListHead)
236     {
237         return (AE_OK);
238     }
239 
240     if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)
241     {
242         return (AE_OK);
243     }
244 
245     /*
246      * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL
247      * by XfNamespaceLocateBegin(). Ignore these.
248      */
249     if (Op->Asl.Parent &&
250         Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL)
251     {
252         return (AE_OK);
253     }
254 
255     ExInsertArgCount (Op);
256     return (AE_OK);
257 }
258 
259 
260 /*******************************************************************************
261  *
262  * FUNCTION:    ExAmlExternalWalkEnd
263  *
264  * PARAMETERS:  ASL_WALK_CALLBACK
265  *
266  * RETURN:      None
267  *
268  * DESCRIPTION: Parse tree walk to create external opcode list for methods.
269  *              Here, we just want to catch the case where a definition block
270  *              has been completed. Then we move all of the externals into
271  *              a single block in the parse tree and thus the AML code.
272  *
273  ******************************************************************************/
274 
275 ACPI_STATUS
276 ExAmlExternalWalkEnd (
277     ACPI_PARSE_OBJECT       *Op,
278     UINT32                  Level,
279     void                    *Context)
280 {
281 
282     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
283     {
284         /*
285          * Process any existing external list. (Support for
286          * multiple definition blocks in a single file/compile)
287          */
288         ExMoveExternals (Op);
289         Gbl_ExternalsListHead = NULL;
290     }
291 
292     return (AE_OK);
293 }
294 
295 
296 /*******************************************************************************
297  *
298  * FUNCTION:    ExMoveExternals
299  *
300  * PARAMETERS:  DefinitionBlockOp       - Op for current definition block
301  *
302  * RETURN:      None
303  *
304  * DESCRIPTION: Move all externals present in the source file into a single
305  *              block of AML code, surrounded by an "If (0)" to prevent
306  *              AML interpreters from attempting to execute the External
307  *              opcodes.
308  *
309  ******************************************************************************/
310 
311 static void
312 ExMoveExternals (
313     ACPI_PARSE_OBJECT       *DefinitionBlockOp)
314 {
315     ACPI_PARSE_OBJECT       *ParentOp;
316     ACPI_PARSE_OBJECT       *ExternalOp;
317     ACPI_PARSE_OBJECT       *PredicateOp;
318     ACPI_PARSE_OBJECT       *NextOp;
319     ACPI_PARSE_OBJECT       *Prev;
320     ACPI_PARSE_OBJECT       *Next;
321     ACPI_OBJECT_TYPE        ObjType;
322     UINT32                  i;
323 
324 
325     if (!Gbl_ExternalsListHead)
326     {
327         return;
328     }
329 
330     /* Remove the External nodes from the tree */
331 
332     NextOp = Gbl_ExternalsListHead;
333     while (NextOp)
334     {
335         /*
336          * The External is stored in child pointer of each node in the
337          * list
338          */
339         ExternalOp = NextOp->Asl.Child;
340 
341         /* Set line numbers (for listings, etc.) */
342 
343         ExternalOp->Asl.LineNumber = 0;
344         ExternalOp->Asl.LogicalLineNumber = 0;
345 
346         Next = ExternalOp->Asl.Child;
347         Next->Asl.LineNumber = 0;
348         Next->Asl.LogicalLineNumber = 0;
349 
350         Next = Next->Asl.Next;
351         Next->Asl.LineNumber = 0;
352         Next->Asl.LogicalLineNumber = 0;
353 
354         Next = Next->Asl.Next;
355         Next->Asl.LineNumber = 0;
356         Next->Asl.LogicalLineNumber = 0;
357 
358         Next = Next->Asl.Next;
359         Next->Asl.LineNumber = 0;
360         Next->Asl.LogicalLineNumber = 0;
361 
362         ParentOp = ExternalOp->Asl.Parent;
363         Prev = Next = ParentOp->Asl.Child;
364 
365         /* Now find the External node's position in parse tree */
366 
367         while (Next != ExternalOp)
368         {
369             Prev = Next;
370             Next = Next->Asl.Next;
371         }
372 
373         /* Remove the External from the parse tree */
374 
375         if (Prev == ExternalOp)
376         {
377             /* External was the first child node */
378 
379             ParentOp->Asl.Child = ExternalOp->Asl.Next;
380         }
381 
382         Prev->Asl.Next = ExternalOp->Asl.Next;
383         ExternalOp->Asl.Next = NULL;
384         ExternalOp->Asl.Parent = Gbl_ExternalsListHead;
385 
386         /* Point the External to the next in the list */
387 
388         if (NextOp->Asl.Next)
389         {
390             ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
391         }
392 
393         NextOp = NextOp->Asl.Next;
394     }
395 
396     /*
397      * Loop again to remove MethodObj Externals for which
398      * a MethodCall was not found (dead external reference)
399      */
400     Prev = Gbl_ExternalsListHead->Asl.Child;
401     Next = Prev;
402     while (Next)
403     {
404         ObjType = (ACPI_OBJECT_TYPE)
405             Next->Asl.Child->Asl.Next->Asl.Value.Integer;
406 
407         if (ObjType == ACPI_TYPE_METHOD &&
408             !(Next->Asl.CompileFlags & NODE_VISITED))
409         {
410             if (Next == Prev)
411             {
412                 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
413                 Next->Asl.Next = NULL;
414                 Prev = Gbl_ExternalsListHead->Asl.Child;
415                 Next = Prev;
416                 continue;
417             }
418             else
419             {
420                 Prev->Asl.Next = Next->Asl.Next;
421                 Next->Asl.Next = NULL;
422                 Next = Prev->Asl.Next;
423                 continue;
424             }
425         }
426 
427         Prev = Next;
428         Next = Next->Asl.Next;
429     }
430 
431     /* If list is now empty, don't bother to make If (0) block */
432 
433     if (!Gbl_ExternalsListHead->Asl.Child)
434     {
435         return;
436     }
437 
438     /* Convert Gbl_ExternalsListHead parent to If(). */
439 
440     Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
441     Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
442     Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE;
443     UtSetParseOpName (Gbl_ExternalsListHead);
444 
445     /* Create a Zero op for the If predicate */
446 
447     PredicateOp = TrAllocateNode (PARSEOP_ZERO);
448     PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
449 
450     PredicateOp->Asl.Parent = Gbl_ExternalsListHead;
451     PredicateOp->Asl.Child = NULL;
452     PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child;
453     Gbl_ExternalsListHead->Asl.Child = PredicateOp;
454 
455     /* Set line numbers (for listings, etc.) */
456 
457     Gbl_ExternalsListHead->Asl.LineNumber = 0;
458     Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
459 
460     PredicateOp->Asl.LineNumber = 0;
461     PredicateOp->Asl.LogicalLineNumber = 0;
462 
463     /* Insert block back in the list */
464 
465     Prev = DefinitionBlockOp->Asl.Child;
466     Next = Prev;
467 
468     /* Find last default arg */
469 
470     for (i = 0; i < 6; i++)
471     {
472         Prev = Next;
473         Next = Prev->Asl.Next;
474     }
475 
476     if (Next)
477     {
478         /* Definition Block is not empty */
479 
480         Gbl_ExternalsListHead->Asl.Next = Next;
481     }
482     else
483     {
484         /* Definition Block is empty. */
485 
486         Gbl_ExternalsListHead->Asl.Next = NULL;
487     }
488 
489     Prev->Asl.Next = Gbl_ExternalsListHead;
490     Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
491 }
492