1 /****************************************************************************** 2 * 3 * Module Name: asloffset - Generate a C "offset table" for BIOS use. 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 "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 & OP_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 AslGbl_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 & OP_IS_RESOURCE_DESC)) 124 { 125 LsEmitOffsetTableEntry (FileId, Node, 0, AslGbl_CurrentAmlOffset, 126 Op->Asl.ParseOpName, 0, Op->Asl.Extra, AML_BUFFER_OP); 127 128 AslGbl_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", AslGbl_MsgBuffer); 141 return (AE_OK); 142 } 143 144 Length = Op->Asl.FinalAmlLength; 145 146 /* Get to the NameSeg/NamePath Op (and length of the name) */ 147 148 Op = Op->Asl.Child; 149 150 /* Get offset of last nameseg and the actual data */ 151 152 NamepathOffset = AslGbl_CurrentAmlOffset + Length + 153 (Op->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE); 154 155 DataOffset = AslGbl_CurrentAmlOffset + Length + 156 Op->Asl.FinalAmlLength; 157 158 /* Get actual value associated with the name */ 159 160 Op = Op->Asl.Next; 161 switch (Op->Asl.AmlOpcode) 162 { 163 case AML_BYTE_OP: 164 case AML_WORD_OP: 165 case AML_DWORD_OP: 166 case AML_QWORD_OP: 167 168 /* The +1 is to handle the integer size prefix (opcode) */ 169 170 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1), 171 Op->Asl.ParseOpName, Op->Asl.Value.Integer, 172 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); 173 break; 174 175 case AML_ONE_OP: 176 case AML_ONES_OP: 177 case AML_ZERO_OP: 178 179 /* For these, offset will point to the opcode */ 180 181 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 182 Op->Asl.ParseOpName, Op->Asl.Value.Integer, 183 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); 184 break; 185 186 case AML_PACKAGE_OP: 187 case AML_VARIABLE_PACKAGE_OP: 188 189 /* Get the package element count */ 190 191 NextOp = Op->Asl.Child; 192 193 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 194 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 195 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); 196 break; 197 198 default: 199 break; 200 } 201 202 AslGbl_CurrentAmlOffset += Length; 203 return (AE_OK); 204 205 case AML_REGION_OP: 206 207 /* OperationRegion (NameString, RegionSpace, RegionOffset, RegionLength) */ 208 209 Length = Op->Asl.FinalAmlLength; 210 211 /* Get the name/namepath node */ 212 213 NextOp = Op->Asl.Child; 214 215 /* Get offset of last nameseg and the actual data */ 216 217 NamepathOffset = AslGbl_CurrentAmlOffset + Length + 218 (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE); 219 220 DataOffset = AslGbl_CurrentAmlOffset + Length + 221 (NextOp->Asl.FinalAmlLength + 1); 222 223 /* Get the SpaceId node, then the Offset (address) node */ 224 225 NextOp = NextOp->Asl.Next; 226 NextOp = NextOp->Asl.Next; 227 228 switch (NextOp->Asl.AmlOpcode) 229 { 230 /* 231 * We are only interested in integer constants that can be changed 232 * at boot time. Note, the One/Ones/Zero opcodes are considered 233 * non-changeable, so we ignore them here. 234 */ 235 case AML_BYTE_OP: 236 case AML_WORD_OP: 237 case AML_DWORD_OP: 238 case AML_QWORD_OP: 239 240 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1), 241 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 242 (UINT8) NextOp->Asl.AmlOpcode, AML_REGION_OP); 243 244 AslGbl_CurrentAmlOffset += Length; 245 return (AE_OK); 246 247 default: 248 break; 249 } 250 break; 251 252 case AML_METHOD_OP: 253 254 /* Method (Namepath, ...) */ 255 256 Length = Op->Asl.FinalAmlLength; 257 258 /* Get the NameSeg/NamePath Op */ 259 260 NextOp = Op->Asl.Child; 261 262 /* Get offset of last nameseg and the actual data (flags byte) */ 263 264 NamepathOffset = AslGbl_CurrentAmlOffset + Length + 265 (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE); 266 267 DataOffset = AslGbl_CurrentAmlOffset + Length + 268 NextOp->Asl.FinalAmlLength; 269 270 /* Get the flags byte Op */ 271 272 NextOp = NextOp->Asl.Next; 273 274 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 275 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 276 (UINT8) Op->Asl.AmlOpcode, AML_METHOD_OP); 277 break; 278 279 case AML_PROCESSOR_OP: 280 281 /* Processor (Namepath, ProcessorId, Address, Length) */ 282 283 Length = Op->Asl.FinalAmlLength; 284 NextOp = Op->Asl.Child; /* Get Namepath */ 285 286 /* Get offset of last nameseg and the actual data (PBlock address) */ 287 288 NamepathOffset = AslGbl_CurrentAmlOffset + Length + 289 (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE); 290 291 DataOffset = AslGbl_CurrentAmlOffset + Length + 292 (NextOp->Asl.FinalAmlLength + 1); 293 294 NextOp = NextOp->Asl.Next; /* Get ProcessorID (BYTE) */ 295 NextOp = NextOp->Asl.Next; /* Get Address (DWORD) */ 296 297 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, 298 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, 299 (UINT8) AML_DWORD_OP, AML_PROCESSOR_OP); 300 break; 301 302 case AML_DEVICE_OP: 303 case AML_SCOPE_OP: 304 case AML_THERMAL_ZONE_OP: 305 306 /* Device/Scope/ThermalZone (Namepath) */ 307 308 Length = Op->Asl.FinalAmlLength; 309 NextOp = Op->Asl.Child; /* Get Namepath */ 310 311 /* Get offset of last nameseg */ 312 313 NamepathOffset = AslGbl_CurrentAmlOffset + Length + 314 (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE); 315 316 LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, 0, 317 Op->Asl.ParseOpName, 0, (UINT8) 0, Op->Asl.AmlOpcode); 318 break; 319 320 default: 321 break; 322 } 323 324 AslGbl_CurrentAmlOffset += Op->Asl.FinalAmlLength; 325 return (AE_OK); 326 } 327 328 329 /******************************************************************************* 330 * 331 * FUNCTION: LsEmitOffsetTableEntry 332 * 333 * PARAMETERS: FileId - ID of current listing file 334 * Node - Namespace node associated with the name 335 * Offset - Offset of the value within the AML table 336 * OpName - Name of the AML opcode 337 * Value - Current value of the AML field 338 * AmlOpcode - Opcode associated with the field 339 * ObjectType - ACPI object type 340 * 341 * RETURN: None 342 * 343 * DESCRIPTION: Emit a line of the offset table (-so option) 344 * 345 ******************************************************************************/ 346 347 static void 348 LsEmitOffsetTableEntry ( 349 UINT32 FileId, 350 ACPI_NAMESPACE_NODE *Node, 351 UINT32 NamepathOffset, 352 UINT32 Offset, 353 char *OpName, 354 UINT64 Value, 355 UINT8 AmlOpcode, 356 UINT16 ParentOpcode) 357 { 358 ACPI_BUFFER TargetPath; 359 ACPI_STATUS Status; 360 361 362 /* Get the full pathname to the namespace node */ 363 364 TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 365 Status = AcpiNsHandleToPathname (Node, &TargetPath, FALSE); 366 if (ACPI_FAILURE (Status)) 367 { 368 return; 369 } 370 371 /* [1] - Skip the opening backslash for the path */ 372 373 strcpy (AslGbl_MsgBuffer, "\""); 374 strcat (AslGbl_MsgBuffer, &((char *) TargetPath.Pointer)[1]); 375 strcat (AslGbl_MsgBuffer, "\","); 376 ACPI_FREE (TargetPath.Pointer); 377 378 /* 379 * Max offset is 4G, constrained by 32-bit ACPI table length. 380 * Max Length for Integers is 8 bytes. 381 */ 382 FlPrintFile (FileId, 383 " {%-29s 0x%4.4X, 0x%8.8X, 0x%2.2X, 0x%8.8X, 0x%8.8X%8.8X}, /* %s */\n", 384 AslGbl_MsgBuffer, ParentOpcode, NamepathOffset, AmlOpcode, 385 Offset, ACPI_FORMAT_UINT64 (Value), OpName); 386 } 387 388 389 /******************************************************************************* 390 * 391 * FUNCTION: LsDoOffsetTableHeader, LsDoOffsetTableFooter 392 * 393 * PARAMETERS: FileId - ID of current listing file 394 * 395 * RETURN: None 396 * 397 * DESCRIPTION: Header and footer for the offset table file. 398 * 399 ******************************************************************************/ 400 401 void 402 LsDoOffsetTableHeader ( 403 UINT32 FileId) 404 { 405 406 FlPrintFile (FileId, 407 "#ifndef __AML_OFFSET_TABLE_H\n" 408 "#define __AML_OFFSET_TABLE_H\n\n"); 409 410 FlPrintFile (FileId, "typedef struct {\n" 411 " char *Pathname; /* Full pathname (from root) to the object */\n" 412 " unsigned short ParentOpcode; /* AML opcode for the parent object */\n" 413 " unsigned long NamesegOffset; /* Offset of last nameseg in the parent namepath */\n" 414 " unsigned char Opcode; /* AML opcode for the data */\n" 415 " unsigned long Offset; /* Offset for the data */\n" 416 " unsigned long long Value; /* Original value of the data (as applicable) */\n" 417 "} AML_OFFSET_TABLE_ENTRY;\n\n"); 418 419 FlPrintFile (FileId, 420 "#endif /* __AML_OFFSET_TABLE_H */\n\n"); 421 422 FlPrintFile (FileId, 423 "/*\n" 424 " * Information specific to the supported object types:\n" 425 " *\n" 426 " * Integers:\n" 427 " * Opcode is the integer prefix, indicates length of the data\n" 428 " * (One of: BYTE, WORD, DWORD, QWORD, ZERO, ONE, ONES)\n" 429 " * Offset points to the actual integer data\n" 430 " * Value is the existing value in the AML\n" 431 " *\n" 432 " * Packages:\n" 433 " * Opcode is the package or var_package opcode\n" 434 " * Offset points to the package opcode\n" 435 " * Value is the package element count\n" 436 " *\n" 437 " * Operation Regions:\n" 438 " * Opcode is the address integer prefix, indicates length of the data\n" 439 " * Offset points to the region address\n" 440 " * Value is the existing address value in the AML\n" 441 " *\n" 442 " * Control Methods:\n" 443 " * Offset points to the method flags byte\n" 444 " * Value is the existing flags value in the AML\n" 445 " *\n" 446 " * Processors:\n" 447 " * Offset points to the first byte of the PBlock Address\n" 448 " *\n" 449 " * Resource Descriptors:\n" 450 " * Opcode is the descriptor type\n" 451 " * Offset points to the start of the descriptor\n" 452 " *\n" 453 " * Scopes/Devices/ThermalZones:\n" 454 " * Nameseg offset only\n" 455 " */\n"); 456 457 FlPrintFile (FileId, 458 "AML_OFFSET_TABLE_ENTRY %s_%s_OffsetTable[] =\n{\n", 459 AslGbl_TableSignature, AslGbl_TableId); 460 } 461 462 463 void 464 LsDoOffsetTableFooter ( 465 UINT32 FileId) 466 { 467 468 FlPrintFile (FileId, 469 " {NULL,0,0,0,0,0} /* Table terminator */\n};\n\n"); 470 AslGbl_CurrentAmlOffset = 0; 471 } 472