asllength.c revision 241973
1/******************************************************************************
2 *
3 * Module Name: asllength - Tree walk to determine package and opcode lengths
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2012, 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        /* All data opcodes must be above */
262        break;
263    }
264}
265
266
267/*******************************************************************************
268 *
269 * FUNCTION:    CgGenerateAmlLengths
270 *
271 * PARAMETERS:  Op        - Parse node
272 *
273 * RETURN:      None.
274 *
275 * DESCRIPTION: Generate internal length fields based on the AML opcode or
276 *              parse opcode.
277 *
278 ******************************************************************************/
279
280void
281CgGenerateAmlLengths (
282    ACPI_PARSE_OBJECT       *Op)
283{
284    char                    *Buffer;
285    ACPI_STATUS             Status;
286
287
288    switch (Op->Asl.AmlOpcode)
289    {
290    case AML_RAW_DATA_BYTE:
291
292        Op->Asl.AmlOpcodeLength = 0;
293        Op->Asl.AmlLength = 1;
294        return;
295
296    case AML_RAW_DATA_WORD:
297
298        Op->Asl.AmlOpcodeLength = 0;
299        Op->Asl.AmlLength = 2;
300        return;
301
302    case AML_RAW_DATA_DWORD:
303
304        Op->Asl.AmlOpcodeLength = 0;
305        Op->Asl.AmlLength = 4;
306        return;
307
308    case AML_RAW_DATA_QWORD:
309
310        Op->Asl.AmlOpcodeLength = 0;
311        Op->Asl.AmlLength = 8;
312        return;
313
314    case AML_RAW_DATA_BUFFER:
315
316        /* Aml length is/was set by creator */
317
318        Op->Asl.AmlOpcodeLength = 0;
319        return;
320
321    case AML_RAW_DATA_CHAIN:
322
323        /* Aml length is/was set by creator */
324
325        Op->Asl.AmlOpcodeLength = 0;
326        return;
327
328    default:
329        break;
330    }
331
332    switch (Op->Asl.ParseOpcode)
333    {
334    case PARSEOP_DEFINITIONBLOCK:
335
336        Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) +
337                            Op->Asl.AmlSubtreeLength;
338        break;
339
340    case PARSEOP_NAMESEG:
341
342        Op->Asl.AmlOpcodeLength = 0;
343        Op->Asl.AmlLength = 4;
344        Op->Asl.ExternalName = Op->Asl.Value.String;
345        break;
346
347    case PARSEOP_NAMESTRING:
348    case PARSEOP_METHODCALL:
349
350        if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED)
351        {
352            break;
353        }
354
355        Op->Asl.AmlOpcodeLength = 0;
356        Status = UtInternalizeName (Op->Asl.Value.String, &Buffer);
357        if (ACPI_FAILURE (Status))
358        {
359            DbgPrint (ASL_DEBUG_OUTPUT,
360                "Failure from internalize name %X\n", Status);
361            break;
362        }
363
364        Op->Asl.ExternalName = Op->Asl.Value.String;
365        Op->Asl.Value.String = Buffer;
366        Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED;
367
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_EXTERNAL:
403    case PARSEOP_INCLUDE:
404    case PARSEOP_INCLUDE_END:
405
406        /* Ignore the "default arg" nodes, they are extraneous at this point */
407
408        break;
409
410    default:
411
412        CgGenerateAmlOpcodeLength (Op);
413        break;
414    }
415}
416
417
418#ifdef ACPI_OBSOLETE_FUNCTIONS
419/*******************************************************************************
420 *
421 * FUNCTION:    LnAdjustLengthToRoot
422 *
423 * PARAMETERS:  Op      - Node whose Length was changed
424 *
425 * RETURN:      None.
426 *
427 * DESCRIPTION: Change the Subtree length of the given node, and bubble the
428 *              change all the way up to the root node. This allows for
429 *              last second changes to a package length (for example, if the
430 *              package length encoding gets shorter or longer.)
431 *
432 ******************************************************************************/
433
434void
435LnAdjustLengthToRoot (
436    ACPI_PARSE_OBJECT       *SubtreeOp,
437    UINT32                  LengthDelta)
438{
439    ACPI_PARSE_OBJECT       *Op;
440
441
442    /* Adjust all subtree lengths up to the root */
443
444    Op = SubtreeOp->Asl.Parent;
445    while (Op)
446    {
447        Op->Asl.AmlSubtreeLength -= LengthDelta;
448        Op = Op->Asl.Parent;
449    }
450
451    /* Adjust the global table length */
452
453    Gbl_TableLength -= LengthDelta;
454}
455#endif
456