asllength.c revision 229989
1
2/******************************************************************************
3 *
4 * Module Name: asllength - Tree walk to determine package and opcode lengths
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2012, Intel Corp.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions, and the following disclaimer,
17 *    without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 *    substantially similar to the "NO WARRANTY" disclaimer below
20 *    ("Disclaimer") and any redistribution must be conditioned upon
21 *    including a substantially similar Disclaimer requirement for further
22 *    binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 *    of any contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
30 *
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
43 */
44
45
46#include <contrib/dev/acpica/compiler/aslcompiler.h>
47#include "aslcompiler.y.h"
48#include <contrib/dev/acpica/include/amlcode.h>
49
50
51#define _COMPONENT          ACPI_COMPILER
52        ACPI_MODULE_NAME    ("asllength")
53
54/* Local prototypes */
55
56static UINT8
57CgGetPackageLenByteCount (
58    ACPI_PARSE_OBJECT       *Op,
59    UINT32                  PackageLength);
60
61static void
62CgGenerateAmlOpcodeLength (
63    ACPI_PARSE_OBJECT       *Op);
64
65
66#ifdef ACPI_OBSOLETE_FUNCTIONS
67void
68LnAdjustLengthToRoot (
69    ACPI_PARSE_OBJECT       *Op,
70    UINT32                  LengthDelta);
71#endif
72
73
74/*******************************************************************************
75 *
76 * FUNCTION:    LnInitLengthsWalk
77 *
78 * PARAMETERS:  ASL_WALK_CALLBACK
79 *
80 * RETURN:      Status
81 *
82 * DESCRIPTION: Walk callback to initialize (and re-initialize) the node
83 *              subtree length(s) to zero.  The Subtree lengths are bubbled
84 *              up to the root node in order to get a total AML length.
85 *
86 ******************************************************************************/
87
88ACPI_STATUS
89LnInitLengthsWalk (
90    ACPI_PARSE_OBJECT       *Op,
91    UINT32                  Level,
92    void                    *Context)
93{
94
95    Op->Asl.AmlSubtreeLength = 0;
96    return (AE_OK);
97}
98
99
100/*******************************************************************************
101 *
102 * FUNCTION:    LnPackageLengthWalk
103 *
104 * PARAMETERS:  ASL_WALK_CALLBACK
105 *
106 * RETURN:      Status
107 *
108 * DESCRIPTION: Walk callback to calculate the total AML length.
109 *              1) Calculate the AML lengths (opcode, package length, etc.) for
110 *                 THIS node.
111 *              2) Bubbble up all of these lengths to the parent node by summing
112 *                 them all into the parent subtree length.
113 *
114 * Note:  The SubtreeLength represents the total AML length of all child nodes
115 *        in all subtrees under a given node.  Therefore, once this walk is
116 *        complete, the Root Node subtree length is the AML length of the entire
117 *        tree (and thus, the entire ACPI table)
118 *
119 ******************************************************************************/
120
121ACPI_STATUS
122LnPackageLengthWalk (
123    ACPI_PARSE_OBJECT       *Op,
124    UINT32                  Level,
125    void                    *Context)
126{
127
128    /* Generate the AML lengths for this node */
129
130    CgGenerateAmlLengths (Op);
131
132    /* Bubble up all lengths (this node and all below it) to the parent */
133
134    if ((Op->Asl.Parent) &&
135        (Op->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
136    {
137        Op->Asl.Parent->Asl.AmlSubtreeLength += (Op->Asl.AmlLength +
138                                           Op->Asl.AmlOpcodeLength +
139                                           Op->Asl.AmlPkgLenBytes +
140                                           Op->Asl.AmlSubtreeLength);
141    }
142    return (AE_OK);
143}
144
145
146/*******************************************************************************
147 *
148 * FUNCTION:    CgGetPackageLenByteCount
149 *
150 * PARAMETERS:  Op              - Parse node
151 *              PackageLength   - Length to be encoded
152 *
153 * RETURN:      Required length of the package length encoding
154 *
155 * DESCRIPTION: Calculate the number of bytes required to encode the given
156 *              package length.
157 *
158 ******************************************************************************/
159
160static UINT8
161CgGetPackageLenByteCount (
162    ACPI_PARSE_OBJECT       *Op,
163    UINT32                  PackageLength)
164{
165
166    /*
167     * Determine the number of bytes required to encode the package length
168     * Note: the package length includes the number of bytes used to encode
169     * the package length, so we must account for this also.
170     */
171    if (PackageLength <= (0x0000003F - 1))
172    {
173        return (1);
174    }
175    else if (PackageLength <= (0x00000FFF - 2))
176    {
177        return (2);
178    }
179    else if (PackageLength <= (0x000FFFFF - 3))
180    {
181        return (3);
182    }
183    else if (PackageLength <= (0x0FFFFFFF - 4))
184    {
185        return (4);
186    }
187    else
188    {
189        /* Fatal error - the package length is too large to encode */
190
191        AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, Op, NULL);
192    }
193
194    return (0);
195}
196
197
198/*******************************************************************************
199 *
200 * FUNCTION:    CgGenerateAmlOpcodeLength
201 *
202 * PARAMETERS:  Op          - Parse node whose AML opcode lengths will be
203 *                            calculated
204 *
205 * RETURN:      None.
206 *
207 * DESCRIPTION: Calculate the AmlOpcodeLength, AmlPkgLenBytes, and AmlLength
208 *              fields for this node.
209 *
210 ******************************************************************************/
211
212static void
213CgGenerateAmlOpcodeLength (
214    ACPI_PARSE_OBJECT       *Op)
215{
216
217    /* Check for two-byte opcode */
218
219    if (Op->Asl.AmlOpcode > 0x00FF)
220    {
221        Op->Asl.AmlOpcodeLength = 2;
222    }
223    else
224    {
225        Op->Asl.AmlOpcodeLength = 1;
226    }
227
228    /* Does this opcode have an associated "PackageLength" field? */
229
230    Op->Asl.AmlPkgLenBytes = 0;
231    if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
232    {
233        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (
234                                    Op, Op->Asl.AmlSubtreeLength);
235    }
236
237    /* Data opcode lengths are easy */
238
239    switch (Op->Asl.AmlOpcode)
240    {
241    case AML_BYTE_OP:
242
243        Op->Asl.AmlLength = 1;
244        break;
245
246    case AML_WORD_OP:
247
248        Op->Asl.AmlLength = 2;
249        break;
250
251    case AML_DWORD_OP:
252
253        Op->Asl.AmlLength = 4;
254        break;
255
256    case AML_QWORD_OP:
257
258        Op->Asl.AmlLength = 8;
259        break;
260
261    default:
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        break;
331    }
332
333    switch (Op->Asl.ParseOpcode)
334    {
335    case PARSEOP_DEFINITIONBLOCK:
336
337        Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) +
338                            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
369        Op->Asl.AmlLength = strlen (Buffer);
370
371        /*
372         * Check for single backslash reference to root,
373         * make it a null terminated string in the AML
374         */
375        if (Op->Asl.AmlLength == 1)
376        {
377            Op->Asl.AmlLength = 2;
378        }
379        break;
380
381    case PARSEOP_STRING_LITERAL:
382
383        Op->Asl.AmlOpcodeLength = 1;
384
385        /* Get null terminator */
386
387        Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1;
388        break;
389
390    case PARSEOP_PACKAGE_LENGTH:
391
392        Op->Asl.AmlOpcodeLength = 0;
393        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op,
394                                    (UINT32) Op->Asl.Value.Integer);
395        break;
396
397    case PARSEOP_RAW_DATA:
398
399        Op->Asl.AmlOpcodeLength = 0;
400        break;
401
402    case PARSEOP_DEFAULT_ARG:
403    case PARSEOP_EXTERNAL:
404    case PARSEOP_INCLUDE:
405    case PARSEOP_INCLUDE_END:
406
407        /* Ignore the "default arg" nodes, they are extraneous at this point */
408
409        break;
410
411    default:
412
413        CgGenerateAmlOpcodeLength (Op);
414        break;
415    }
416}
417
418
419#ifdef ACPI_OBSOLETE_FUNCTIONS
420/*******************************************************************************
421 *
422 * FUNCTION:    LnAdjustLengthToRoot
423 *
424 * PARAMETERS:  Op      - Node whose Length was changed
425 *
426 * RETURN:      None.
427 *
428 * DESCRIPTION: Change the Subtree length of the given node, and bubble the
429 *              change all the way up to the root node.  This allows for
430 *              last second changes to a package length (for example, if the
431 *              package length encoding gets shorter or longer.)
432 *
433 ******************************************************************************/
434
435void
436LnAdjustLengthToRoot (
437    ACPI_PARSE_OBJECT       *SubtreeOp,
438    UINT32                  LengthDelta)
439{
440    ACPI_PARSE_OBJECT       *Op;
441
442
443    /* Adjust all subtree lengths up to the root */
444
445    Op = SubtreeOp->Asl.Parent;
446    while (Op)
447    {
448        Op->Asl.AmlSubtreeLength -= LengthDelta;
449        Op = Op->Asl.Parent;
450    }
451
452    /* Adjust the global table length */
453
454    Gbl_TableLength -= LengthDelta;
455}
456#endif
457
458
459