aslexternal.c revision 306536
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 <contrib/dev/acpica/compiler/aslcompiler.h>
45#include "aslcompiler.y.h"
46#include <contrib/dev/acpica/include/acparser.h>
47#include <contrib/dev/acpica/include/amlcode.h>
48#include <contrib/dev/acpica/include/acnamesp.h>
49
50
51#define _COMPONENT          ACPI_COMPILER
52        ACPI_MODULE_NAME    ("aslexternal")
53
54
55/* Local prototypes */
56
57static void
58ExInsertArgCount (
59    ACPI_PARSE_OBJECT       *Op);
60
61static void
62ExMoveExternals (
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
79void
80ExDoExternal (
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
138static void
139ExInsertArgCount (
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 = Gbl_ExternalsListHead;
155    while (Next)
156    {
157        ArgCount = 0;
158
159        /* Skip if External node already handled */
160
161        if (Next->Asl.Child->Asl.CompileFlags & NODE_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 |= NODE_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
228ACPI_STATUS
229ExAmlExternalWalkBegin (
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        Gbl_ExternalsListHead = Op->Asl.Value.Arg;
240    }
241
242    if (!Gbl_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
282ACPI_STATUS
283ExAmlExternalWalkEnd (
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        Gbl_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
318static void
319ExMoveExternals (
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    ACPI_OBJECT_TYPE        ObjType;
329    UINT32                  i;
330
331
332    if (!Gbl_ExternalsListHead)
333    {
334        return;
335    }
336
337    /* Remove the External nodes from the tree */
338
339    NextOp = Gbl_ExternalsListHead;
340    while (NextOp)
341    {
342        /*
343         * The External is stored in child pointer of each node in the
344         * list
345         */
346        ExternalOp = NextOp->Asl.Child;
347
348        /* Set line numbers (for listings, etc.) */
349
350        ExternalOp->Asl.LineNumber = 0;
351        ExternalOp->Asl.LogicalLineNumber = 0;
352
353        Next = ExternalOp->Asl.Child;
354        Next->Asl.LineNumber = 0;
355        Next->Asl.LogicalLineNumber = 0;
356
357        Next = Next->Asl.Next;
358        Next->Asl.LineNumber = 0;
359        Next->Asl.LogicalLineNumber = 0;
360
361        Next = Next->Asl.Next;
362        Next->Asl.LineNumber = 0;
363        Next->Asl.LogicalLineNumber = 0;
364
365        Next = Next->Asl.Next;
366        Next->Asl.LineNumber = 0;
367        Next->Asl.LogicalLineNumber = 0;
368
369        ParentOp = ExternalOp->Asl.Parent;
370        Prev = Next = ParentOp->Asl.Child;
371
372        /* Now find the External node's position in parse tree */
373
374        while (Next != ExternalOp)
375        {
376            Prev = Next;
377            Next = Next->Asl.Next;
378        }
379
380        /* Remove the External from the parse tree */
381
382        if (Prev == ExternalOp)
383        {
384            /* External was the first child node */
385
386            ParentOp->Asl.Child = ExternalOp->Asl.Next;
387        }
388
389        Prev->Asl.Next = ExternalOp->Asl.Next;
390        ExternalOp->Asl.Next = NULL;
391        ExternalOp->Asl.Parent = Gbl_ExternalsListHead;
392
393        /* Point the External to the next in the list */
394
395        if (NextOp->Asl.Next)
396        {
397            ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
398        }
399
400        NextOp = NextOp->Asl.Next;
401    }
402
403    /*
404     * Loop again to remove MethodObj Externals for which
405     * a MethodCall was not found (dead external reference)
406     */
407    Prev = Gbl_ExternalsListHead->Asl.Child;
408    Next = Prev;
409    while (Next)
410    {
411        ObjType = (ACPI_OBJECT_TYPE)
412            Next->Asl.Child->Asl.Next->Asl.Value.Integer;
413
414        if (ObjType == ACPI_TYPE_METHOD &&
415            !(Next->Asl.CompileFlags & NODE_VISITED))
416        {
417            if (Next == Prev)
418            {
419                Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
420                Next->Asl.Next = NULL;
421                Prev = Gbl_ExternalsListHead->Asl.Child;
422                Next = Prev;
423                continue;
424            }
425            else
426            {
427                Prev->Asl.Next = Next->Asl.Next;
428                Next->Asl.Next = NULL;
429                Next = Prev->Asl.Next;
430                continue;
431            }
432        }
433
434        Prev = Next;
435        Next = Next->Asl.Next;
436    }
437
438    /* If list is now empty, don't bother to make If (0) block */
439
440    if (!Gbl_ExternalsListHead->Asl.Child)
441    {
442        return;
443    }
444
445    /* Convert Gbl_ExternalsListHead parent to If(). */
446
447    Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
448    Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
449    Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE;
450    UtSetParseOpName (Gbl_ExternalsListHead);
451
452    /* Create a Zero op for the If predicate */
453
454    PredicateOp = TrAllocateNode (PARSEOP_ZERO);
455    PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
456
457    PredicateOp->Asl.Parent = Gbl_ExternalsListHead;
458    PredicateOp->Asl.Child = NULL;
459    PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child;
460    Gbl_ExternalsListHead->Asl.Child = PredicateOp;
461
462    /* Set line numbers (for listings, etc.) */
463
464    Gbl_ExternalsListHead->Asl.LineNumber = 0;
465    Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
466
467    PredicateOp->Asl.LineNumber = 0;
468    PredicateOp->Asl.LogicalLineNumber = 0;
469
470    /* Insert block back in the list */
471
472    Prev = DefinitionBlockOp->Asl.Child;
473    Next = Prev;
474
475    /* Find last default arg */
476
477    for (i = 0; i < 6; i++)
478    {
479        Prev = Next;
480        Next = Prev->Asl.Next;
481    }
482
483    if (Next)
484    {
485        /* Definition Block is not empty */
486
487        Gbl_ExternalsListHead->Asl.Next = Next;
488    }
489    else
490    {
491        /* Definition Block is empty. */
492
493        Gbl_ExternalsListHead->Asl.Next = NULL;
494    }
495
496    Prev->Asl.Next = Gbl_ExternalsListHead;
497    Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
498}
499