1118611Snjl/******************************************************************************
2118611Snjl *
3118611Snjl * Module Name: asllength - Tree walk to determine package and opcode lengths
4118611Snjl *
5118611Snjl *****************************************************************************/
6118611Snjl
7217365Sjkim/*
8298714Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
9118611Snjl * All rights reserved.
10118611Snjl *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
25118611Snjl *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
29118611Snjl *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
43118611Snjl
44151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
45118611Snjl#include "aslcompiler.y.h"
46193529Sjkim#include <contrib/dev/acpica/include/amlcode.h>
47118611Snjl
48118611Snjl
49118611Snjl#define _COMPONENT          ACPI_COMPILER
50118611Snjl        ACPI_MODULE_NAME    ("asllength")
51118611Snjl
52151937Sjkim/* Local prototypes */
53118611Snjl
54151937Sjkimstatic UINT8
55151937SjkimCgGetPackageLenByteCount (
56151937Sjkim    ACPI_PARSE_OBJECT       *Op,
57151937Sjkim    UINT32                  PackageLength);
58151937Sjkim
59151937Sjkimstatic void
60151937SjkimCgGenerateAmlOpcodeLength (
61151937Sjkim    ACPI_PARSE_OBJECT       *Op);
62151937Sjkim
63151937Sjkim
64151937Sjkim#ifdef ACPI_OBSOLETE_FUNCTIONS
65151937Sjkimvoid
66151937SjkimLnAdjustLengthToRoot (
67151937Sjkim    ACPI_PARSE_OBJECT       *Op,
68151937Sjkim    UINT32                  LengthDelta);
69151937Sjkim#endif
70151937Sjkim
71151937Sjkim
72118611Snjl/*******************************************************************************
73118611Snjl *
74118611Snjl * FUNCTION:    LnInitLengthsWalk
75118611Snjl *
76118611Snjl * PARAMETERS:  ASL_WALK_CALLBACK
77118611Snjl *
78118611Snjl * RETURN:      Status
79118611Snjl *
80118611Snjl * DESCRIPTION: Walk callback to initialize (and re-initialize) the node
81241973Sjkim *              subtree length(s) to zero. The Subtree lengths are bubbled
82118611Snjl *              up to the root node in order to get a total AML length.
83118611Snjl *
84118611Snjl ******************************************************************************/
85118611Snjl
86118611SnjlACPI_STATUS
87118611SnjlLnInitLengthsWalk (
88118611Snjl    ACPI_PARSE_OBJECT       *Op,
89118611Snjl    UINT32                  Level,
90118611Snjl    void                    *Context)
91118611Snjl{
92118611Snjl
93118611Snjl    Op->Asl.AmlSubtreeLength = 0;
94118611Snjl    return (AE_OK);
95118611Snjl}
96118611Snjl
97118611Snjl
98118611Snjl/*******************************************************************************
99118611Snjl *
100118611Snjl * FUNCTION:    LnPackageLengthWalk
101118611Snjl *
102118611Snjl * PARAMETERS:  ASL_WALK_CALLBACK
103118611Snjl *
104118611Snjl * RETURN:      Status
105118611Snjl *
106118611Snjl * DESCRIPTION: Walk callback to calculate the total AML length.
107118611Snjl *              1) Calculate the AML lengths (opcode, package length, etc.) for
108118611Snjl *                 THIS node.
109118611Snjl *              2) Bubbble up all of these lengths to the parent node by summing
110118611Snjl *                 them all into the parent subtree length.
111118611Snjl *
112118611Snjl * Note:  The SubtreeLength represents the total AML length of all child nodes
113241973Sjkim *        in all subtrees under a given node. Therefore, once this walk is
114118611Snjl *        complete, the Root Node subtree length is the AML length of the entire
115118611Snjl *        tree (and thus, the entire ACPI table)
116118611Snjl *
117118611Snjl ******************************************************************************/
118118611Snjl
119118611SnjlACPI_STATUS
120118611SnjlLnPackageLengthWalk (
121118611Snjl    ACPI_PARSE_OBJECT       *Op,
122118611Snjl    UINT32                  Level,
123118611Snjl    void                    *Context)
124118611Snjl{
125118611Snjl
126118611Snjl    /* Generate the AML lengths for this node */
127118611Snjl
128118611Snjl    CgGenerateAmlLengths (Op);
129118611Snjl
130118611Snjl    /* Bubble up all lengths (this node and all below it) to the parent */
131118611Snjl
132118611Snjl    if ((Op->Asl.Parent) &&
133118611Snjl        (Op->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
134118611Snjl    {
135298714Sjkim        Op->Asl.Parent->Asl.AmlSubtreeLength += (
136298714Sjkim            Op->Asl.AmlLength +
137298714Sjkim            Op->Asl.AmlOpcodeLength +
138298714Sjkim            Op->Asl.AmlPkgLenBytes +
139298714Sjkim            Op->Asl.AmlSubtreeLength);
140118611Snjl    }
141118611Snjl    return (AE_OK);
142118611Snjl}
143118611Snjl
144118611Snjl
145118611Snjl/*******************************************************************************
146118611Snjl *
147118611Snjl * FUNCTION:    CgGetPackageLenByteCount
148118611Snjl *
149151937Sjkim * PARAMETERS:  Op              - Parse node
150118611Snjl *              PackageLength   - Length to be encoded
151118611Snjl *
152118611Snjl * RETURN:      Required length of the package length encoding
153118611Snjl *
154118611Snjl * DESCRIPTION: Calculate the number of bytes required to encode the given
155118611Snjl *              package length.
156118611Snjl *
157118611Snjl ******************************************************************************/
158118611Snjl
159151937Sjkimstatic UINT8
160118611SnjlCgGetPackageLenByteCount (
161118611Snjl    ACPI_PARSE_OBJECT       *Op,
162118611Snjl    UINT32                  PackageLength)
163118611Snjl{
164118611Snjl
165118611Snjl    /*
166118611Snjl     * Determine the number of bytes required to encode the package length
167118611Snjl     * Note: the package length includes the number of bytes used to encode
168118611Snjl     * the package length, so we must account for this also.
169118611Snjl     */
170118611Snjl    if (PackageLength <= (0x0000003F - 1))
171118611Snjl    {
172118611Snjl        return (1);
173118611Snjl    }
174118611Snjl    else if (PackageLength <= (0x00000FFF - 2))
175118611Snjl    {
176118611Snjl        return (2);
177118611Snjl    }
178118611Snjl    else if (PackageLength <= (0x000FFFFF - 3))
179118611Snjl    {
180118611Snjl        return (3);
181118611Snjl    }
182118611Snjl    else if (PackageLength <= (0x0FFFFFFF - 4))
183118611Snjl    {
184118611Snjl        return (4);
185118611Snjl    }
186118611Snjl    else
187118611Snjl    {
188118611Snjl        /* Fatal error - the package length is too large to encode */
189118611Snjl
190118611Snjl        AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, Op, NULL);
191118611Snjl    }
192118611Snjl
193118611Snjl    return (0);
194118611Snjl}
195118611Snjl
196118611Snjl
197118611Snjl/*******************************************************************************
198118611Snjl *
199118611Snjl * FUNCTION:    CgGenerateAmlOpcodeLength
200118611Snjl *
201151937Sjkim * PARAMETERS:  Op          - Parse node whose AML opcode lengths will be
202118611Snjl *                            calculated
203118611Snjl *
204118611Snjl * RETURN:      None.
205118611Snjl *
206118611Snjl * DESCRIPTION: Calculate the AmlOpcodeLength, AmlPkgLenBytes, and AmlLength
207118611Snjl *              fields for this node.
208118611Snjl *
209118611Snjl ******************************************************************************/
210118611Snjl
211151937Sjkimstatic void
212118611SnjlCgGenerateAmlOpcodeLength (
213118611Snjl    ACPI_PARSE_OBJECT       *Op)
214118611Snjl{
215118611Snjl
216118611Snjl    /* Check for two-byte opcode */
217118611Snjl
218118611Snjl    if (Op->Asl.AmlOpcode > 0x00FF)
219118611Snjl    {
220118611Snjl        Op->Asl.AmlOpcodeLength = 2;
221118611Snjl    }
222118611Snjl    else
223118611Snjl    {
224118611Snjl        Op->Asl.AmlOpcodeLength = 1;
225118611Snjl    }
226118611Snjl
227118611Snjl    /* Does this opcode have an associated "PackageLength" field? */
228118611Snjl
229118611Snjl    Op->Asl.AmlPkgLenBytes = 0;
230118611Snjl    if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
231118611Snjl    {
232151937Sjkim        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (
233298714Sjkim            Op, Op->Asl.AmlSubtreeLength);
234118611Snjl    }
235118611Snjl
236118611Snjl    /* Data opcode lengths are easy */
237118611Snjl
238118611Snjl    switch (Op->Asl.AmlOpcode)
239118611Snjl    {
240118611Snjl    case AML_BYTE_OP:
241118611Snjl
242118611Snjl        Op->Asl.AmlLength = 1;
243118611Snjl        break;
244118611Snjl
245118611Snjl    case AML_WORD_OP:
246118611Snjl
247118611Snjl        Op->Asl.AmlLength = 2;
248118611Snjl        break;
249118611Snjl
250118611Snjl    case AML_DWORD_OP:
251118611Snjl
252118611Snjl        Op->Asl.AmlLength = 4;
253118611Snjl        break;
254118611Snjl
255118611Snjl    case AML_QWORD_OP:
256118611Snjl
257118611Snjl        Op->Asl.AmlLength = 8;
258118611Snjl        break;
259118611Snjl
260118611Snjl    default:
261250838Sjkim
262118611Snjl        /* All data opcodes must be above */
263118611Snjl        break;
264118611Snjl    }
265118611Snjl}
266118611Snjl
267118611Snjl
268118611Snjl/*******************************************************************************
269118611Snjl *
270118611Snjl * FUNCTION:    CgGenerateAmlLengths
271118611Snjl *
272118611Snjl * PARAMETERS:  Op        - Parse node
273118611Snjl *
274118611Snjl * RETURN:      None.
275118611Snjl *
276118611Snjl * DESCRIPTION: Generate internal length fields based on the AML opcode or
277118611Snjl *              parse opcode.
278118611Snjl *
279118611Snjl ******************************************************************************/
280118611Snjl
281118611Snjlvoid
282118611SnjlCgGenerateAmlLengths (
283118611Snjl    ACPI_PARSE_OBJECT       *Op)
284118611Snjl{
285118611Snjl    char                    *Buffer;
286118611Snjl    ACPI_STATUS             Status;
287118611Snjl
288118611Snjl
289118611Snjl    switch (Op->Asl.AmlOpcode)
290118611Snjl    {
291118611Snjl    case AML_RAW_DATA_BYTE:
292118611Snjl
293118611Snjl        Op->Asl.AmlOpcodeLength = 0;
294118611Snjl        Op->Asl.AmlLength = 1;
295118611Snjl        return;
296118611Snjl
297118611Snjl    case AML_RAW_DATA_WORD:
298118611Snjl
299118611Snjl        Op->Asl.AmlOpcodeLength = 0;
300118611Snjl        Op->Asl.AmlLength = 2;
301118611Snjl        return;
302118611Snjl
303118611Snjl    case AML_RAW_DATA_DWORD:
304118611Snjl
305118611Snjl        Op->Asl.AmlOpcodeLength = 0;
306118611Snjl        Op->Asl.AmlLength = 4;
307118611Snjl        return;
308118611Snjl
309118611Snjl    case AML_RAW_DATA_QWORD:
310118611Snjl
311118611Snjl        Op->Asl.AmlOpcodeLength = 0;
312118611Snjl        Op->Asl.AmlLength = 8;
313118611Snjl        return;
314118611Snjl
315118611Snjl    case AML_RAW_DATA_BUFFER:
316118611Snjl
317118611Snjl        /* Aml length is/was set by creator */
318118611Snjl
319118611Snjl        Op->Asl.AmlOpcodeLength = 0;
320118611Snjl        return;
321118611Snjl
322118611Snjl    case AML_RAW_DATA_CHAIN:
323118611Snjl
324118611Snjl        /* Aml length is/was set by creator */
325118611Snjl
326118611Snjl        Op->Asl.AmlOpcodeLength = 0;
327118611Snjl        return;
328118611Snjl
329118611Snjl    default:
330250838Sjkim
331118611Snjl        break;
332118611Snjl    }
333118611Snjl
334118611Snjl    switch (Op->Asl.ParseOpcode)
335118611Snjl    {
336298714Sjkim    case PARSEOP_DEFINITION_BLOCK:
337118611Snjl
338298714Sjkim        Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
339118611Snjl        break;
340118611Snjl
341118611Snjl    case PARSEOP_NAMESEG:
342118611Snjl
343118611Snjl        Op->Asl.AmlOpcodeLength = 0;
344118611Snjl        Op->Asl.AmlLength = 4;
345118611Snjl        Op->Asl.ExternalName = Op->Asl.Value.String;
346118611Snjl        break;
347118611Snjl
348118611Snjl    case PARSEOP_NAMESTRING:
349118611Snjl    case PARSEOP_METHODCALL:
350118611Snjl
351118611Snjl        if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED)
352118611Snjl        {
353118611Snjl            break;
354118611Snjl        }
355118611Snjl
356118611Snjl        Op->Asl.AmlOpcodeLength = 0;
357118611Snjl        Status = UtInternalizeName (Op->Asl.Value.String, &Buffer);
358118611Snjl        if (ACPI_FAILURE (Status))
359118611Snjl        {
360118611Snjl            DbgPrint (ASL_DEBUG_OUTPUT,
361118611Snjl                "Failure from internalize name %X\n", Status);
362118611Snjl            break;
363118611Snjl        }
364118611Snjl
365118611Snjl        Op->Asl.ExternalName = Op->Asl.Value.String;
366118611Snjl        Op->Asl.Value.String = Buffer;
367118611Snjl        Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED;
368118611Snjl        Op->Asl.AmlLength = strlen (Buffer);
369118611Snjl
370118611Snjl        /*
371118611Snjl         * Check for single backslash reference to root,
372118611Snjl         * make it a null terminated string in the AML
373118611Snjl         */
374118611Snjl        if (Op->Asl.AmlLength == 1)
375118611Snjl        {
376118611Snjl            Op->Asl.AmlLength = 2;
377118611Snjl        }
378118611Snjl        break;
379118611Snjl
380118611Snjl    case PARSEOP_STRING_LITERAL:
381118611Snjl
382118611Snjl        Op->Asl.AmlOpcodeLength = 1;
383151937Sjkim
384151937Sjkim        /* Get null terminator */
385151937Sjkim
386151937Sjkim        Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1;
387118611Snjl        break;
388118611Snjl
389118611Snjl    case PARSEOP_PACKAGE_LENGTH:
390118611Snjl
391118611Snjl        Op->Asl.AmlOpcodeLength = 0;
392151937Sjkim        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op,
393298714Sjkim            (UINT32) Op->Asl.Value.Integer);
394118611Snjl        break;
395118611Snjl
396118611Snjl    case PARSEOP_RAW_DATA:
397118611Snjl
398118611Snjl        Op->Asl.AmlOpcodeLength = 0;
399118611Snjl        break;
400118611Snjl
401118611Snjl    case PARSEOP_DEFAULT_ARG:
402118611Snjl    case PARSEOP_INCLUDE:
403118611Snjl    case PARSEOP_INCLUDE_END:
404118611Snjl
405118611Snjl        /* Ignore the "default arg" nodes, they are extraneous at this point */
406118611Snjl
407118611Snjl        break;
408118611Snjl
409298714Sjkim    case PARSEOP_EXTERNAL:
410298714Sjkim
411298714Sjkim        if (Gbl_DoExternals == TRUE)
412298714Sjkim        {
413298714Sjkim            CgGenerateAmlOpcodeLength (Op);
414298714Sjkim        }
415298714Sjkim        break;
416298714Sjkim
417118611Snjl    default:
418118611Snjl
419118611Snjl        CgGenerateAmlOpcodeLength (Op);
420118611Snjl        break;
421118611Snjl    }
422118611Snjl}
423118611Snjl
424118611Snjl
425151937Sjkim#ifdef ACPI_OBSOLETE_FUNCTIONS
426151937Sjkim/*******************************************************************************
427151937Sjkim *
428151937Sjkim * FUNCTION:    LnAdjustLengthToRoot
429151937Sjkim *
430151937Sjkim * PARAMETERS:  Op      - Node whose Length was changed
431151937Sjkim *
432151937Sjkim * RETURN:      None.
433151937Sjkim *
434151937Sjkim * DESCRIPTION: Change the Subtree length of the given node, and bubble the
435241973Sjkim *              change all the way up to the root node. This allows for
436151937Sjkim *              last second changes to a package length (for example, if the
437151937Sjkim *              package length encoding gets shorter or longer.)
438151937Sjkim *
439151937Sjkim ******************************************************************************/
440151937Sjkim
441151937Sjkimvoid
442151937SjkimLnAdjustLengthToRoot (
443151937Sjkim    ACPI_PARSE_OBJECT       *SubtreeOp,
444151937Sjkim    UINT32                  LengthDelta)
445151937Sjkim{
446151937Sjkim    ACPI_PARSE_OBJECT       *Op;
447151937Sjkim
448151937Sjkim
449151937Sjkim    /* Adjust all subtree lengths up to the root */
450151937Sjkim
451151937Sjkim    Op = SubtreeOp->Asl.Parent;
452151937Sjkim    while (Op)
453151937Sjkim    {
454151937Sjkim        Op->Asl.AmlSubtreeLength -= LengthDelta;
455151937Sjkim        Op = Op->Asl.Parent;
456151937Sjkim    }
457151937Sjkim
458151937Sjkim    /* Adjust the global table length */
459151937Sjkim
460151937Sjkim    Gbl_TableLength -= LengthDelta;
461151937Sjkim}
462151937Sjkim#endif
463