xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/asllength.c (revision 046a29855e04359424fd074e8313af6b6be8cfb6)
1 /******************************************************************************
2  *
3  * Module Name: asllength - Tree walk to determine package and opcode lengths
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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
LnInitLengthsWalk(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)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
LnPackageLengthWalk(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)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
CgGetPackageLenByteCount(ACPI_PARSE_OBJECT * Op,UINT32 PackageLength)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
CgGenerateAmlOpcodeLength(ACPI_PARSE_OBJECT * Op)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 & OP_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
CgGenerateAmlLengths(ACPI_PARSE_OBJECT * Op)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         AslGbl_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 & OP_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 |= OP_NAME_INTERNALIZED;
371         Op->Asl.AmlLength = strlen (Buffer);
372 
373         /*
374          * Check for single backslash reference to root or reference to a name
375          * consisting of only prefix (^) characters. Make it a null terminated
376          * string in the AML.
377          */
378         if (Op->Asl.AmlLength == 1 || UtNameContainsAllPrefix(Op))
379         {
380             Op->Asl.AmlLength++;
381         }
382         break;
383 
384     case PARSEOP_STRING_LITERAL:
385 
386         Op->Asl.AmlOpcodeLength = 1;
387 
388         /* Get null terminator */
389 
390         Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1;
391         break;
392 
393     case PARSEOP_PACKAGE_LENGTH:
394 
395         Op->Asl.AmlOpcodeLength = 0;
396         Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op,
397             (UINT32) Op->Asl.Value.Integer);
398         break;
399 
400     case PARSEOP_RAW_DATA:
401 
402         Op->Asl.AmlOpcodeLength = 0;
403         break;
404 
405     case PARSEOP_DEFAULT_ARG:
406     case PARSEOP_INCLUDE:
407     case PARSEOP_INCLUDE_END:
408 
409         /* Ignore the "default arg" nodes, they are extraneous at this point */
410 
411         break;
412 
413     case PARSEOP_EXTERNAL:
414 
415         CgGenerateAmlOpcodeLength (Op);
416         break;
417 
418     default:
419 
420         CgGenerateAmlOpcodeLength (Op);
421         break;
422     }
423 }
424 
425 
426 #ifdef ACPI_OBSOLETE_FUNCTIONS
427 /*******************************************************************************
428  *
429  * FUNCTION:    LnAdjustLengthToRoot
430  *
431  * PARAMETERS:  Op      - Node whose Length was changed
432  *
433  * RETURN:      None.
434  *
435  * DESCRIPTION: Change the Subtree length of the given node, and bubble the
436  *              change all the way up to the root node. This allows for
437  *              last second changes to a package length (for example, if the
438  *              package length encoding gets shorter or longer.)
439  *
440  ******************************************************************************/
441 
442 void
LnAdjustLengthToRoot(ACPI_PARSE_OBJECT * SubtreeOp,UINT32 LengthDelta)443 LnAdjustLengthToRoot (
444     ACPI_PARSE_OBJECT       *SubtreeOp,
445     UINT32                  LengthDelta)
446 {
447     ACPI_PARSE_OBJECT       *Op;
448 
449 
450     /* Adjust all subtree lengths up to the root */
451 
452     Op = SubtreeOp->Asl.Parent;
453     while (Op)
454     {
455         Op->Asl.AmlSubtreeLength -= LengthDelta;
456         Op = Op->Asl.Parent;
457     }
458 
459     /* Adjust the global table length */
460 
461     AslGbl_TableLength -= LengthDelta;
462 }
463 #endif
464