xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/aslexternal.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /******************************************************************************
2  *
3  * Module Name: aslexternal - ASL External opcode compiler support
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2019, 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 = TrAllocateOp (PARSEOP_DEFAULT_ARG);
98 
99     /* Store External node as child */
100 
101     ListOp->Asl.Child = Op;
102     ListOp->Asl.Next = NULL;
103 
104     if (AslGbl_ExternalsListHead)
105     {
106         /* Link new External to end of list */
107 
108         Prev = AslGbl_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         AslGbl_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     ACPI_STATUS             Status;
150 
151 
152     CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
153 
154     Next = AslGbl_ExternalsListHead;
155     while (Next)
156     {
157         ArgCount = 0;
158 
159         /* Skip if External node already handled */
160 
161         if (Next->Asl.Child->Asl.CompileFlags & OP_VISITED)
162         {
163             Next = Next->Asl.Next;
164             continue;
165         }
166 
167         NameOp = Next->Asl.Child->Asl.Child;
168         ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE);
169 
170         if (strcmp (CallName, ExternalName))
171         {
172             ACPI_FREE (ExternalName);
173             Next = Next->Asl.Next;
174             continue;
175         }
176 
177         Next->Asl.Child->Asl.CompileFlags |= OP_VISITED;
178 
179         /*
180          * Since we will reposition Externals to the Root, set Namepath
181          * to the fully qualified name and recalculate the aml length
182          */
183         Status = UtInternalizeName (ExternalName,
184             &NameOp->Asl.Value.String);
185 
186         ACPI_FREE (ExternalName);
187         if (ACPI_FAILURE (Status))
188         {
189             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
190                 NULL, "- Could not Internalize External");
191             break;
192         }
193 
194         NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String);
195 
196         /* Get argument count */
197 
198         Child = Op->Asl.Child;
199         while (Child)
200         {
201             ArgCount++;
202             Child = Child->Asl.Next;
203         }
204 
205         /* Setup ArgCount operand */
206 
207         ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next;
208         ArgCountOp->Asl.Value.Integer = ArgCount;
209         break;
210     }
211 
212     ACPI_FREE (CallName);
213 }
214 
215 
216 /*******************************************************************************
217  *
218  * FUNCTION:    ExAmlExternalWalkBegin
219  *
220  * PARAMETERS:  ASL_WALK_CALLBACK
221  *
222  * RETURN:      None
223  *
224  * DESCRIPTION: Parse tree walk to create external opcode list for methods.
225  *
226  ******************************************************************************/
227 
228 ACPI_STATUS
229 ExAmlExternalWalkBegin (
230     ACPI_PARSE_OBJECT       *Op,
231     UINT32                  Level,
232     void                    *Context)
233 {
234 
235     /* External list head saved in the definition block op */
236 
237     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
238     {
239         AslGbl_ExternalsListHead = Op->Asl.Value.Arg;
240     }
241 
242     if (!AslGbl_ExternalsListHead)
243     {
244         return (AE_OK);
245     }
246 
247     if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)
248     {
249         return (AE_OK);
250     }
251 
252     /*
253      * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL
254      * by XfNamespaceLocateBegin(). Ignore these.
255      */
256     if (Op->Asl.Parent &&
257         Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL)
258     {
259         return (AE_OK);
260     }
261 
262     ExInsertArgCount (Op);
263     return (AE_OK);
264 }
265 
266 
267 /*******************************************************************************
268  *
269  * FUNCTION:    ExAmlExternalWalkEnd
270  *
271  * PARAMETERS:  ASL_WALK_CALLBACK
272  *
273  * RETURN:      None
274  *
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.
279  *
280  ******************************************************************************/
281 
282 ACPI_STATUS
283 ExAmlExternalWalkEnd (
284     ACPI_PARSE_OBJECT       *Op,
285     UINT32                  Level,
286     void                    *Context)
287 {
288 
289     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
290     {
291         /*
292          * Process any existing external list. (Support for
293          * multiple definition blocks in a single file/compile)
294          */
295         ExMoveExternals (Op);
296         AslGbl_ExternalsListHead = NULL;
297     }
298 
299     return (AE_OK);
300 }
301 
302 
303 /*******************************************************************************
304  *
305  * FUNCTION:    ExMoveExternals
306  *
307  * PARAMETERS:  DefinitionBlockOp       - Op for current definition block
308  *
309  * RETURN:      None
310  *
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
314  *              opcodes.
315  *
316  ******************************************************************************/
317 
318 static void
319 ExMoveExternals (
320     ACPI_PARSE_OBJECT       *DefinitionBlockOp)
321 {
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;
328     char                    *ExternalName;
329     ACPI_OBJECT_TYPE        ObjType;
330     ACPI_STATUS             Status;
331     UINT32                  i;
332 
333 
334     if (!AslGbl_ExternalsListHead)
335     {
336         return;
337     }
338 
339     /* Remove the External nodes from the tree */
340 
341     NextOp = AslGbl_ExternalsListHead;
342     while (NextOp)
343     {
344         /*
345          * The External is stored in child pointer of each node in the
346          * list
347          */
348         ExternalOp = NextOp->Asl.Child;
349 
350         /* Get/set the fully qualified name */
351 
352         ExternalName = AcpiNsGetNormalizedPathname (ExternalOp->Asl.Node, TRUE);
353         ExternalOp->Asl.ExternalName = ExternalName;
354         ExternalOp->Asl.Namepath = ExternalName;
355 
356         /* Set line numbers (for listings, etc.) */
357 
358         ExternalOp->Asl.LineNumber = 0;
359         ExternalOp->Asl.LogicalLineNumber = 0;
360 
361         Next = ExternalOp->Asl.Child;
362         Next->Asl.LineNumber = 0;
363         Next->Asl.LogicalLineNumber = 0;
364 
365         if (Next->Asl.ParseOpcode == PARSEOP_NAMESEG)
366         {
367             Next->Asl.ParseOpcode = PARSEOP_NAMESTRING;
368         }
369 
370         Next->Asl.ExternalName = ExternalName;
371         Status = UtInternalizeName (ExternalName, &Next->Asl.Value.String);
372         if (ACPI_FAILURE (Status))
373         {
374             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
375                 Next, "Could not internalize namestring");
376             return;
377         }
378 
379         Next->Asl.AmlLength = strlen (Next->Asl.Value.String);
380 
381         Next = Next->Asl.Next;
382         Next->Asl.LineNumber = 0;
383         Next->Asl.LogicalLineNumber = 0;
384 
385         Next = Next->Asl.Next;
386         Next->Asl.LineNumber = 0;
387         Next->Asl.LogicalLineNumber = 0;
388 
389         Next = Next->Asl.Next;
390         Next->Asl.LineNumber = 0;
391         Next->Asl.LogicalLineNumber = 0;
392 
393         ParentOp = ExternalOp->Asl.Parent;
394         Prev = Next = ParentOp->Asl.Child;
395 
396         /* Now find the External node's position in parse tree */
397 
398         while (Next != ExternalOp)
399         {
400             Prev = Next;
401             Next = Next->Asl.Next;
402         }
403 
404         /* Remove the External from the parse tree */
405 
406         if (Prev == ExternalOp)
407         {
408             /* External was the first child node */
409 
410             ParentOp->Asl.Child = ExternalOp->Asl.Next;
411         }
412 
413         Prev->Asl.Next = ExternalOp->Asl.Next;
414         ExternalOp->Asl.Next = NULL;
415         ExternalOp->Asl.Parent = AslGbl_ExternalsListHead;
416 
417         /* Point the External to the next in the list */
418 
419         if (NextOp->Asl.Next)
420         {
421             ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
422         }
423 
424         NextOp = NextOp->Asl.Next;
425     }
426 
427     /*
428      * Loop again to remove MethodObj Externals for which
429      * a MethodCall was not found (dead external reference)
430      */
431     Prev = AslGbl_ExternalsListHead->Asl.Child;
432     Next = Prev;
433     while (Next)
434     {
435         ObjType = (ACPI_OBJECT_TYPE)
436             Next->Asl.Child->Asl.Next->Asl.Value.Integer;
437 
438         if (ObjType == ACPI_TYPE_METHOD &&
439             !(Next->Asl.CompileFlags & OP_VISITED))
440         {
441             if (Next == Prev)
442             {
443                 AslGbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
444                 Next->Asl.Next = NULL;
445                 Prev = AslGbl_ExternalsListHead->Asl.Child;
446                 Next = Prev;
447                 continue;
448             }
449             else
450             {
451                 Prev->Asl.Next = Next->Asl.Next;
452                 Next->Asl.Next = NULL;
453                 Next = Prev->Asl.Next;
454                 continue;
455             }
456         }
457 
458         Prev = Next;
459         Next = Next->Asl.Next;
460     }
461 
462     /* If list is now empty, don't bother to make If (0) block */
463 
464     if (!AslGbl_ExternalsListHead->Asl.Child)
465     {
466         return;
467     }
468 
469     /* Convert Gbl_ExternalsListHead parent to If(). */
470 
471     AslGbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
472     AslGbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
473     AslGbl_ExternalsListHead->Asl.CompileFlags = OP_AML_PACKAGE;
474     UtSetParseOpName (AslGbl_ExternalsListHead);
475 
476     /* Create a Zero op for the If predicate */
477 
478     PredicateOp = TrAllocateOp (PARSEOP_ZERO);
479     PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
480 
481     PredicateOp->Asl.Parent = AslGbl_ExternalsListHead;
482     PredicateOp->Asl.Child = NULL;
483     PredicateOp->Asl.Next = AslGbl_ExternalsListHead->Asl.Child;
484     AslGbl_ExternalsListHead->Asl.Child = PredicateOp;
485 
486     /* Set line numbers (for listings, etc.) */
487 
488     AslGbl_ExternalsListHead->Asl.LineNumber = 0;
489     AslGbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
490 
491     PredicateOp->Asl.LineNumber = 0;
492     PredicateOp->Asl.LogicalLineNumber = 0;
493 
494     /* Insert block back in the list */
495 
496     Prev = DefinitionBlockOp->Asl.Child;
497     Next = Prev;
498 
499     /* Find last default arg */
500 
501     for (i = 0; i < 6; i++)
502     {
503         Prev = Next;
504         Next = Prev->Asl.Next;
505     }
506 
507     if (Next)
508     {
509         /* Definition Block is not empty */
510 
511         AslGbl_ExternalsListHead->Asl.Next = Next;
512     }
513     else
514     {
515         /* Definition Block is empty. */
516 
517         AslGbl_ExternalsListHead->Asl.Next = NULL;
518     }
519 
520     Prev->Asl.Next = AslGbl_ExternalsListHead;
521     AslGbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
522 }
523