Sync ACPICA with Intel's version 20170224.
[dragonfly.git] / sys / contrib / dev / acpica / source / compiler / asllength.c
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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "amlcode.h"
47 #include "acconvert.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 += (
137             Op->Asl.AmlLength +
138             Op->Asl.AmlOpcodeLength +
139             Op->Asl.AmlPkgLenBytes +
140             Op->Asl.AmlSubtreeLength +
141             CvCalculateCommentLengths (Op)
142         );
143     }
144     return (AE_OK);
145 }
146
147
148 /*******************************************************************************
149  *
150  * FUNCTION:    CgGetPackageLenByteCount
151  *
152  * PARAMETERS:  Op              - Parse node
153  *              PackageLength   - Length to be encoded
154  *
155  * RETURN:      Required length of the package length encoding
156  *
157  * DESCRIPTION: Calculate the number of bytes required to encode the given
158  *              package length.
159  *
160  ******************************************************************************/
161
162 static UINT8
163 CgGetPackageLenByteCount (
164     ACPI_PARSE_OBJECT       *Op,
165     UINT32                  PackageLength)
166 {
167
168     /*
169      * Determine the number of bytes required to encode the package length
170      * Note: the package length includes the number of bytes used to encode
171      * the package length, so we must account for this also.
172      */
173     if (PackageLength <= (0x0000003F - 1))
174     {
175         return (1);
176     }
177     else if (PackageLength <= (0x00000FFF - 2))
178     {
179         return (2);
180     }
181     else if (PackageLength <= (0x000FFFFF - 3))
182     {
183         return (3);
184     }
185     else if (PackageLength <= (0x0FFFFFFF - 4))
186     {
187         return (4);
188     }
189     else
190     {
191         /* Fatal error - the package length is too large to encode */
192
193         AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, Op, NULL);
194     }
195
196     return (0);
197 }
198
199
200 /*******************************************************************************
201  *
202  * FUNCTION:    CgGenerateAmlOpcodeLength
203  *
204  * PARAMETERS:  Op          - Parse node whose AML opcode lengths will be
205  *                            calculated
206  *
207  * RETURN:      None.
208  *
209  * DESCRIPTION: Calculate the AmlOpcodeLength, AmlPkgLenBytes, and AmlLength
210  *              fields for this node.
211  *
212  ******************************************************************************/
213
214 static void
215 CgGenerateAmlOpcodeLength (
216     ACPI_PARSE_OBJECT       *Op)
217 {
218
219     /* Check for two-byte opcode */
220
221     if (Op->Asl.AmlOpcode > 0x00FF)
222     {
223         Op->Asl.AmlOpcodeLength = 2;
224     }
225     else
226     {
227         Op->Asl.AmlOpcodeLength = 1;
228     }
229
230     /* Does this opcode have an associated "PackageLength" field? */
231
232     Op->Asl.AmlPkgLenBytes = 0;
233     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
234     {
235         Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (
236             Op, Op->Asl.AmlSubtreeLength);
237     }
238
239     /* Data opcode lengths are easy */
240
241     switch (Op->Asl.AmlOpcode)
242     {
243     case AML_BYTE_OP:
244
245         Op->Asl.AmlLength = 1;
246         break;
247
248     case AML_WORD_OP:
249
250         Op->Asl.AmlLength = 2;
251         break;
252
253     case AML_DWORD_OP:
254
255         Op->Asl.AmlLength = 4;
256         break;
257
258     case AML_QWORD_OP:
259
260         Op->Asl.AmlLength = 8;
261         break;
262
263     default:
264
265         /* All data opcodes must be above */
266         break;
267     }
268 }
269
270
271 /*******************************************************************************
272  *
273  * FUNCTION:    CgGenerateAmlLengths
274  *
275  * PARAMETERS:  Op        - Parse node
276  *
277  * RETURN:      None.
278  *
279  * DESCRIPTION: Generate internal length fields based on the AML opcode or
280  *              parse opcode.
281  *
282  ******************************************************************************/
283
284 void
285 CgGenerateAmlLengths (
286     ACPI_PARSE_OBJECT       *Op)
287 {
288     char                    *Buffer;
289     ACPI_STATUS             Status;
290
291
292     switch (Op->Asl.AmlOpcode)
293     {
294     case AML_RAW_DATA_BYTE:
295
296         Op->Asl.AmlOpcodeLength = 0;
297         Op->Asl.AmlLength = 1;
298         return;
299
300     case AML_RAW_DATA_WORD:
301
302         Op->Asl.AmlOpcodeLength = 0;
303         Op->Asl.AmlLength = 2;
304         return;
305
306     case AML_RAW_DATA_DWORD:
307
308         Op->Asl.AmlOpcodeLength = 0;
309         Op->Asl.AmlLength = 4;
310         return;
311
312     case AML_RAW_DATA_QWORD:
313
314         Op->Asl.AmlOpcodeLength = 0;
315         Op->Asl.AmlLength = 8;
316         return;
317
318     case AML_RAW_DATA_BUFFER:
319
320         /* Aml length is/was set by creator */
321
322         Op->Asl.AmlOpcodeLength = 0;
323         return;
324
325     case AML_RAW_DATA_CHAIN:
326
327         /* Aml length is/was set by creator */
328
329         Op->Asl.AmlOpcodeLength = 0;
330         return;
331
332     default:
333
334         break;
335     }
336
337     switch (Op->Asl.ParseOpcode)
338     {
339     case PARSEOP_DEFINITION_BLOCK:
340
341         Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
342         break;
343
344     case PARSEOP_NAMESEG:
345
346         Op->Asl.AmlOpcodeLength = 0;
347         Op->Asl.AmlLength = 4;
348         Op->Asl.ExternalName = Op->Asl.Value.String;
349         break;
350
351     case PARSEOP_NAMESTRING:
352     case PARSEOP_METHODCALL:
353
354         if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED)
355         {
356             break;
357         }
358
359         Op->Asl.AmlOpcodeLength = 0;
360         Status = UtInternalizeName (Op->Asl.Value.String, &Buffer);
361         if (ACPI_FAILURE (Status))
362         {
363             DbgPrint (ASL_DEBUG_OUTPUT,
364                 "Failure from internalize name %X\n", Status);
365             break;
366         }
367
368         Op->Asl.ExternalName = Op->Asl.Value.String;
369         Op->Asl.Value.String = Buffer;
370         Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED;
371         Op->Asl.AmlLength = strlen (Buffer);
372
373         /*
374          * Check for single backslash reference to root,
375          * make it a null terminated string in the AML
376          */
377         if (Op->Asl.AmlLength == 1)
378         {
379             Op->Asl.AmlLength = 2;
380         }
381         break;
382
383     case PARSEOP_STRING_LITERAL:
384
385         Op->Asl.AmlOpcodeLength = 1;
386
387         /* Get null terminator */
388
389         Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1;
390         break;
391
392     case PARSEOP_PACKAGE_LENGTH:
393
394         Op->Asl.AmlOpcodeLength = 0;
395         Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op,
396             (UINT32) Op->Asl.Value.Integer);
397         break;
398
399     case PARSEOP_RAW_DATA:
400
401         Op->Asl.AmlOpcodeLength = 0;
402         break;
403
404     case PARSEOP_DEFAULT_ARG:
405     case PARSEOP_INCLUDE:
406     case PARSEOP_INCLUDE_END:
407
408         /* Ignore the "default arg" nodes, they are extraneous at this point */
409
410         break;
411
412     case PARSEOP_EXTERNAL:
413
414         if (Gbl_DoExternals == TRUE)
415         {
416             CgGenerateAmlOpcodeLength (Op);
417         }
418         break;
419
420     default:
421
422         CgGenerateAmlOpcodeLength (Op);
423         break;
424     }
425 }
426
427
428 #ifdef ACPI_OBSOLETE_FUNCTIONS
429 /*******************************************************************************
430  *
431  * FUNCTION:    LnAdjustLengthToRoot
432  *
433  * PARAMETERS:  Op      - Node whose Length was changed
434  *
435  * RETURN:      None.
436  *
437  * DESCRIPTION: Change the Subtree length of the given node, and bubble the
438  *              change all the way up to the root node. This allows for
439  *              last second changes to a package length (for example, if the
440  *              package length encoding gets shorter or longer.)
441  *
442  ******************************************************************************/
443
444 void
445 LnAdjustLengthToRoot (
446     ACPI_PARSE_OBJECT       *SubtreeOp,
447     UINT32                  LengthDelta)
448 {
449     ACPI_PARSE_OBJECT       *Op;
450
451
452     /* Adjust all subtree lengths up to the root */
453
454     Op = SubtreeOp->Asl.Parent;
455     while (Op)
456     {
457         Op->Asl.AmlSubtreeLength -= LengthDelta;
458         Op = Op->Asl.Parent;
459     }
460
461     /* Adjust the global table length */
462
463     Gbl_TableLength -= LengthDelta;
464 }
465 #endif