asllength.c revision 281075
1/******************************************************************************
2 *
3 * Module Name: asllength - Tree walk to determine package and opcode lengths
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2015, 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 += (Op->Asl.AmlLength +
136                                           Op->Asl.AmlOpcodeLength +
137                                           Op->Asl.AmlPkgLenBytes +
138                                           Op->Asl.AmlSubtreeLength);
139    }
140    return (AE_OK);
141}
142
143
144/*******************************************************************************
145 *
146 * FUNCTION:    CgGetPackageLenByteCount
147 *
148 * PARAMETERS:  Op              - Parse node
149 *              PackageLength   - Length to be encoded
150 *
151 * RETURN:      Required length of the package length encoding
152 *
153 * DESCRIPTION: Calculate the number of bytes required to encode the given
154 *              package length.
155 *
156 ******************************************************************************/
157
158static UINT8
159CgGetPackageLenByteCount (
160    ACPI_PARSE_OBJECT       *Op,
161    UINT32                  PackageLength)
162{
163
164    /*
165     * Determine the number of bytes required to encode the package length
166     * Note: the package length includes the number of bytes used to encode
167     * the package length, so we must account for this also.
168     */
169    if (PackageLength <= (0x0000003F - 1))
170    {
171        return (1);
172    }
173    else if (PackageLength <= (0x00000FFF - 2))
174    {
175        return (2);
176    }
177    else if (PackageLength <= (0x000FFFFF - 3))
178    {
179        return (3);
180    }
181    else if (PackageLength <= (0x0FFFFFFF - 4))
182    {
183        return (4);
184    }
185    else
186    {
187        /* Fatal error - the package length is too large to encode */
188
189        AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, Op, NULL);
190    }
191
192    return (0);
193}
194
195
196/*******************************************************************************
197 *
198 * FUNCTION:    CgGenerateAmlOpcodeLength
199 *
200 * PARAMETERS:  Op          - Parse node whose AML opcode lengths will be
201 *                            calculated
202 *
203 * RETURN:      None.
204 *
205 * DESCRIPTION: Calculate the AmlOpcodeLength, AmlPkgLenBytes, and AmlLength
206 *              fields for this node.
207 *
208 ******************************************************************************/
209
210static void
211CgGenerateAmlOpcodeLength (
212    ACPI_PARSE_OBJECT       *Op)
213{
214
215    /* Check for two-byte opcode */
216
217    if (Op->Asl.AmlOpcode > 0x00FF)
218    {
219        Op->Asl.AmlOpcodeLength = 2;
220    }
221    else
222    {
223        Op->Asl.AmlOpcodeLength = 1;
224    }
225
226    /* Does this opcode have an associated "PackageLength" field? */
227
228    Op->Asl.AmlPkgLenBytes = 0;
229    if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
230    {
231        Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (
232                                    Op, Op->Asl.AmlSubtreeLength);
233    }
234
235    /* Data opcode lengths are easy */
236
237    switch (Op->Asl.AmlOpcode)
238    {
239    case AML_BYTE_OP:
240
241        Op->Asl.AmlLength = 1;
242        break;
243
244    case AML_WORD_OP:
245
246        Op->Asl.AmlLength = 2;
247        break;
248
249    case AML_DWORD_OP:
250
251        Op->Asl.AmlLength = 4;
252        break;
253
254    case AML_QWORD_OP:
255
256        Op->Asl.AmlLength = 8;
257        break;
258
259    default:
260
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
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