1295571Sjkim/******************************************************************************
2295571Sjkim *
3295571Sjkim * Module Name: aslexternal - ASL External opcode compiler support
4295571Sjkim *
5295571Sjkim *****************************************************************************/
6295571Sjkim
7295571Sjkim/*
8295571Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
9295571Sjkim * All rights reserved.
10295571Sjkim *
11295571Sjkim * Redistribution and use in source and binary forms, with or without
12295571Sjkim * modification, are permitted provided that the following conditions
13295571Sjkim * are met:
14295571Sjkim * 1. Redistributions of source code must retain the above copyright
15295571Sjkim *    notice, this list of conditions, and the following disclaimer,
16295571Sjkim *    without modification.
17295571Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18295571Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19295571Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20295571Sjkim *    including a substantially similar Disclaimer requirement for further
21295571Sjkim *    binary redistribution.
22295571Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23295571Sjkim *    of any contributors may be used to endorse or promote products derived
24295571Sjkim *    from this software without specific prior written permission.
25295571Sjkim *
26295571Sjkim * Alternatively, this software may be distributed under the terms of the
27295571Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28295571Sjkim * Software Foundation.
29295571Sjkim *
30295571Sjkim * NO WARRANTY
31295571Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32295571Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33295571Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34295571Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35295571Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36295571Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37295571Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38295571Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39295571Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40295571Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41295571Sjkim * POSSIBILITY OF SUCH DAMAGES.
42295571Sjkim */
43295571Sjkim
44298714Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
45295571Sjkim#include "aslcompiler.y.h"
46298714Sjkim#include <contrib/dev/acpica/include/acparser.h>
47298714Sjkim#include <contrib/dev/acpica/include/amlcode.h>
48298714Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
49295571Sjkim
50295571Sjkim
51295571Sjkim#define _COMPONENT          ACPI_COMPILER
52295571Sjkim        ACPI_MODULE_NAME    ("aslexternal")
53295571Sjkim
54295571Sjkim
55295571Sjkim/* Local prototypes */
56295571Sjkim
57295571Sjkimstatic void
58295571SjkimExInsertArgCount (
59295571Sjkim    ACPI_PARSE_OBJECT       *Op);
60295571Sjkim
61295571Sjkimstatic void
62295571SjkimExMoveExternals (
63295571Sjkim    ACPI_PARSE_OBJECT       *DefinitionBlockOp);
64295571Sjkim
65295571Sjkim
66295571Sjkim/*******************************************************************************
67295571Sjkim *
68295571Sjkim * FUNCTION:    ExDoExternal
69295571Sjkim *
70295571Sjkim * PARAMETERS:  Op                  - Current Parse node
71295571Sjkim *
72295571Sjkim * RETURN:      None
73295571Sjkim *
74295571Sjkim * DESCRIPTION: Add an External() definition to the global list. This list
75295571Sjkim *              is used to generate External opcodes.
76295571Sjkim *
77295571Sjkim ******************************************************************************/
78295571Sjkim
79295571Sjkimvoid
80295571SjkimExDoExternal (
81295571Sjkim    ACPI_PARSE_OBJECT       *Op)
82295571Sjkim{
83295571Sjkim    ACPI_PARSE_OBJECT       *ListOp;
84295571Sjkim    ACPI_PARSE_OBJECT       *Prev;
85295571Sjkim    ACPI_PARSE_OBJECT       *Next;
86295571Sjkim    ACPI_PARSE_OBJECT       *ArgCountOp;
87295571Sjkim
88295571Sjkim
89295571Sjkim    ArgCountOp = Op->Asl.Child->Asl.Next->Asl.Next;
90295571Sjkim    ArgCountOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
91295571Sjkim    ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST;
92295571Sjkim    ArgCountOp->Asl.Value.Integer = 0;
93295571Sjkim    UtSetParseOpName (ArgCountOp);
94295571Sjkim
95295571Sjkim    /* Create new list node of arbitrary type */
96295571Sjkim
97295571Sjkim    ListOp = TrAllocateNode (PARSEOP_DEFAULT_ARG);
98295571Sjkim
99295571Sjkim    /* Store External node as child */
100295571Sjkim
101295571Sjkim    ListOp->Asl.Child = Op;
102295571Sjkim    ListOp->Asl.Next = NULL;
103295571Sjkim
104295571Sjkim    if (Gbl_ExternalsListHead)
105295571Sjkim    {
106295571Sjkim        /* Link new External to end of list */
107295571Sjkim
108295571Sjkim        Prev = Gbl_ExternalsListHead;
109295571Sjkim        Next = Prev;
110295571Sjkim        while (Next)
111295571Sjkim        {
112295571Sjkim            Prev = Next;
113295571Sjkim            Next = Next->Asl.Next;
114295571Sjkim        }
115295571Sjkim
116295571Sjkim        Prev->Asl.Next = ListOp;
117295571Sjkim    }
118295571Sjkim    else
119295571Sjkim    {
120295571Sjkim        Gbl_ExternalsListHead = ListOp;
121295571Sjkim    }
122295571Sjkim}
123295571Sjkim
124295571Sjkim
125295571Sjkim/*******************************************************************************
126295571Sjkim *
127295571Sjkim * FUNCTION:    ExInsertArgCount
128295571Sjkim *
129295571Sjkim * PARAMETERS:  Op              - Op for a method invocation
130295571Sjkim *
131295571Sjkim * RETURN:      None
132295571Sjkim *
133295571Sjkim * DESCRIPTION: Obtain the number of arguments for a control method -- from
134295571Sjkim *              the actual invocation.
135295571Sjkim *
136295571Sjkim ******************************************************************************/
137295571Sjkim
138295571Sjkimstatic void
139295571SjkimExInsertArgCount (
140295571Sjkim    ACPI_PARSE_OBJECT       *Op)
141295571Sjkim{
142295571Sjkim    ACPI_PARSE_OBJECT       *Next;
143295571Sjkim    ACPI_PARSE_OBJECT       *NameOp;
144295571Sjkim    ACPI_PARSE_OBJECT       *Child;
145295571Sjkim    ACPI_PARSE_OBJECT       *ArgCountOp;
146295571Sjkim    char *                  ExternalName;
147295571Sjkim    char *                  CallName;
148295571Sjkim    UINT16                  ArgCount = 0;
149298714Sjkim    ACPI_STATUS             Status;
150295571Sjkim
151295571Sjkim
152295571Sjkim    CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
153295571Sjkim
154295571Sjkim    Next = Gbl_ExternalsListHead;
155295571Sjkim    while (Next)
156295571Sjkim    {
157295571Sjkim        ArgCount = 0;
158295571Sjkim
159295571Sjkim        /* Skip if External node already handled */
160295571Sjkim
161295571Sjkim        if (Next->Asl.Child->Asl.CompileFlags & NODE_VISITED)
162295571Sjkim        {
163295571Sjkim            Next = Next->Asl.Next;
164295571Sjkim            continue;
165295571Sjkim        }
166295571Sjkim
167295571Sjkim        NameOp = Next->Asl.Child->Asl.Child;
168295571Sjkim        ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE);
169295571Sjkim
170298714Sjkim        if (strcmp (CallName, ExternalName))
171295571Sjkim        {
172298714Sjkim            ACPI_FREE (ExternalName);
173298714Sjkim            Next = Next->Asl.Next;
174298714Sjkim            continue;
175298714Sjkim        }
176295571Sjkim
177298714Sjkim        Next->Asl.Child->Asl.CompileFlags |= NODE_VISITED;
178295571Sjkim
179298714Sjkim        /*
180298714Sjkim         * Since we will reposition Externals to the Root, set Namepath
181298714Sjkim         * to the fully qualified name and recalculate the aml length
182298714Sjkim         */
183298714Sjkim        Status = UtInternalizeName (ExternalName,
184298714Sjkim            &NameOp->Asl.Value.String);
185295571Sjkim
186298714Sjkim        ACPI_FREE (ExternalName);
187298714Sjkim        if (ACPI_FAILURE (Status))
188298714Sjkim        {
189298714Sjkim            AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
190298714Sjkim                NULL, "- Could not Internalize External");
191298714Sjkim            break;
192298714Sjkim        }
193295571Sjkim
194298714Sjkim        NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String);
195295571Sjkim
196298714Sjkim        /* Get argument count */
197295571Sjkim
198298714Sjkim        Child = Op->Asl.Child;
199298714Sjkim        while (Child)
200298714Sjkim        {
201298714Sjkim            ArgCount++;
202298714Sjkim            Child = Child->Asl.Next;
203295571Sjkim        }
204295571Sjkim
205298714Sjkim        /* Setup ArgCount operand */
206298714Sjkim
207298714Sjkim        ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next;
208298714Sjkim        ArgCountOp->Asl.Value.Integer = ArgCount;
209298714Sjkim        break;
210295571Sjkim    }
211298714Sjkim
212298714Sjkim    ACPI_FREE (CallName);
213295571Sjkim}
214295571Sjkim
215295571Sjkim
216295571Sjkim/*******************************************************************************
217295571Sjkim *
218295571Sjkim * FUNCTION:    ExAmlExternalWalkBegin
219295571Sjkim *
220295571Sjkim * PARAMETERS:  ASL_WALK_CALLBACK
221295571Sjkim *
222295571Sjkim * RETURN:      None
223295571Sjkim *
224295571Sjkim * DESCRIPTION: Parse tree walk to create external opcode list for methods.
225295571Sjkim *
226295571Sjkim ******************************************************************************/
227295571Sjkim
228295571SjkimACPI_STATUS
229295571SjkimExAmlExternalWalkBegin (
230295571Sjkim    ACPI_PARSE_OBJECT       *Op,
231295571Sjkim    UINT32                  Level,
232295571Sjkim    void                    *Context)
233295571Sjkim{
234295571Sjkim
235295571Sjkim    /* External list head saved in the definition block op */
236295571Sjkim
237295571Sjkim    if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
238295571Sjkim    {
239295571Sjkim        Gbl_ExternalsListHead = Op->Asl.Value.Arg;
240295571Sjkim    }
241295571Sjkim
242295571Sjkim    if (!Gbl_ExternalsListHead)
243295571Sjkim    {
244295571Sjkim        return (AE_OK);
245295571Sjkim    }
246295571Sjkim
247295571Sjkim    if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)
248295571Sjkim    {
249295571Sjkim        return (AE_OK);
250295571Sjkim    }
251295571Sjkim
252295571Sjkim    /*
253295571Sjkim     * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL
254295571Sjkim     * by XfNamespaceLocateBegin(). Ignore these.
255295571Sjkim     */
256295571Sjkim    if (Op->Asl.Parent &&
257295571Sjkim        Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL)
258295571Sjkim    {
259295571Sjkim        return (AE_OK);
260295571Sjkim    }
261295571Sjkim
262295571Sjkim    ExInsertArgCount (Op);
263295571Sjkim    return (AE_OK);
264295571Sjkim}
265295571Sjkim
266295571Sjkim
267295571Sjkim/*******************************************************************************
268295571Sjkim *
269295571Sjkim * FUNCTION:    ExAmlExternalWalkEnd
270295571Sjkim *
271295571Sjkim * PARAMETERS:  ASL_WALK_CALLBACK
272295571Sjkim *
273295571Sjkim * RETURN:      None
274295571Sjkim *
275295571Sjkim * DESCRIPTION: Parse tree walk to create external opcode list for methods.
276295571Sjkim *              Here, we just want to catch the case where a definition block
277295571Sjkim *              has been completed. Then we move all of the externals into
278295571Sjkim *              a single block in the parse tree and thus the AML code.
279295571Sjkim *
280295571Sjkim ******************************************************************************/
281295571Sjkim
282295571SjkimACPI_STATUS
283295571SjkimExAmlExternalWalkEnd (
284295571Sjkim    ACPI_PARSE_OBJECT       *Op,
285295571Sjkim    UINT32                  Level,
286295571Sjkim    void                    *Context)
287295571Sjkim{
288295571Sjkim
289295571Sjkim    if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
290295571Sjkim    {
291295571Sjkim        /*
292295571Sjkim         * Process any existing external list. (Support for
293295571Sjkim         * multiple definition blocks in a single file/compile)
294295571Sjkim         */
295295571Sjkim        ExMoveExternals (Op);
296295571Sjkim        Gbl_ExternalsListHead = NULL;
297295571Sjkim    }
298295571Sjkim
299295571Sjkim    return (AE_OK);
300295571Sjkim}
301295571Sjkim
302295571Sjkim
303295571Sjkim/*******************************************************************************
304295571Sjkim *
305295571Sjkim * FUNCTION:    ExMoveExternals
306295571Sjkim *
307295571Sjkim * PARAMETERS:  DefinitionBlockOp       - Op for current definition block
308295571Sjkim *
309295571Sjkim * RETURN:      None
310295571Sjkim *
311295571Sjkim * DESCRIPTION: Move all externals present in the source file into a single
312295571Sjkim *              block of AML code, surrounded by an "If (0)" to prevent
313295571Sjkim *              AML interpreters from attempting to execute the External
314295571Sjkim *              opcodes.
315295571Sjkim *
316295571Sjkim ******************************************************************************/
317295571Sjkim
318295571Sjkimstatic void
319295571SjkimExMoveExternals (
320295571Sjkim    ACPI_PARSE_OBJECT       *DefinitionBlockOp)
321295571Sjkim{
322295571Sjkim    ACPI_PARSE_OBJECT       *ParentOp;
323295571Sjkim    ACPI_PARSE_OBJECT       *ExternalOp;
324295571Sjkim    ACPI_PARSE_OBJECT       *PredicateOp;
325295571Sjkim    ACPI_PARSE_OBJECT       *NextOp;
326295571Sjkim    ACPI_PARSE_OBJECT       *Prev;
327295571Sjkim    ACPI_PARSE_OBJECT       *Next;
328295571Sjkim    ACPI_OBJECT_TYPE        ObjType;
329295571Sjkim    UINT32                  i;
330295571Sjkim
331295571Sjkim
332295571Sjkim    if (!Gbl_ExternalsListHead)
333295571Sjkim    {
334295571Sjkim        return;
335295571Sjkim    }
336295571Sjkim
337295571Sjkim    /* Remove the External nodes from the tree */
338295571Sjkim
339295571Sjkim    NextOp = Gbl_ExternalsListHead;
340295571Sjkim    while (NextOp)
341295571Sjkim    {
342295571Sjkim        /*
343295571Sjkim         * The External is stored in child pointer of each node in the
344295571Sjkim         * list
345295571Sjkim         */
346295571Sjkim        ExternalOp = NextOp->Asl.Child;
347295571Sjkim
348295571Sjkim        /* Set line numbers (for listings, etc.) */
349295571Sjkim
350295571Sjkim        ExternalOp->Asl.LineNumber = 0;
351295571Sjkim        ExternalOp->Asl.LogicalLineNumber = 0;
352295571Sjkim
353295571Sjkim        Next = ExternalOp->Asl.Child;
354295571Sjkim        Next->Asl.LineNumber = 0;
355295571Sjkim        Next->Asl.LogicalLineNumber = 0;
356295571Sjkim
357295571Sjkim        Next = Next->Asl.Next;
358295571Sjkim        Next->Asl.LineNumber = 0;
359295571Sjkim        Next->Asl.LogicalLineNumber = 0;
360295571Sjkim
361295571Sjkim        Next = Next->Asl.Next;
362295571Sjkim        Next->Asl.LineNumber = 0;
363295571Sjkim        Next->Asl.LogicalLineNumber = 0;
364295571Sjkim
365295571Sjkim        Next = Next->Asl.Next;
366295571Sjkim        Next->Asl.LineNumber = 0;
367295571Sjkim        Next->Asl.LogicalLineNumber = 0;
368295571Sjkim
369295571Sjkim        ParentOp = ExternalOp->Asl.Parent;
370295571Sjkim        Prev = Next = ParentOp->Asl.Child;
371295571Sjkim
372295571Sjkim        /* Now find the External node's position in parse tree */
373295571Sjkim
374295571Sjkim        while (Next != ExternalOp)
375295571Sjkim        {
376295571Sjkim            Prev = Next;
377295571Sjkim            Next = Next->Asl.Next;
378295571Sjkim        }
379295571Sjkim
380295571Sjkim        /* Remove the External from the parse tree */
381295571Sjkim
382295571Sjkim        if (Prev == ExternalOp)
383295571Sjkim        {
384295571Sjkim            /* External was the first child node */
385295571Sjkim
386295571Sjkim            ParentOp->Asl.Child = ExternalOp->Asl.Next;
387295571Sjkim        }
388295571Sjkim
389295571Sjkim        Prev->Asl.Next = ExternalOp->Asl.Next;
390295571Sjkim        ExternalOp->Asl.Next = NULL;
391295571Sjkim        ExternalOp->Asl.Parent = Gbl_ExternalsListHead;
392295571Sjkim
393295571Sjkim        /* Point the External to the next in the list */
394295571Sjkim
395295571Sjkim        if (NextOp->Asl.Next)
396295571Sjkim        {
397295571Sjkim            ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
398295571Sjkim        }
399295571Sjkim
400295571Sjkim        NextOp = NextOp->Asl.Next;
401295571Sjkim    }
402295571Sjkim
403295571Sjkim    /*
404295571Sjkim     * Loop again to remove MethodObj Externals for which
405295571Sjkim     * a MethodCall was not found (dead external reference)
406295571Sjkim     */
407295571Sjkim    Prev = Gbl_ExternalsListHead->Asl.Child;
408295571Sjkim    Next = Prev;
409295571Sjkim    while (Next)
410295571Sjkim    {
411295571Sjkim        ObjType = (ACPI_OBJECT_TYPE)
412295571Sjkim            Next->Asl.Child->Asl.Next->Asl.Value.Integer;
413295571Sjkim
414295571Sjkim        if (ObjType == ACPI_TYPE_METHOD &&
415295571Sjkim            !(Next->Asl.CompileFlags & NODE_VISITED))
416295571Sjkim        {
417295571Sjkim            if (Next == Prev)
418295571Sjkim            {
419295571Sjkim                Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
420295571Sjkim                Next->Asl.Next = NULL;
421295571Sjkim                Prev = Gbl_ExternalsListHead->Asl.Child;
422295571Sjkim                Next = Prev;
423295571Sjkim                continue;
424295571Sjkim            }
425295571Sjkim            else
426295571Sjkim            {
427295571Sjkim                Prev->Asl.Next = Next->Asl.Next;
428295571Sjkim                Next->Asl.Next = NULL;
429295571Sjkim                Next = Prev->Asl.Next;
430295571Sjkim                continue;
431295571Sjkim            }
432295571Sjkim        }
433295571Sjkim
434295571Sjkim        Prev = Next;
435295571Sjkim        Next = Next->Asl.Next;
436295571Sjkim    }
437295571Sjkim
438295571Sjkim    /* If list is now empty, don't bother to make If (0) block */
439295571Sjkim
440295571Sjkim    if (!Gbl_ExternalsListHead->Asl.Child)
441295571Sjkim    {
442295571Sjkim        return;
443295571Sjkim    }
444295571Sjkim
445295571Sjkim    /* Convert Gbl_ExternalsListHead parent to If(). */
446295571Sjkim
447295571Sjkim    Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
448295571Sjkim    Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
449295571Sjkim    Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE;
450295571Sjkim    UtSetParseOpName (Gbl_ExternalsListHead);
451295571Sjkim
452295571Sjkim    /* Create a Zero op for the If predicate */
453295571Sjkim
454295571Sjkim    PredicateOp = TrAllocateNode (PARSEOP_ZERO);
455295571Sjkim    PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
456295571Sjkim
457295571Sjkim    PredicateOp->Asl.Parent = Gbl_ExternalsListHead;
458295571Sjkim    PredicateOp->Asl.Child = NULL;
459295571Sjkim    PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child;
460295571Sjkim    Gbl_ExternalsListHead->Asl.Child = PredicateOp;
461295571Sjkim
462295571Sjkim    /* Set line numbers (for listings, etc.) */
463295571Sjkim
464295571Sjkim    Gbl_ExternalsListHead->Asl.LineNumber = 0;
465295571Sjkim    Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
466295571Sjkim
467295571Sjkim    PredicateOp->Asl.LineNumber = 0;
468295571Sjkim    PredicateOp->Asl.LogicalLineNumber = 0;
469295571Sjkim
470295571Sjkim    /* Insert block back in the list */
471295571Sjkim
472295571Sjkim    Prev = DefinitionBlockOp->Asl.Child;
473295571Sjkim    Next = Prev;
474295571Sjkim
475295571Sjkim    /* Find last default arg */
476295571Sjkim
477295571Sjkim    for (i = 0; i < 6; i++)
478295571Sjkim    {
479295571Sjkim        Prev = Next;
480295571Sjkim        Next = Prev->Asl.Next;
481295571Sjkim    }
482295571Sjkim
483295571Sjkim    if (Next)
484295571Sjkim    {
485295571Sjkim        /* Definition Block is not empty */
486295571Sjkim
487295571Sjkim        Gbl_ExternalsListHead->Asl.Next = Next;
488295571Sjkim    }
489295571Sjkim    else
490295571Sjkim    {
491295571Sjkim        /* Definition Block is empty. */
492295571Sjkim
493295571Sjkim        Gbl_ExternalsListHead->Asl.Next = NULL;
494295571Sjkim    }
495295571Sjkim
496295571Sjkim    Prev->Asl.Next = Gbl_ExternalsListHead;
497295571Sjkim    Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
498295571Sjkim}
499