1118611Snjl/******************************************************************************
2118611Snjl *
3118611Snjl * Module Name: asllength - Tree walk to determine package and opcode lengths
4118611Snjl *
5118611Snjl *****************************************************************************/
6118611Snjl
7217365Sjkim/*
8245582Sjkim * Copyright (C) 2000 - 2013, 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
44118611Snjl
45151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
46118611Snjl#include "aslcompiler.y.h"
47193529Sjkim#include <contrib/dev/acpica/include/amlcode.h>
48118611Snjl
49118611Snjl
50118611Snjl#define _COMPONENT          ACPI_COMPILER
51118611Snjl        ACPI_MODULE_NAME    ("asllength")
52118611Snjl
53151937Sjkim/* Local prototypes */
54118611Snjl
55151937Sjkimstatic UINT8
56151937SjkimCgGetPackageLenByteCount (
57151937Sjkim    ACPI_PARSE_OBJECT       *Op,
58151937Sjkim    UINT32                  PackageLength);
59151937Sjkim
60151937Sjkimstatic void
61151937SjkimCgGenerateAmlOpcodeLength (
62151937Sjkim    ACPI_PARSE_OBJECT       *Op);
63151937Sjkim
64151937Sjkim
65151937Sjkim#ifdef ACPI_OBSOLETE_FUNCTIONS
66151937Sjkimvoid
67151937SjkimLnAdjustLengthToRoot (
68151937Sjkim    ACPI_PARSE_OBJECT       *Op,
69151937Sjkim    UINT32                  LengthDelta);
70151937Sjkim#endif
71151937Sjkim
72151937Sjkim
73118611Snjl/*******************************************************************************
74118611Snjl *
75118611Snjl * FUNCTION:    LnInitLengthsWalk
76118611Snjl *
77118611Snjl * PARAMETERS:  ASL_WALK_CALLBACK
78118611Snjl *
79118611Snjl * RETURN:      Status
80118611Snjl *
81118611Snjl * DESCRIPTION: Walk callback to initialize (and re-initialize) the node
82241973Sjkim *              subtree length(s) to zero. The Subtree lengths are bubbled
83118611Snjl *              up to the root node in order to get a total AML length.
84118611Snjl *
85118611Snjl ******************************************************************************/
86118611Snjl
87118611SnjlACPI_STATUS
88118611SnjlLnInitLengthsWalk (
89118611Snjl    ACPI_PARSE_OBJECT       *Op,
90118611Snjl    UINT32                  Level,
91118611Snjl    void                    *Context)
92118611Snjl{
93118611Snjl
94118611Snjl    Op->Asl.AmlSubtreeLength = 0;
95118611Snjl    return (AE_OK);
96118611Snjl}
97118611Snjl
98118611Snjl
99118611Snjl/*******************************************************************************
100118611Snjl *
101118611Snjl * FUNCTION:    LnPackageLengthWalk
102118611Snjl *
103118611Snjl * PARAMETERS:  ASL_WALK_CALLBACK
104118611Snjl *
105118611Snjl * RETURN:      Status
106118611Snjl *
107118611Snjl * DESCRIPTION: Walk callback to calculate the total AML length.
108118611Snjl *              1) Calculate the AML lengths (opcode, package length, etc.) for
109118611Snjl *                 THIS node.
110118611Snjl *              2) Bubbble up all of these lengths to the parent node by summing
111118611Snjl *                 them all into the parent subtree length.
112118611Snjl *
113118611Snjl * Note:  The SubtreeLength represents the total AML length of all child nodes
114241973Sjkim *        in all subtrees under a given node. Therefore, once this walk is
115118611Snjl *        complete, the Root Node subtree length is the AML length of the entire
116118611Snjl *        tree (and thus, the entire ACPI table)
117118611Snjl *
118118611Snjl ******************************************************************************/
119118611Snjl
120118611SnjlACPI_STATUS
121118611SnjlLnPackageLengthWalk (
122118611Snjl    ACPI_PARSE_OBJECT       *Op,
123118611Snjl    UINT32                  Level,
124118611Snjl    void                    *Context)
125118611Snjl{
126118611Snjl
127118611Snjl    /* Generate the AML lengths for this node */
128118611Snjl
129118611Snjl    CgGenerateAmlLengths (Op);
130118611Snjl
131118611Snjl    /* Bubble up all lengths (this node and all below it) to the parent */
132118611Snjl
133118611Snjl    if ((Op->Asl.Parent) &&
134118611Snjl        (Op->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
135118611Snjl    {
136118611Snjl        Op->Asl.Parent->Asl.AmlSubtreeLength += (Op->Asl.AmlLength +
137118611Snjl                                           Op->Asl.AmlOpcodeLength +
138118611Snjl                                           Op->Asl.AmlPkgLenBytes +
139118611Snjl                                           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 (
233151937Sjkim                                    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    {
336118611Snjl    case PARSEOP_DEFINITIONBLOCK:
337118611Snjl
338151937Sjkim        Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) +
339151937Sjkim                            Op->Asl.AmlSubtreeLength;
340118611Snjl        break;
341118611Snjl
342118611Snjl    case PARSEOP_NAMESEG:
343118611Snjl
344118611Snjl        Op->Asl.AmlOpcodeLength = 0;
345118611Snjl        Op->Asl.AmlLength = 4;
346118611Snjl        Op->Asl.ExternalName = Op->Asl.Value.String;
347118611Snjl        break;
348118611Snjl
349118611Snjl    case PARSEOP_NAMESTRING:
350118611Snjl    case PARSEOP_METHODCALL:
351118611Snjl
352118611Snjl        if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED)
353118611Snjl        {
354118611Snjl            break;
355118611Snjl        }
356118611Snjl
357118611Snjl        Op->Asl.AmlOpcodeLength = 0;
358118611Snjl        Status = UtInternalizeName (Op->Asl.Value.String, &Buffer);
359118611Snjl        if (ACPI_FAILURE (Status))
360118611Snjl        {
361118611Snjl            DbgPrint (ASL_DEBUG_OUTPUT,
362118611Snjl                "Failure from internalize name %X\n", Status);
363118611Snjl            break;
364118611Snjl        }
365118611Snjl
366118611Snjl        Op->Asl.ExternalName = Op->Asl.Value.String;
367118611Snjl        Op->Asl.Value.String = Buffer;
368118611Snjl        Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED;
369118611Snjl
370118611Snjl        Op->Asl.AmlLength = strlen (Buffer);
371118611Snjl
372118611Snjl        /*
373118611Snjl         * Check for single backslash reference to root,
374118611Snjl         * make it a null terminated string in the AML
375118611Snjl         */
376118611Snjl        if (Op->Asl.AmlLength == 1)
377118611Snjl        {
378118611Snjl            Op->Asl.AmlLength = 2;
379118611Snjl        }
380118611Snjl        break;
381118611Snjl
382118611Snjl    case PARSEOP_STRING_LITERAL:
383118611Snjl
384118611Snjl        Op->Asl.AmlOpcodeLength = 1;
385151937Sjkim
386151937Sjkim        /* Get null terminator */
387151937Sjkim
388151937Sjkim        Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1;
389118611Snjl        break;
390118611Snjl
391118611Snjl    case PARSEOP_PACKAGE_LENGTH:
392118611Snjl
393118611Snjl        Op->Asl.AmlOpcodeLength = 0;
394151937Sjkim        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op,
395151937Sjkim                                    (UINT32) Op->Asl.Value.Integer);
396118611Snjl        break;
397118611Snjl
398118611Snjl    case PARSEOP_RAW_DATA:
399118611Snjl
400118611Snjl        Op->Asl.AmlOpcodeLength = 0;
401118611Snjl        break;
402118611Snjl
403118611Snjl    case PARSEOP_DEFAULT_ARG:
404118611Snjl    case PARSEOP_EXTERNAL:
405118611Snjl    case PARSEOP_INCLUDE:
406118611Snjl    case PARSEOP_INCLUDE_END:
407118611Snjl
408118611Snjl        /* Ignore the "default arg" nodes, they are extraneous at this point */
409118611Snjl
410118611Snjl        break;
411118611Snjl
412118611Snjl    default:
413118611Snjl
414118611Snjl        CgGenerateAmlOpcodeLength (Op);
415118611Snjl        break;
416118611Snjl    }
417118611Snjl}
418118611Snjl
419118611Snjl
420151937Sjkim#ifdef ACPI_OBSOLETE_FUNCTIONS
421151937Sjkim/*******************************************************************************
422151937Sjkim *
423151937Sjkim * FUNCTION:    LnAdjustLengthToRoot
424151937Sjkim *
425151937Sjkim * PARAMETERS:  Op      - Node whose Length was changed
426151937Sjkim *
427151937Sjkim * RETURN:      None.
428151937Sjkim *
429151937Sjkim * DESCRIPTION: Change the Subtree length of the given node, and bubble the
430241973Sjkim *              change all the way up to the root node. This allows for
431151937Sjkim *              last second changes to a package length (for example, if the
432151937Sjkim *              package length encoding gets shorter or longer.)
433151937Sjkim *
434151937Sjkim ******************************************************************************/
435151937Sjkim
436151937Sjkimvoid
437151937SjkimLnAdjustLengthToRoot (
438151937Sjkim    ACPI_PARSE_OBJECT       *SubtreeOp,
439151937Sjkim    UINT32                  LengthDelta)
440151937Sjkim{
441151937Sjkim    ACPI_PARSE_OBJECT       *Op;
442151937Sjkim
443151937Sjkim
444151937Sjkim    /* Adjust all subtree lengths up to the root */
445151937Sjkim
446151937Sjkim    Op = SubtreeOp->Asl.Parent;
447151937Sjkim    while (Op)
448151937Sjkim    {
449151937Sjkim        Op->Asl.AmlSubtreeLength -= LengthDelta;
450151937Sjkim        Op = Op->Asl.Parent;
451151937Sjkim    }
452151937Sjkim
453151937Sjkim    /* Adjust the global table length */
454151937Sjkim
455151937Sjkim    Gbl_TableLength -= LengthDelta;
456151937Sjkim}
457151937Sjkim#endif
458