xref: /freebsd/sys/contrib/dev/acpica/compiler/asllength.c (revision af6a5351a1fdb1130f18be6c782c4d48916eb971)
1 /******************************************************************************
2  *
3  * Module Name: asllength - Tree walk to determine package and opcode lengths
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2017, 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 += (
136             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 
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 
331         break;
332     }
333 
334     switch (Op->Asl.ParseOpcode)
335     {
336     case PARSEOP_DEFINITION_BLOCK:
337 
338         Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) + 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         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_INCLUDE:
403     case PARSEOP_INCLUDE_END:
404 
405         /* Ignore the "default arg" nodes, they are extraneous at this point */
406 
407         break;
408 
409     case PARSEOP_EXTERNAL:
410 
411         if (Gbl_DoExternals == TRUE)
412         {
413             CgGenerateAmlOpcodeLength (Op);
414         }
415         break;
416 
417     default:
418 
419         CgGenerateAmlOpcodeLength (Op);
420         break;
421     }
422 }
423 
424 
425 #ifdef ACPI_OBSOLETE_FUNCTIONS
426 /*******************************************************************************
427  *
428  * FUNCTION:    LnAdjustLengthToRoot
429  *
430  * PARAMETERS:  Op      - Node whose Length was changed
431  *
432  * RETURN:      None.
433  *
434  * DESCRIPTION: Change the Subtree length of the given node, and bubble the
435  *              change all the way up to the root node. This allows for
436  *              last second changes to a package length (for example, if the
437  *              package length encoding gets shorter or longer.)
438  *
439  ******************************************************************************/
440 
441 void
442 LnAdjustLengthToRoot (
443     ACPI_PARSE_OBJECT       *SubtreeOp,
444     UINT32                  LengthDelta)
445 {
446     ACPI_PARSE_OBJECT       *Op;
447 
448 
449     /* Adjust all subtree lengths up to the root */
450 
451     Op = SubtreeOp->Asl.Parent;
452     while (Op)
453     {
454         Op->Asl.AmlSubtreeLength -= LengthDelta;
455         Op = Op->Asl.Parent;
456     }
457 
458     /* Adjust the global table length */
459 
460     Gbl_TableLength -= LengthDelta;
461 }
462 #endif
463