1 /****************************************************************************** 2 * 3 * Module Name: asllength - Tree walk to determine package and opcode lengths 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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 45 #include "aslcompiler.h" 46 #include "aslcompiler.y.h" 47 #include "amlcode.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 += (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_DEFINITIONBLOCK: 337 338 Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) + 339 Op->Asl.AmlSubtreeLength; 340 break; 341 342 case PARSEOP_NAMESEG: 343 344 Op->Asl.AmlOpcodeLength = 0; 345 Op->Asl.AmlLength = 4; 346 Op->Asl.ExternalName = Op->Asl.Value.String; 347 break; 348 349 case PARSEOP_NAMESTRING: 350 case PARSEOP_METHODCALL: 351 352 if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED) 353 { 354 break; 355 } 356 357 Op->Asl.AmlOpcodeLength = 0; 358 Status = UtInternalizeName (Op->Asl.Value.String, &Buffer); 359 if (ACPI_FAILURE (Status)) 360 { 361 DbgPrint (ASL_DEBUG_OUTPUT, 362 "Failure from internalize name %X\n", Status); 363 break; 364 } 365 366 Op->Asl.ExternalName = Op->Asl.Value.String; 367 Op->Asl.Value.String = Buffer; 368 Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED; 369 370 Op->Asl.AmlLength = strlen (Buffer); 371 372 /* 373 * Check for single backslash reference to root, 374 * make it a null terminated string in the AML 375 */ 376 if (Op->Asl.AmlLength == 1) 377 { 378 Op->Asl.AmlLength = 2; 379 } 380 break; 381 382 case PARSEOP_STRING_LITERAL: 383 384 Op->Asl.AmlOpcodeLength = 1; 385 386 /* Get null terminator */ 387 388 Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1; 389 break; 390 391 case PARSEOP_PACKAGE_LENGTH: 392 393 Op->Asl.AmlOpcodeLength = 0; 394 Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op, 395 (UINT32) Op->Asl.Value.Integer); 396 break; 397 398 case PARSEOP_RAW_DATA: 399 400 Op->Asl.AmlOpcodeLength = 0; 401 break; 402 403 case PARSEOP_DEFAULT_ARG: 404 case PARSEOP_EXTERNAL: 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 default: 413 414 CgGenerateAmlOpcodeLength (Op); 415 break; 416 } 417 } 418 419 420 #ifdef ACPI_OBSOLETE_FUNCTIONS 421 /******************************************************************************* 422 * 423 * FUNCTION: LnAdjustLengthToRoot 424 * 425 * PARAMETERS: Op - Node whose Length was changed 426 * 427 * RETURN: None. 428 * 429 * DESCRIPTION: Change the Subtree length of the given node, and bubble the 430 * change all the way up to the root node. This allows for 431 * last second changes to a package length (for example, if the 432 * package length encoding gets shorter or longer.) 433 * 434 ******************************************************************************/ 435 436 void 437 LnAdjustLengthToRoot ( 438 ACPI_PARSE_OBJECT *SubtreeOp, 439 UINT32 LengthDelta) 440 { 441 ACPI_PARSE_OBJECT *Op; 442 443 444 /* Adjust all subtree lengths up to the root */ 445 446 Op = SubtreeOp->Asl.Parent; 447 while (Op) 448 { 449 Op->Asl.AmlSubtreeLength -= LengthDelta; 450 Op = Op->Asl.Parent; 451 } 452 453 /* Adjust the global table length */ 454 455 Gbl_TableLength -= LengthDelta; 456 } 457 #endif