1 /****************************************************************************** 2 * 3 * Module Name: asllength - Tree walk to determine package and opcode lengths 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2020, 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 & 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 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 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