xref: /freebsd/sys/contrib/dev/acpica/compiler/asllength.c (revision 7750ad47a9a7dbc83f87158464170c8640723293)
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 
56 static UINT8
57 CgGetPackageLenByteCount (
58     ACPI_PARSE_OBJECT       *Op,
59     UINT32                  PackageLength);
60 
61 static void
62 CgGenerateAmlOpcodeLength (
63     ACPI_PARSE_OBJECT       *Op);
64 
65 
66 #ifdef ACPI_OBSOLETE_FUNCTIONS
67 void
68 LnAdjustLengthToRoot (
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 
88 ACPI_STATUS
89 LnInitLengthsWalk (
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 
121 ACPI_STATUS
122 LnPackageLengthWalk (
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 
160 static UINT8
161 CgGetPackageLenByteCount (
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 
212 static void
213 CgGenerateAmlOpcodeLength (
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 
281 void
282 CgGenerateAmlLengths (
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 
435 void
436 LnAdjustLengthToRoot (
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