xref: /freebsd/sys/contrib/dev/acpica/compiler/asllength.c (revision c6ec7d31830ab1c80edae95ad5e4b9dba10c47ac)
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 
55 static UINT8
56 CgGetPackageLenByteCount (
57     ACPI_PARSE_OBJECT       *Op,
58     UINT32                  PackageLength);
59 
60 static void
61 CgGenerateAmlOpcodeLength (
62     ACPI_PARSE_OBJECT       *Op);
63 
64 
65 #ifdef ACPI_OBSOLETE_FUNCTIONS
66 void
67 LnAdjustLengthToRoot (
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 
87 ACPI_STATUS
88 LnInitLengthsWalk (
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 
120 ACPI_STATUS
121 LnPackageLengthWalk (
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 
159 static UINT8
160 CgGetPackageLenByteCount (
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 
211 static void
212 CgGenerateAmlOpcodeLength (
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 
280 void
281 CgGenerateAmlLengths (
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 
434 void
435 LnAdjustLengthToRoot (
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