asllength.c revision 306536
1/******************************************************************************
2 *
3 * Module Name: asllength - Tree walk to determine package and opcode lengths
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/amlcode.h>
47
48
49#define _COMPONENT          ACPI_COMPILER
50        ACPI_MODULE_NAME    ("asllength")
51
52/* Local prototypes */
53
54static UINT8
55CgGetPackageLenByteCount (
56    ACPI_PARSE_OBJECT       *Op,
57    UINT32                  PackageLength);
58
59static void
60CgGenerateAmlOpcodeLength (
61    ACPI_PARSE_OBJECT       *Op);
62
63
64#ifdef ACPI_OBSOLETE_FUNCTIONS
65void
66LnAdjustLengthToRoot (
67    ACPI_PARSE_OBJECT       *Op,
68    UINT32                  LengthDelta);
69#endif
70
71
72/*******************************************************************************
73 *
74 * FUNCTION:    LnInitLengthsWalk
75 *
76 * PARAMETERS:  ASL_WALK_CALLBACK
77 *
78 * RETURN:      Status
79 *
80 * DESCRIPTION: Walk callback to initialize (and re-initialize) the node
81 *              subtree length(s) to zero. The Subtree lengths are bubbled
82 *              up to the root node in order to get a total AML length.
83 *
84 ******************************************************************************/
85
86ACPI_STATUS
87LnInitLengthsWalk (
88    ACPI_PARSE_OBJECT       *Op,
89    UINT32                  Level,
90    void                    *Context)
91{
92
93    Op->Asl.AmlSubtreeLength = 0;
94    return (AE_OK);
95}
96
97
98/*******************************************************************************
99 *
100 * FUNCTION:    LnPackageLengthWalk
101 *
102 * PARAMETERS:  ASL_WALK_CALLBACK
103 *
104 * RETURN:      Status
105 *
106 * DESCRIPTION: Walk callback to calculate the total AML length.
107 *              1) Calculate the AML lengths (opcode, package length, etc.) for
108 *                 THIS node.
109 *              2) Bubbble up all of these lengths to the parent node by summing
110 *                 them all into the parent subtree length.
111 *
112 * Note:  The SubtreeLength represents the total AML length of all child nodes
113 *        in all subtrees under a given node. Therefore, once this walk is
114 *        complete, the Root Node subtree length is the AML length of the entire
115 *        tree (and thus, the entire ACPI table)
116 *
117 ******************************************************************************/
118
119ACPI_STATUS
120LnPackageLengthWalk (
121    ACPI_PARSE_OBJECT       *Op,
122    UINT32                  Level,
123    void                    *Context)
124{
125
126    /* Generate the AML lengths for this node */
127
128    CgGenerateAmlLengths (Op);
129
130    /* Bubble up all lengths (this node and all below it) to the parent */
131
132    if ((Op->Asl.Parent) &&
133        (Op->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
134    {
135        Op->Asl.Parent->Asl.AmlSubtreeLength += (
136            Op->Asl.AmlLength +
137            Op->Asl.AmlOpcodeLength +
138            Op->Asl.AmlPkgLenBytes +
139            Op->Asl.AmlSubtreeLength);
140    }
141    return (AE_OK);
142}
143
144
145/*******************************************************************************
146 *
147 * FUNCTION:    CgGetPackageLenByteCount
148 *
149 * PARAMETERS:  Op              - Parse node
150 *              PackageLength   - Length to be encoded
151 *
152 * RETURN:      Required length of the package length encoding
153 *
154 * DESCRIPTION: Calculate the number of bytes required to encode the given
155 *              package length.
156 *
157 ******************************************************************************/
158
159static UINT8
160CgGetPackageLenByteCount (
161    ACPI_PARSE_OBJECT       *Op,
162    UINT32                  PackageLength)
163{
164
165    /*
166     * Determine the number of bytes required to encode the package length
167     * Note: the package length includes the number of bytes used to encode
168     * the package length, so we must account for this also.
169     */
170    if (PackageLength <= (0x0000003F - 1))
171    {
172        return (1);
173    }
174    else if (PackageLength <= (0x00000FFF - 2))
175    {
176        return (2);
177    }
178    else if (PackageLength <= (0x000FFFFF - 3))
179    {
180        return (3);
181    }
182    else if (PackageLength <= (0x0FFFFFFF - 4))
183    {
184        return (4);
185    }
186    else
187    {
188        /* Fatal error - the package length is too large to encode */
189
190        AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, Op, NULL);
191    }
192
193    return (0);
194}
195
196
197/*******************************************************************************
198 *
199 * FUNCTION:    CgGenerateAmlOpcodeLength
200 *
201 * PARAMETERS:  Op          - Parse node whose AML opcode lengths will be
202 *                            calculated
203 *
204 * RETURN:      None.
205 *
206 * DESCRIPTION: Calculate the AmlOpcodeLength, AmlPkgLenBytes, and AmlLength
207 *              fields for this node.
208 *
209 ******************************************************************************/
210
211static void
212CgGenerateAmlOpcodeLength (
213    ACPI_PARSE_OBJECT       *Op)
214{
215
216    /* Check for two-byte opcode */
217
218    if (Op->Asl.AmlOpcode > 0x00FF)
219    {
220        Op->Asl.AmlOpcodeLength = 2;
221    }
222    else
223    {
224        Op->Asl.AmlOpcodeLength = 1;
225    }
226
227    /* Does this opcode have an associated "PackageLength" field? */
228
229    Op->Asl.AmlPkgLenBytes = 0;
230    if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
231    {
232        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (
233            Op, Op->Asl.AmlSubtreeLength);
234    }
235
236    /* Data opcode lengths are easy */
237
238    switch (Op->Asl.AmlOpcode)
239    {
240    case AML_BYTE_OP:
241
242        Op->Asl.AmlLength = 1;
243        break;
244
245    case AML_WORD_OP:
246
247        Op->Asl.AmlLength = 2;
248        break;
249
250    case AML_DWORD_OP:
251
252        Op->Asl.AmlLength = 4;
253        break;
254
255    case AML_QWORD_OP:
256
257        Op->Asl.AmlLength = 8;
258        break;
259
260    default:
261
262        /* All data opcodes must be above */
263        break;
264    }
265}
266
267
268/*******************************************************************************
269 *
270 * FUNCTION:    CgGenerateAmlLengths
271 *
272 * PARAMETERS:  Op        - Parse node
273 *
274 * RETURN:      None.
275 *
276 * DESCRIPTION: Generate internal length fields based on the AML opcode or
277 *              parse opcode.
278 *
279 ******************************************************************************/
280
281void
282CgGenerateAmlLengths (
283    ACPI_PARSE_OBJECT       *Op)
284{
285    char                    *Buffer;
286    ACPI_STATUS             Status;
287
288
289    switch (Op->Asl.AmlOpcode)
290    {
291    case AML_RAW_DATA_BYTE:
292
293        Op->Asl.AmlOpcodeLength = 0;
294        Op->Asl.AmlLength = 1;
295        return;
296
297    case AML_RAW_DATA_WORD:
298
299        Op->Asl.AmlOpcodeLength = 0;
300        Op->Asl.AmlLength = 2;
301        return;
302
303    case AML_RAW_DATA_DWORD:
304
305        Op->Asl.AmlOpcodeLength = 0;
306        Op->Asl.AmlLength = 4;
307        return;
308
309    case AML_RAW_DATA_QWORD:
310
311        Op->Asl.AmlOpcodeLength = 0;
312        Op->Asl.AmlLength = 8;
313        return;
314
315    case AML_RAW_DATA_BUFFER:
316
317        /* Aml length is/was set by creator */
318
319        Op->Asl.AmlOpcodeLength = 0;
320        return;
321
322    case AML_RAW_DATA_CHAIN:
323
324        /* Aml length is/was set by creator */
325
326        Op->Asl.AmlOpcodeLength = 0;
327        return;
328
329    default:
330
331        break;
332    }
333
334    switch (Op->Asl.ParseOpcode)
335    {
336    case PARSEOP_DEFINITION_BLOCK:
337
338        Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
339        break;
340
341    case PARSEOP_NAMESEG:
342
343        Op->Asl.AmlOpcodeLength = 0;
344        Op->Asl.AmlLength = 4;
345        Op->Asl.ExternalName = Op->Asl.Value.String;
346        break;
347
348    case PARSEOP_NAMESTRING:
349    case PARSEOP_METHODCALL:
350
351        if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED)
352        {
353            break;
354        }
355
356        Op->Asl.AmlOpcodeLength = 0;
357        Status = UtInternalizeName (Op->Asl.Value.String, &Buffer);
358        if (ACPI_FAILURE (Status))
359        {
360            DbgPrint (ASL_DEBUG_OUTPUT,
361                "Failure from internalize name %X\n", Status);
362            break;
363        }
364
365        Op->Asl.ExternalName = Op->Asl.Value.String;
366        Op->Asl.Value.String = Buffer;
367        Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED;
368        Op->Asl.AmlLength = strlen (Buffer);
369
370        /*
371         * Check for single backslash reference to root,
372         * make it a null terminated string in the AML
373         */
374        if (Op->Asl.AmlLength == 1)
375        {
376            Op->Asl.AmlLength = 2;
377        }
378        break;
379
380    case PARSEOP_STRING_LITERAL:
381
382        Op->Asl.AmlOpcodeLength = 1;
383
384        /* Get null terminator */
385
386        Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1;
387        break;
388
389    case PARSEOP_PACKAGE_LENGTH:
390
391        Op->Asl.AmlOpcodeLength = 0;
392        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op,
393            (UINT32) Op->Asl.Value.Integer);
394        break;
395
396    case PARSEOP_RAW_DATA:
397
398        Op->Asl.AmlOpcodeLength = 0;
399        break;
400
401    case PARSEOP_DEFAULT_ARG:
402    case PARSEOP_INCLUDE:
403    case PARSEOP_INCLUDE_END:
404
405        /* Ignore the "default arg" nodes, they are extraneous at this point */
406
407        break;
408
409    case PARSEOP_EXTERNAL:
410
411        if (Gbl_DoExternals == TRUE)
412        {
413            CgGenerateAmlOpcodeLength (Op);
414        }
415        break;
416
417    default:
418
419        CgGenerateAmlOpcodeLength (Op);
420        break;
421    }
422}
423
424
425#ifdef ACPI_OBSOLETE_FUNCTIONS
426/*******************************************************************************
427 *
428 * FUNCTION:    LnAdjustLengthToRoot
429 *
430 * PARAMETERS:  Op      - Node whose Length was changed
431 *
432 * RETURN:      None.
433 *
434 * DESCRIPTION: Change the Subtree length of the given node, and bubble the
435 *              change all the way up to the root node. This allows for
436 *              last second changes to a package length (for example, if the
437 *              package length encoding gets shorter or longer.)
438 *
439 ******************************************************************************/
440
441void
442LnAdjustLengthToRoot (
443    ACPI_PARSE_OBJECT       *SubtreeOp,
444    UINT32                  LengthDelta)
445{
446    ACPI_PARSE_OBJECT       *Op;
447
448
449    /* Adjust all subtree lengths up to the root */
450
451    Op = SubtreeOp->Asl.Parent;
452    while (Op)
453    {
454        Op->Asl.AmlSubtreeLength -= LengthDelta;
455        Op = Op->Asl.Parent;
456    }
457
458    /* Adjust the global table length */
459
460    Gbl_TableLength -= LengthDelta;
461}
462#endif
463