asllength.c revision 256281
1/******************************************************************************
2 *
3 * Module Name: asllength - Tree walk to determine package and opcode lengths
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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
45#include <contrib/dev/acpica/compiler/aslcompiler.h>
46#include "aslcompiler.y.h"
47#include <contrib/dev/acpica/include/amlcode.h>
48
49
50#define _COMPONENT          ACPI_COMPILER
51        ACPI_MODULE_NAME    ("asllength")
52
53/* Local prototypes */
54
55static UINT8
56CgGetPackageLenByteCount (
57    ACPI_PARSE_OBJECT       *Op,
58    UINT32                  PackageLength);
59
60static void
61CgGenerateAmlOpcodeLength (
62    ACPI_PARSE_OBJECT       *Op);
63
64
65#ifdef ACPI_OBSOLETE_FUNCTIONS
66void
67LnAdjustLengthToRoot (
68    ACPI_PARSE_OBJECT       *Op,
69    UINT32                  LengthDelta);
70#endif
71
72
73/*******************************************************************************
74 *
75 * FUNCTION:    LnInitLengthsWalk
76 *
77 * PARAMETERS:  ASL_WALK_CALLBACK
78 *
79 * RETURN:      Status
80 *
81 * DESCRIPTION: Walk callback to initialize (and re-initialize) the node
82 *              subtree length(s) to zero. The Subtree lengths are bubbled
83 *              up to the root node in order to get a total AML length.
84 *
85 ******************************************************************************/
86
87ACPI_STATUS
88LnInitLengthsWalk (
89    ACPI_PARSE_OBJECT       *Op,
90    UINT32                  Level,
91    void                    *Context)
92{
93
94    Op->Asl.AmlSubtreeLength = 0;
95    return (AE_OK);
96}
97
98
99/*******************************************************************************
100 *
101 * FUNCTION:    LnPackageLengthWalk
102 *
103 * PARAMETERS:  ASL_WALK_CALLBACK
104 *
105 * RETURN:      Status
106 *
107 * DESCRIPTION: Walk callback to calculate the total AML length.
108 *              1) Calculate the AML lengths (opcode, package length, etc.) for
109 *                 THIS node.
110 *              2) Bubbble up all of these lengths to the parent node by summing
111 *                 them all into the parent subtree length.
112 *
113 * Note:  The SubtreeLength represents the total AML length of all child nodes
114 *        in all subtrees under a given node. Therefore, once this walk is
115 *        complete, the Root Node subtree length is the AML length of the entire
116 *        tree (and thus, the entire ACPI table)
117 *
118 ******************************************************************************/
119
120ACPI_STATUS
121LnPackageLengthWalk (
122    ACPI_PARSE_OBJECT       *Op,
123    UINT32                  Level,
124    void                    *Context)
125{
126
127    /* Generate the AML lengths for this node */
128
129    CgGenerateAmlLengths (Op);
130
131    /* Bubble up all lengths (this node and all below it) to the parent */
132
133    if ((Op->Asl.Parent) &&
134        (Op->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
135    {
136        Op->Asl.Parent->Asl.AmlSubtreeLength += (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_DEFINITIONBLOCK:
337
338        Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) +
339                            Op->Asl.AmlSubtreeLength;
340        break;
341
342    case PARSEOP_NAMESEG:
343
344        Op->Asl.AmlOpcodeLength = 0;
345        Op->Asl.AmlLength = 4;
346        Op->Asl.ExternalName = Op->Asl.Value.String;
347        break;
348
349    case PARSEOP_NAMESTRING:
350    case PARSEOP_METHODCALL:
351
352        if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED)
353        {
354            break;
355        }
356
357        Op->Asl.AmlOpcodeLength = 0;
358        Status = UtInternalizeName (Op->Asl.Value.String, &Buffer);
359        if (ACPI_FAILURE (Status))
360        {
361            DbgPrint (ASL_DEBUG_OUTPUT,
362                "Failure from internalize name %X\n", Status);
363            break;
364        }
365
366        Op->Asl.ExternalName = Op->Asl.Value.String;
367        Op->Asl.Value.String = Buffer;
368        Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED;
369
370        Op->Asl.AmlLength = strlen (Buffer);
371
372        /*
373         * Check for single backslash reference to root,
374         * make it a null terminated string in the AML
375         */
376        if (Op->Asl.AmlLength == 1)
377        {
378            Op->Asl.AmlLength = 2;
379        }
380        break;
381
382    case PARSEOP_STRING_LITERAL:
383
384        Op->Asl.AmlOpcodeLength = 1;
385
386        /* Get null terminator */
387
388        Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1;
389        break;
390
391    case PARSEOP_PACKAGE_LENGTH:
392
393        Op->Asl.AmlOpcodeLength = 0;
394        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op,
395                                    (UINT32) Op->Asl.Value.Integer);
396        break;
397
398    case PARSEOP_RAW_DATA:
399
400        Op->Asl.AmlOpcodeLength = 0;
401        break;
402
403    case PARSEOP_DEFAULT_ARG:
404    case PARSEOP_EXTERNAL:
405    case PARSEOP_INCLUDE:
406    case PARSEOP_INCLUDE_END:
407
408        /* Ignore the "default arg" nodes, they are extraneous at this point */
409
410        break;
411
412    default:
413
414        CgGenerateAmlOpcodeLength (Op);
415        break;
416    }
417}
418
419
420#ifdef ACPI_OBSOLETE_FUNCTIONS
421/*******************************************************************************
422 *
423 * FUNCTION:    LnAdjustLengthToRoot
424 *
425 * PARAMETERS:  Op      - Node whose Length was changed
426 *
427 * RETURN:      None.
428 *
429 * DESCRIPTION: Change the Subtree length of the given node, and bubble the
430 *              change all the way up to the root node. This allows for
431 *              last second changes to a package length (for example, if the
432 *              package length encoding gets shorter or longer.)
433 *
434 ******************************************************************************/
435
436void
437LnAdjustLengthToRoot (
438    ACPI_PARSE_OBJECT       *SubtreeOp,
439    UINT32                  LengthDelta)
440{
441    ACPI_PARSE_OBJECT       *Op;
442
443
444    /* Adjust all subtree lengths up to the root */
445
446    Op = SubtreeOp->Asl.Parent;
447    while (Op)
448    {
449        Op->Asl.AmlSubtreeLength -= LengthDelta;
450        Op = Op->Asl.Parent;
451    }
452
453    /* Adjust the global table length */
454
455    Gbl_TableLength -= LengthDelta;
456}
457#endif
458