1 /****************************************************************************** 2 * 3 * Module Name: axutils - Utility functions for acpixtract tool. 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 "acpixtract.h" 45 46 47 /******************************************************************************* 48 * 49 * FUNCTION: AxCheckAscii 50 * 51 * PARAMETERS: Name - Ascii string, at least as long as Count 52 * Count - Number of characters to check 53 * 54 * RETURN: None 55 * 56 * DESCRIPTION: Ensure that the requested number of characters are printable 57 * Ascii characters. Sets non-printable and null chars to <space>. 58 * 59 ******************************************************************************/ 60 61 void 62 AxCheckAscii ( 63 char *Name, 64 int Count) 65 { 66 int i; 67 68 69 for (i = 0; i < Count; i++) 70 { 71 if (!Name[i] || !isprint ((int) Name[i])) 72 { 73 Name[i] = ' '; 74 } 75 } 76 } 77 78 79 /******************************************************************************* 80 * 81 * FUNCTION: AxIsFileAscii 82 * 83 * PARAMETERS: Handle - To open input file 84 * 85 * RETURN: TRUE if file is entirely ASCII and printable 86 * 87 * DESCRIPTION: Verify that the input file is entirely ASCII. 88 * 89 ******************************************************************************/ 90 91 BOOLEAN 92 AxIsFileAscii ( 93 FILE *Handle) 94 { 95 UINT8 Byte; 96 UINT32 Offset = 0; 97 98 99 /* Read the entire file */ 100 101 fseek (Handle, 0, SEEK_SET); 102 while (fread (&Byte, 1, 1, Handle) == 1) 103 { 104 /* 105 * Ignore null characters. Some acpidump-type utilities insert 106 * a few of these, probably a bug in the utility. As long as these 107 * characters are in lines that are tossed (non-data), they 108 * won't cause a problem. 109 */ 110 if (!Byte) 111 { 112 continue; 113 } 114 115 /* Check for an ASCII character */ 116 117 if (!ACPI_IS_ASCII (Byte)) 118 { 119 printf ("Found non-ascii char: %2.2X at file offset %u (0x%X)\n", 120 Byte, Offset, Offset); 121 if (!Gbl_ForceExtraction) 122 { 123 goto ErrorExit; 124 } 125 } 126 127 /* Ensure character is either printable or a "space" char */ 128 129 else if (!isprint (Byte) && !isspace (Byte)) 130 { 131 printf ("Found non-printable char: %2.2X at file offset %u (0x%X)\n", 132 Byte, Offset, Offset); 133 if (!Gbl_ForceExtraction) 134 { 135 goto ErrorExit; 136 } 137 } 138 139 Offset++; 140 } 141 142 /* File is OK (100% ASCII) */ 143 144 fseek (Handle, 0, SEEK_SET); 145 return (TRUE); 146 147 ErrorExit: 148 149 printf ("File appears to be binary " 150 "(contains non-text or non-ascii characters)\n"); 151 fseek (Handle, 0, SEEK_SET); 152 return (FALSE); 153 } 154 155 156 /****************************************************************************** 157 * 158 * FUNCTION: AxIsEmptyLine 159 * 160 * PARAMETERS: Buffer - Line from input file 161 * 162 * RETURN: TRUE if line is empty (zero or more blanks only) 163 * 164 * DESCRIPTION: Determine if an input line is empty. 165 * 166 ******************************************************************************/ 167 168 BOOLEAN 169 AxIsEmptyLine ( 170 char *Buffer) 171 { 172 173 /* Skip all spaces */ 174 175 while (*Buffer == ' ') 176 { 177 Buffer++; 178 } 179 180 /* Line is empty when a Unix or DOS-style line terminator is found. */ 181 182 if ((*Buffer == '\r') || (*Buffer == '\n')) 183 { 184 return (1); 185 } 186 187 return (0); 188 } 189 190 191 /****************************************************************************** 192 * 193 * FUNCTION: AxIsHexDataLine 194 * 195 * PARAMETERS: None 196 * 197 * RETURN: Status. 1 if the table header is valid, 0 otherwise. 198 * 199 * DESCRIPTION: Check for a valid line of hex data of the form: 200 * 201 * 00a0: 0c 00 00 00 03 00 00 00 43 48 41 35 0c 00 00 00 ........CHA5.... 202 * 203 ******************************************************************************/ 204 205 BOOLEAN 206 AxIsHexDataLine ( 207 void) 208 { 209 210 if (AxIsEmptyLine (Gbl_LineBuffer) || 211 (Gbl_LineBuffer[0] != ' ')) 212 { 213 return (FALSE); 214 } 215 216 if (!strstr (Gbl_LineBuffer, ": ")) 217 { 218 /* Not valid data line */ 219 220 return (FALSE); 221 } 222 223 return (TRUE); 224 } 225 226 227 /****************************************************************************** 228 * 229 * FUNCTION: AxIsDataBlockHeader 230 * 231 * PARAMETERS: None 232 * 233 * RETURN: Status. 1 if the table header is valid, 0 otherwise. 234 * 235 * DESCRIPTION: Check if the ACPI table identifier in the input acpidump text 236 * file is valid (of the form: <sig> @ <addr>). 237 * 238 ******************************************************************************/ 239 240 BOOLEAN 241 AxIsDataBlockHeader ( 242 void) 243 { 244 245 /* Ignore lines that are too short to be header lines */ 246 247 if (strlen (Gbl_LineBuffer) < AX_MIN_BLOCK_HEADER_LENGTH) 248 { 249 return (FALSE); 250 } 251 252 /* Ignore empty lines and lines that start with a space */ 253 254 if (AxIsEmptyLine (Gbl_LineBuffer) || 255 (Gbl_LineBuffer[0] == ' ')) 256 { 257 return (FALSE); 258 } 259 260 /* 261 * Ignore lines that are not headers of the form <sig> @ <addr>. 262 * Basically, just look for the '@' symbol, surrounded by spaces. 263 * 264 * Examples of headers that must be supported: 265 * 266 * DSDT @ 0x737e4000 267 * XSDT @ 0x737f2fff 268 * RSD PTR @ 0xf6cd0 269 * SSDT @ (nil) 270 */ 271 if (!AX_IS_TABLE_BLOCK_HEADER) 272 { 273 return (FALSE); 274 } 275 276 AxNormalizeSignature (Gbl_LineBuffer); 277 return (TRUE); 278 } 279 280 281 /******************************************************************************* 282 * 283 * FUNCTION: AxNormalizeSignature 284 * 285 * PARAMETERS: Name - Ascii string containing an ACPI signature 286 * 287 * RETURN: None 288 * 289 * DESCRIPTION: Change "RSD PTR" to "RSDP" 290 * 291 ******************************************************************************/ 292 293 void 294 AxNormalizeSignature ( 295 char *Signature) 296 { 297 298 if (!strncmp (Signature, "RSD ", 4)) 299 { 300 Signature[3] = 'P'; 301 } 302 } 303 304 305 /****************************************************************************** 306 * 307 * FUNCTION: AxConvertToBinary 308 * 309 * PARAMETERS: InputLine - One line from the input acpidump file 310 * OutputData - Where the converted data is returned 311 * 312 * RETURN: The number of bytes actually converted 313 * 314 * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes) 315 * 316 * NOTE: Assumes the input data line has been validated to be of the form: 317 * 318 * 0010: 48 53 57 55 4c 54 2d 52 01 00 00 00 49 4e 54 4c HSWULT-R....INTL 319 * 320 ******************************************************************************/ 321 322 int 323 AxConvertToBinary ( 324 char *InputLine, 325 unsigned char *OutputData) 326 { 327 char *ColonDelimiter; 328 int BytesConverted; 329 int Converted[16]; 330 int i; 331 332 333 /* 334 * Terminate input line immediately after the data. Otherwise, the 335 * second line below will not scan correctly. 336 * 337 * This handles varying lengths for the offset: line prefix. This support 338 * for tables larger than 1mb was added 05/2018. 339 * 340 * 00b0: 03 00 00 00 43 48 41 36 0c 00 00 00 03 00 00 00 ....CHA6........ 341 * 00c0: 43 48 41 37 CHA7 342 * 343 * 012340b0: 03 00 00 00 43 48 41 36 0c 00 00 00 03 00 00 00 ....CHA6........ 344 * 012340c0: 43 48 41 37 CHA7 345 */ 346 ColonDelimiter = strchr (InputLine, ':'); 347 ColonDelimiter [AX_HEX_DATA_LENGTH] = 0; 348 349 /* 350 * Convert one line of table data, of the form: 351 * <offset>: <up to 16 bytes of hex data> <ASCII representation> <newline> 352 * 353 * Example: 354 * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08 _SB_LNKD........ 355 */ 356 BytesConverted = sscanf (InputLine, 357 "%*s %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X", 358 &Converted[0], &Converted[1], &Converted[2], &Converted[3], 359 &Converted[4], &Converted[5], &Converted[6], &Converted[7], 360 &Converted[8], &Converted[9], &Converted[10], &Converted[11], 361 &Converted[12], &Converted[13], &Converted[14], &Converted[15]); 362 363 if (BytesConverted == EOF) 364 { 365 printf ("EOF while converting ASCII line to binary\n"); 366 return (-1); 367 } 368 369 /* 370 * Pack converted data into a byte array. 371 * Note: BytesConverted == 0 is acceptable. 372 */ 373 for (i = 0; i < BytesConverted; i++) 374 { 375 OutputData[i] = (unsigned char) Converted[i]; 376 } 377 378 return (BytesConverted); 379 } 380 381 382 /****************************************************************************** 383 * 384 * FUNCTION: AxCountTableInstances 385 * 386 * PARAMETERS: InputPathname - Filename for acpidump file 387 * Signature - Requested signature to count 388 * 389 * RETURN: The number of instances of the signature 390 * 391 * DESCRIPTION: Count the instances of tables with the given signature within 392 * the input acpidump file. 393 * 394 ******************************************************************************/ 395 396 unsigned int 397 AxCountTableInstances ( 398 char *InputPathname, 399 char *Signature) 400 { 401 FILE *InputFile; 402 unsigned int Instances = 0; 403 404 405 InputFile = fopen (InputPathname, "r"); 406 if (!InputFile) 407 { 408 printf ("Could not open input file %s\n", InputPathname); 409 return (0); 410 } 411 412 /* Count the number of instances of this signature */ 413 414 while (fgets (Gbl_InstanceBuffer, AX_LINE_BUFFER_SIZE, InputFile)) 415 { 416 /* Ignore empty lines and lines that start with a space */ 417 418 if (AxIsEmptyLine (Gbl_InstanceBuffer) || 419 (Gbl_InstanceBuffer[0] == ' ')) 420 { 421 continue; 422 } 423 424 AxNormalizeSignature (Gbl_InstanceBuffer); 425 if (ACPI_COMPARE_NAMESEG (Gbl_InstanceBuffer, Signature)) 426 { 427 Instances++; 428 } 429 } 430 431 fclose (InputFile); 432 return (Instances); 433 } 434 435 436 /****************************************************************************** 437 * 438 * FUNCTION: AxGetNextInstance 439 * 440 * PARAMETERS: InputPathname - Filename for acpidump file 441 * Signature - Requested ACPI signature 442 * 443 * RETURN: The next instance number for this signature. Zero if this 444 * is the first instance of this signature. 445 * 446 * DESCRIPTION: Get the next instance number of the specified table. If this 447 * is the first instance of the table, create a new instance 448 * block. Note: only SSDT and PSDT tables can have multiple 449 * instances. 450 * 451 ******************************************************************************/ 452 453 unsigned int 454 AxGetNextInstance ( 455 char *InputPathname, 456 char *Signature) 457 { 458 AX_TABLE_INFO *Info; 459 460 461 Info = Gbl_TableListHead; 462 while (Info) 463 { 464 if (*(UINT32 *) Signature == Info->Signature) 465 { 466 break; 467 } 468 469 Info = Info->Next; 470 } 471 472 if (!Info) 473 { 474 /* Signature not found, create new table info block */ 475 476 Info = malloc (sizeof (AX_TABLE_INFO)); 477 if (!Info) 478 { 479 printf ("Could not allocate memory (0x%X bytes)\n", 480 (unsigned int) sizeof (AX_TABLE_INFO)); 481 exit (0); 482 } 483 484 Info->Signature = *(UINT32 *) Signature; 485 Info->Instances = AxCountTableInstances (InputPathname, Signature); 486 Info->NextInstance = 1; 487 Info->Next = Gbl_TableListHead; 488 Gbl_TableListHead = Info; 489 } 490 491 if (Info->Instances > 1) 492 { 493 return (Info->NextInstance++); 494 } 495 496 return (0); 497 } 498 499 500 /****************************************************************************** 501 * 502 * FUNCTION: AxConvertAndWrite 503 * 504 * PARAMETERS: OutputFile - Where to write the binary data 505 * ThisSignature - Signature of current ACPI table 506 * 507 * RETURN: Length of the converted line 508 * 509 * DESCRIPTION: Convert one line of input hex ascii text to binary, and write 510 * the binary data to the table output file. 511 * 512 * NOTE: Assumes the input data line has been validated to be of the form: 513 * 514 * 0010: 48 53 57 55 4c 54 2d 52 01 00 00 00 49 4e 54 4c HSWULT-R....INTL 515 * 516 ******************************************************************************/ 517 518 int 519 AxConvertAndWrite ( 520 FILE *OutputFile, 521 char *ThisSignature) 522 { 523 int BytesWritten; 524 int BytesConverted; 525 526 527 /* Convert one line of ascii hex data to binary */ 528 529 BytesConverted = AxConvertToBinary (Gbl_LineBuffer, Gbl_BinaryData); 530 if (BytesConverted == EOF) 531 { 532 return (EOF); 533 } 534 if (!BytesConverted) 535 { 536 return (0); 537 } 538 539 /* Write the binary data */ 540 541 BytesWritten = fwrite (Gbl_BinaryData, 1, BytesConverted, OutputFile); 542 if (BytesWritten != BytesConverted) 543 { 544 printf ("Error while writing file %s\n", Gbl_OutputFilename); 545 return (-1); 546 } 547 548 return (BytesWritten); 549 } 550 551 552 /****************************************************************************** 553 * 554 * FUNCTION: AxDumpTableHeader 555 * 556 * PARAMETERS: Header - A binary ACPI table header 557 * 558 * RETURN: None 559 * 560 * DESCRIPTION: Display the contents of a standard ACPI table header 561 * 562 ******************************************************************************/ 563 564 void 565 AxDumpTableHeader ( 566 unsigned char *Header) 567 { 568 ACPI_TABLE_HEADER *TableHeader = (ACPI_TABLE_HEADER *) (void *) Header; 569 ACPI_TABLE_RSDP *Rsdp = (ACPI_TABLE_RSDP *) (void *) Header; 570 ACPI_TABLE_FACS *Facs = (ACPI_TABLE_FACS *) (void *) Header; 571 572 573 /* RSDP has an oddball signature and header */ 574 575 if (!strncmp (TableHeader->Signature, "RSD PTR ", 8)) 576 { 577 AxCheckAscii ((char *) &Header[9], 6); 578 579 Gbl_TableCount++; 580 printf (" %.2u) %5.4s 0x%8.8X 0x%2.2X \"%6.6s\"\n", 581 Gbl_TableCount, "RSDP", Rsdp->Length, Rsdp->Revision, Rsdp->OemId); 582 return; 583 } 584 585 if (!AcpiUtValidNameseg (TableHeader->Signature)) 586 { 587 return; 588 } 589 590 /* Signature and Table length */ 591 592 Gbl_TableCount++; 593 printf (" %.2u) %5.4s 0x%8.8X", Gbl_TableCount, TableHeader->Signature, 594 TableHeader->Length); 595 596 /* FACS has only signature and length */ 597 598 if (ACPI_COMPARE_NAMESEG (TableHeader->Signature, "FACS")) 599 { 600 printf (" 0x%2.2X\n", Facs->Version); 601 return; 602 } 603 604 /* OEM IDs and Compiler IDs */ 605 606 AxCheckAscii (TableHeader->OemId, 6); 607 AxCheckAscii (TableHeader->OemTableId, 8); 608 AxCheckAscii (TableHeader->AslCompilerId, 4); 609 610 printf ( 611 " 0x%2.2X \"%6.6s\" \"%8.8s\" 0x%8.8X" 612 " \"%4.4s\" 0x%8.8X\n", 613 TableHeader->Revision, TableHeader->OemId, 614 TableHeader->OemTableId, TableHeader->OemRevision, 615 TableHeader->AslCompilerId, TableHeader->AslCompilerRevision); 616 } 617 618 619 #ifdef _AX_FUTURE_ENHANCEMENTS 620 621 /* Possible enhancement to validate table lengths */ 622 623 void 624 AxCheckTableLengths ( 625 UINT32 ByteCount, 626 UINT32 AmlByteCount) 627 { 628 629 if (AmlByteCount == 0) 630 { 631 return; 632 } 633 634 if (ByteCount == 0) 635 { 636 return; 637 } 638 639 if ((ByteCount < sizeof (ACPI_TABLE_HEADER)) && 640 (ByteCount >= ACPI_NAMESEG_SIZE)) 641 { 642 printf (" : (Table too short for an ACPI table)"); 643 } 644 645 else if (ByteCount != AmlByteCount) 646 { 647 printf (" : (Hex data length mismatch with AML length 0x%X)", 648 AmlByteCount); 649 } 650 651 printf ("\n"); 652 } 653 #endif 654