xref: /freebsd/sys/contrib/dev/acpica/compiler/asllength.c (revision 98e0ffaefb0f241cda3a72395d3be04192ae0d47)
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 
54 static UINT8
55 CgGetPackageLenByteCount (
56     ACPI_PARSE_OBJECT       *Op,
57     UINT32                  PackageLength);
58 
59 static void
60 CgGenerateAmlOpcodeLength (
61     ACPI_PARSE_OBJECT       *Op);
62 
63 
64 #ifdef ACPI_OBSOLETE_FUNCTIONS
65 void
66 LnAdjustLengthToRoot (
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 
86 ACPI_STATUS
87 LnInitLengthsWalk (
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 
119 ACPI_STATUS
120 LnPackageLengthWalk (
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 
158 static UINT8
159 CgGetPackageLenByteCount (
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 
210 static void
211 CgGenerateAmlOpcodeLength (
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 
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 
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