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