asllength.c revision 1.1.1.5 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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #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