1 /****************************************************************************** 2 * 3 * Module Name: asloffset - Generate a C "offset table" for BIOS use. 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, 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 "acnamesp.h" 48 49 50 #define _COMPONENT ACPI_COMPILER 51 ACPI_MODULE_NAME ("asloffset") 52 53 54 /* Local prototypes */ 55 56 static void 57 LsEmitOffsetTableEntry ( 58 UINT32 FileId, 59 ACPI_NAMESPACE_NODE *Node, 60 UINT32 NamepathOffset, 61 UINT32 Offset, 62 char *OpName, 63 UINT64 Value, 64 UINT8 AmlOpcode, 65 UINT16 ParentOpcode); 66 67 68 /******************************************************************************* 69 * 70 * FUNCTION: LsAmlOffsetWalk 71 * 72 * PARAMETERS: ASL_WALK_CALLBACK 73 * 74 * RETURN: Status 75 * 76 * DESCRIPTION: Process one node during a offset table file generation. 77 * 78 * Three types of objects are currently emitted to the offset table: 79 * 1) Tagged (named) resource descriptors 80 * 2) Named integer objects with constant integer values 81 * 3) Named package objects 82 * 4) Operation Regions that have constant Offset (address) parameters 83 * 5) Control methods 84 * 85 * The offset table allows the BIOS to dynamically update the values of these 86 * objects at boot time. 87 * 88 ******************************************************************************/ 89 90 ACPI_STATUS 91 LsAmlOffsetWalk ( 92 ACPI_PARSE_OBJECT *Op, 93 UINT32 Level, 94 void *Context) 95 { 96 UINT32 FileId = (UINT32) ACPI_TO_INTEGER (Context); 97 ACPI_NAMESPACE_NODE *Node; 98 UINT32 Length; 99 UINT32 NamepathOffset; 100 UINT32 DataOffset; 101 ACPI_PARSE_OBJECT *NextOp; 102 103 104 /* Ignore actual data blocks for resource descriptors */ 105 106 if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DATA) 107 { 108 return (AE_OK); /* Do NOT update the global AML offset */ 109 } 110 111 /* We are only interested in named objects (have a namespace node) */ 112 113 Node = Op->Asl.Node; 114 if (!Node) 115 { 116 Gbl_CurrentAmlOffset += Op->Asl.FinalAmlLength; 117 return (AE_OK); 118 } 119 120 /* Named resource descriptor (has a descriptor tag) */ 121 122 if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE) && 123 (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC)) 124 { 125 LsEmitOffsetTableEntry (FileId, Node, 0, Gbl_CurrentAmlOffset, 126 Op->Asl.ParseOpName, 0, Op->Asl.Extra, AML_BUFFER_OP); 127 128 Gbl_CurrentAmlOffset += Op->Asl.FinalAmlLength; 129 return (AE_OK); 130 } 131 132 switch (Op->Asl.AmlOpcode) 133 { 134 case AML_NAME_OP: 135 136 /* Named object -- Name (NameString, DataRefObject) */ 137 138 if (!Op->Asl.Child) 139 { 140 FlPrintFile (FileId, "%s NO CHILD!\n", MsgBuffer); 141 return (AE_OK); 142 } 143 144 Length = Op->Asl.FinalAmlLength; 145 NamepathOffset = Gbl_CurrentAmlOffset + Length; 146 147 /* Get to the NameSeg/NamePath Op (and length of the name) */ 148 149 Op = Op->Asl.Child; 150 151 /* Get offset of last nameseg and the actual data */ 152 153 NamepathOffset = Gbl_CurrentAmlOffset + Length + 154 (Op->Asl.FinalAmlLength - ACPI_NAME_SIZE); 155 156 DataOffset = Gbl_CurrentAmlOffset + Length + 157 Op->Asl.FinalAmlLength; 158 159 /* Get actual value associated with the name */ 160 161 Op = Op->Asl.Next; 162 switch (Op->Asl.AmlOpcode) 163 { 164 case AML_BYTE_OP: 165 case AML_WORD_OP: 166 case AML_DWORD_OP: 167 case AML_QWORD_OP: 168 169 /* The +1 is to handle the integer size prefix (opcode) */ 170 171 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1), 172 Op->Asl.ParseOpName, Op->Asl.Value.Integer, 173 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); 174 break; 175 176 case AML_ONE_OP: 177 case AML_ONES_OP: 178 case AML_ZERO_OP: 179 180 /* For these, offset will point to the opcode */ 181 182 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 183 Op->Asl.ParseOpName, Op->Asl.Value.Integer, 184 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); 185 break; 186 187 case AML_PACKAGE_OP: 188 case AML_VAR_PACKAGE_OP: 189 190 /* Get the package element count */ 191 192 NextOp = Op->Asl.Child; 193 194 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 195 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 196 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); 197 break; 198 199 default: 200 break; 201 } 202 203 Gbl_CurrentAmlOffset += Length; 204 return (AE_OK); 205 206 case AML_REGION_OP: 207 208 /* OperationRegion (NameString, RegionSpace, RegionOffset, RegionLength) */ 209 210 Length = Op->Asl.FinalAmlLength; 211 212 /* Get the name/namepath node */ 213 214 NextOp = Op->Asl.Child; 215 216 /* Get offset of last nameseg and the actual data */ 217 218 NamepathOffset = Gbl_CurrentAmlOffset + Length + 219 (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); 220 221 DataOffset = Gbl_CurrentAmlOffset + Length + 222 (NextOp->Asl.FinalAmlLength + 1); 223 224 /* Get the SpaceId node, then the Offset (address) node */ 225 226 NextOp = NextOp->Asl.Next; 227 NextOp = NextOp->Asl.Next; 228 229 switch (NextOp->Asl.AmlOpcode) 230 { 231 /* 232 * We are only interested in integer constants that can be changed 233 * at boot time. Note, the One/Ones/Zero opcodes are considered 234 * non-changeable, so we ignore them here. 235 */ 236 case AML_BYTE_OP: 237 case AML_WORD_OP: 238 case AML_DWORD_OP: 239 case AML_QWORD_OP: 240 241 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1), 242 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 243 (UINT8) NextOp->Asl.AmlOpcode, AML_REGION_OP); 244 245 Gbl_CurrentAmlOffset += Length; 246 return (AE_OK); 247 248 default: 249 break; 250 } 251 break; 252 253 case AML_METHOD_OP: 254 255 /* Method (Namepath, ...) */ 256 257 Length = Op->Asl.FinalAmlLength; 258 259 /* Get the NameSeg/NamePath Op */ 260 261 NextOp = Op->Asl.Child; 262 263 /* Get offset of last nameseg and the actual data (flags byte) */ 264 265 NamepathOffset = Gbl_CurrentAmlOffset + Length + 266 (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); 267 268 DataOffset = Gbl_CurrentAmlOffset + Length + 269 NextOp->Asl.FinalAmlLength; 270 271 /* Get the flags byte Op */ 272 273 NextOp = NextOp->Asl.Next; 274 275 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 276 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 277 (UINT8) Op->Asl.AmlOpcode, AML_METHOD_OP); 278 break; 279 280 case AML_PROCESSOR_OP: 281 282 /* Processor (Namepath, ProcessorId, Address, Length) */ 283 284 Length = Op->Asl.FinalAmlLength; 285 NextOp = Op->Asl.Child; /* Get Namepath */ 286 287 /* Get offset of last nameseg and the actual data (PBlock address) */ 288 289 NamepathOffset = Gbl_CurrentAmlOffset + Length + 290 (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); 291 292 DataOffset = Gbl_CurrentAmlOffset + Length + 293 (NextOp->Asl.FinalAmlLength + 1); 294 295 NextOp = NextOp->Asl.Next; /* Get ProcessorID (BYTE) */ 296 NextOp = NextOp->Asl.Next; /* Get Address (DWORD) */ 297 298 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 299 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 300 (UINT8) AML_DWORD_OP, AML_PROCESSOR_OP); 301 break; 302 303 case AML_DEVICE_OP: 304 case AML_SCOPE_OP: 305 case AML_THERMAL_ZONE_OP: 306 307 /* Device/Scope/ThermalZone (Namepath) */ 308 309 Length = Op->Asl.FinalAmlLength; 310 NextOp = Op->Asl.Child; /* Get Namepath */ 311 312 /* Get offset of last nameseg */ 313 314 NamepathOffset = Gbl_CurrentAmlOffset + Length + 315 (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); 316 317 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, 0, 318 Op->Asl.ParseOpName, 0, (UINT8) 0, Op->Asl.AmlOpcode); 319 break; 320 321 default: 322 break; 323 } 324 325 Gbl_CurrentAmlOffset += Op->Asl.FinalAmlLength; 326 return (AE_OK); 327 } 328 329 330 /******************************************************************************* 331 * 332 * FUNCTION: LsEmitOffsetTableEntry 333 * 334 * PARAMETERS: FileId - ID of current listing file 335 * Node - Namespace node associated with the name 336 * Offset - Offset of the value within the AML table 337 * OpName - Name of the AML opcode 338 * Value - Current value of the AML field 339 * AmlOpcode - Opcode associated with the field 340 * ObjectType - ACPI object type 341 * 342 * RETURN: None 343 * 344 * DESCRIPTION: Emit a line of the offset table (-so option) 345 * 346 ******************************************************************************/ 347 348 static void 349 LsEmitOffsetTableEntry ( 350 UINT32 FileId, 351 ACPI_NAMESPACE_NODE *Node, 352 UINT32 NamepathOffset, 353 UINT32 Offset, 354 char *OpName, 355 UINT64 Value, 356 UINT8 AmlOpcode, 357 UINT16 ParentOpcode) 358 { 359 ACPI_BUFFER TargetPath; 360 ACPI_STATUS Status; 361 362 363 /* Get the full pathname to the namespace node */ 364 365 TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 366 Status = AcpiNsHandleToPathname (Node, &TargetPath); 367 if (ACPI_FAILURE (Status)) 368 { 369 return; 370 } 371 372 /* [1] - Skip the opening backslash for the path */ 373 374 strcpy (MsgBuffer, "\""); 375 strcat (MsgBuffer, &((char *) TargetPath.Pointer)[1]); 376 strcat (MsgBuffer, "\","); 377 ACPI_FREE (TargetPath.Pointer); 378 379 /* 380 * Max offset is 4G, constrained by 32-bit ACPI table length. 381 * Max Length for Integers is 8 bytes. 382 */ 383 FlPrintFile (FileId, 384 " {%-29s 0x%4.4X, 0x%8.8X, 0x%2.2X, 0x%8.8X, 0x%8.8X%8.8X}, /* %s */\n", 385 MsgBuffer, ParentOpcode, NamepathOffset, AmlOpcode, 386 Offset, ACPI_FORMAT_UINT64 (Value), OpName); 387 } 388 389 390 /******************************************************************************* 391 * 392 * FUNCTION: LsDoOffsetTableHeader, LsDoOffsetTableFooter 393 * 394 * PARAMETERS: FileId - ID of current listing file 395 * 396 * RETURN: None 397 * 398 * DESCRIPTION: Header and footer for the offset table file. 399 * 400 ******************************************************************************/ 401 402 void 403 LsDoOffsetTableHeader ( 404 UINT32 FileId) 405 { 406 407 FlPrintFile (FileId, 408 "#ifndef __AML_OFFSET_TABLE_H\n" 409 "#define __AML_OFFSET_TABLE_H\n\n"); 410 411 FlPrintFile (FileId, "typedef struct {\n" 412 " char *Pathname; /* Full pathname (from root) to the object */\n" 413 " unsigned short ParentOpcode; /* AML opcode for the parent object */\n" 414 " unsigned long NamesegOffset; /* Offset of last nameseg in the parent namepath */\n" 415 " unsigned char Opcode; /* AML opcode for the data */\n" 416 " unsigned long Offset; /* Offset for the data */\n" 417 " unsigned long long Value; /* Original value of the data (as applicable) */\n" 418 "} AML_OFFSET_TABLE_ENTRY;\n\n"); 419 420 FlPrintFile (FileId, 421 "#endif /* __AML_OFFSET_TABLE_H */\n\n"); 422 423 FlPrintFile (FileId, 424 "/*\n" 425 " * Information specific to the supported object types:\n" 426 " *\n" 427 " * Integers:\n" 428 " * Opcode is the integer prefix, indicates length of the data\n" 429 " * (One of: BYTE, WORD, DWORD, QWORD, ZERO, ONE, ONES)\n" 430 " * Offset points to the actual integer data\n" 431 " * Value is the existing value in the AML\n" 432 " *\n" 433 " * Packages:\n" 434 " * Opcode is the package or var_package opcode\n" 435 " * Offset points to the package opcode\n" 436 " * Value is the package element count\n" 437 " *\n" 438 " * Operation Regions:\n" 439 " * Opcode is the address integer prefix, indicates length of the data\n" 440 " * Offset points to the region address\n" 441 " * Value is the existing address value in the AML\n" 442 " *\n" 443 " * Control Methods:\n" 444 " * Offset points to the method flags byte\n" 445 " * Value is the existing flags value in the AML\n" 446 " *\n" 447 " * Processors:\n" 448 " * Offset points to the first byte of the PBlock Address\n" 449 " *\n" 450 " * Resource Descriptors:\n" 451 " * Opcode is the descriptor type\n" 452 " * Offset points to the start of the descriptor\n" 453 " *\n" 454 " * Scopes/Devices/ThermalZones:\n" 455 " * Nameseg offset only\n" 456 " */\n"); 457 458 FlPrintFile (FileId, 459 "AML_OFFSET_TABLE_ENTRY %s_%s_OffsetTable[] =\n{\n", 460 Gbl_TableSignature, Gbl_TableId); 461 } 462 463 464 void 465 LsDoOffsetTableFooter ( 466 UINT32 FileId) 467 { 468 469 FlPrintFile (FileId, 470 " {NULL,0,0,0,0,0} /* Table terminator */\n};\n\n"); 471 Gbl_CurrentAmlOffset = 0; 472 }