1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2/****************************************************************************** 3 * 4 * Module Name: apdump - Dump routines for ACPI tables (acpidump) 5 * 6 * Copyright (C) 2000 - 2023, Intel Corp. 7 * 8 *****************************************************************************/ 9 10#include "acpidump.h" 11 12/* Local prototypes */ 13 14static int 15ap_dump_table_buffer(struct acpi_table_header *table, 16 u32 instance, acpi_physical_address address); 17 18/****************************************************************************** 19 * 20 * FUNCTION: ap_is_valid_header 21 * 22 * PARAMETERS: table - Pointer to table to be validated 23 * 24 * RETURN: TRUE if the header appears to be valid. FALSE otherwise 25 * 26 * DESCRIPTION: Check for a valid ACPI table header 27 * 28 ******************************************************************************/ 29 30u8 ap_is_valid_header(struct acpi_table_header *table) 31{ 32 33 if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) { 34 35 /* Make sure signature is all ASCII and a valid ACPI name */ 36 37 if (!acpi_ut_valid_nameseg(table->signature)) { 38 fprintf(stderr, 39 "Table signature (0x%8.8X) is invalid\n", 40 *(u32 *)table->signature); 41 return (FALSE); 42 } 43 44 /* Check for minimum table length */ 45 46 if (table->length < sizeof(struct acpi_table_header)) { 47 fprintf(stderr, "Table length (0x%8.8X) is invalid\n", 48 table->length); 49 return (FALSE); 50 } 51 } 52 53 return (TRUE); 54} 55 56/****************************************************************************** 57 * 58 * FUNCTION: ap_is_valid_checksum 59 * 60 * PARAMETERS: table - Pointer to table to be validated 61 * 62 * RETURN: TRUE if the checksum appears to be valid. FALSE otherwise. 63 * 64 * DESCRIPTION: Check for a valid ACPI table checksum. 65 * 66 ******************************************************************************/ 67 68u8 ap_is_valid_checksum(struct acpi_table_header *table) 69{ 70 acpi_status status; 71 struct acpi_table_rsdp *rsdp; 72 73 if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { 74 /* 75 * Checksum for RSDP. 76 * Note: Other checksums are computed during the table dump. 77 */ 78 rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); 79 status = acpi_tb_validate_rsdp(rsdp); 80 } else { 81 /* We don't have to check for a CDAT here, since CDAT is not in the RSDT/XSDT */ 82 83 status = acpi_ut_verify_checksum(table, table->length); 84 } 85 86 if (ACPI_FAILURE(status)) { 87 fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n", 88 table->signature); 89 } 90 91 return (AE_OK); 92} 93 94/****************************************************************************** 95 * 96 * FUNCTION: ap_get_table_length 97 * 98 * PARAMETERS: table - Pointer to the table 99 * 100 * RETURN: Table length 101 * 102 * DESCRIPTION: Obtain table length according to table signature. 103 * 104 ******************************************************************************/ 105 106u32 ap_get_table_length(struct acpi_table_header *table) 107{ 108 struct acpi_table_rsdp *rsdp; 109 110 /* Check if table is valid */ 111 112 if (!ap_is_valid_header(table)) { 113 return (0); 114 } 115 116 if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { 117 rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); 118 return (acpi_tb_get_rsdp_length(rsdp)); 119 } 120 121 /* Normal ACPI table */ 122 123 return (table->length); 124} 125 126/****************************************************************************** 127 * 128 * FUNCTION: ap_dump_table_buffer 129 * 130 * PARAMETERS: table - ACPI table to be dumped 131 * instance - ACPI table instance no. to be dumped 132 * address - Physical address of the table 133 * 134 * RETURN: None 135 * 136 * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a 137 * header that is compatible with the acpi_xtract utility. 138 * 139 ******************************************************************************/ 140 141static int 142ap_dump_table_buffer(struct acpi_table_header *table, 143 u32 instance, acpi_physical_address address) 144{ 145 u32 table_length; 146 147 table_length = ap_get_table_length(table); 148 149 /* Print only the header if requested */ 150 151 if (gbl_summary_mode) { 152 acpi_tb_print_table_header(address, table); 153 return (0); 154 } 155 156 /* Dump to binary file if requested */ 157 158 if (gbl_binary_mode) { 159 return (ap_write_to_binary_file(table, instance)); 160 } 161 162 /* 163 * Dump the table with header for use with acpixtract utility. 164 * Note: simplest to just always emit a 64-bit address. acpi_xtract 165 * utility can handle this. 166 */ 167 fprintf(gbl_output_file, "%4.4s @ 0x%8.8X%8.8X\n", 168 table->signature, ACPI_FORMAT_UINT64(address)); 169 170 acpi_ut_dump_buffer_to_file(gbl_output_file, 171 ACPI_CAST_PTR(u8, table), table_length, 172 DB_BYTE_DISPLAY, 0); 173 fprintf(gbl_output_file, "\n"); 174 return (0); 175} 176 177/****************************************************************************** 178 * 179 * FUNCTION: ap_dump_all_tables 180 * 181 * PARAMETERS: None 182 * 183 * RETURN: Status 184 * 185 * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the 186 * tables that we can possibly get). 187 * 188 ******************************************************************************/ 189 190int ap_dump_all_tables(void) 191{ 192 struct acpi_table_header *table; 193 u32 instance = 0; 194 acpi_physical_address address; 195 acpi_status status; 196 int table_status; 197 u32 i; 198 199 /* Get and dump all available ACPI tables */ 200 201 for (i = 0; i < AP_MAX_ACPI_FILES; i++) { 202 status = 203 acpi_os_get_table_by_index(i, &table, &instance, &address); 204 if (ACPI_FAILURE(status)) { 205 206 /* AE_LIMIT means that no more tables are available */ 207 208 if (status == AE_LIMIT) { 209 return (0); 210 } else if (i == 0) { 211 fprintf(stderr, 212 "Could not get ACPI tables, %s\n", 213 acpi_format_exception(status)); 214 return (-1); 215 } else { 216 fprintf(stderr, 217 "Could not get ACPI table at index %u, %s\n", 218 i, acpi_format_exception(status)); 219 continue; 220 } 221 } 222 223 table_status = ap_dump_table_buffer(table, instance, address); 224 ACPI_FREE(table); 225 226 if (table_status) { 227 break; 228 } 229 } 230 231 /* Something seriously bad happened if the loop terminates here */ 232 233 return (-1); 234} 235 236/****************************************************************************** 237 * 238 * FUNCTION: ap_dump_table_by_address 239 * 240 * PARAMETERS: ascii_address - Address for requested ACPI table 241 * 242 * RETURN: Status 243 * 244 * DESCRIPTION: Get an ACPI table via a physical address and dump it. 245 * 246 ******************************************************************************/ 247 248int ap_dump_table_by_address(char *ascii_address) 249{ 250 acpi_physical_address address; 251 struct acpi_table_header *table; 252 acpi_status status; 253 int table_status; 254 u64 long_address; 255 256 /* Convert argument to an integer physical address */ 257 258 status = acpi_ut_strtoul64(ascii_address, &long_address); 259 if (ACPI_FAILURE(status)) { 260 fprintf(stderr, "%s: Could not convert to a physical address\n", 261 ascii_address); 262 return (-1); 263 } 264 265 address = (acpi_physical_address)long_address; 266 status = acpi_os_get_table_by_address(address, &table); 267 if (ACPI_FAILURE(status)) { 268 fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n", 269 ACPI_FORMAT_UINT64(address), 270 acpi_format_exception(status)); 271 return (-1); 272 } 273 274 table_status = ap_dump_table_buffer(table, 0, address); 275 ACPI_FREE(table); 276 return (table_status); 277} 278 279/****************************************************************************** 280 * 281 * FUNCTION: ap_dump_table_by_name 282 * 283 * PARAMETERS: signature - Requested ACPI table signature 284 * 285 * RETURN: Status 286 * 287 * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles 288 * multiple tables with the same signature (SSDTs). 289 * 290 ******************************************************************************/ 291 292int ap_dump_table_by_name(char *signature) 293{ 294 char local_signature[ACPI_NAMESEG_SIZE + 1]; 295 u32 instance; 296 struct acpi_table_header *table; 297 acpi_physical_address address; 298 acpi_status status; 299 int table_status; 300 301 if (strlen(signature) != ACPI_NAMESEG_SIZE) { 302 fprintf(stderr, 303 "Invalid table signature [%s]: must be exactly 4 characters\n", 304 signature); 305 return (-1); 306 } 307 308 /* Table signatures are expected to be uppercase */ 309 310 strcpy(local_signature, signature); 311 acpi_ut_strupr(local_signature); 312 313 /* To be friendly, handle tables whose signatures do not match the name */ 314 315 if (ACPI_COMPARE_NAMESEG(local_signature, "FADT")) { 316 strcpy(local_signature, ACPI_SIG_FADT); 317 } else if (ACPI_COMPARE_NAMESEG(local_signature, "MADT")) { 318 strcpy(local_signature, ACPI_SIG_MADT); 319 } 320 321 /* Dump all instances of this signature (to handle multiple SSDTs) */ 322 323 for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) { 324 status = acpi_os_get_table_by_name(local_signature, instance, 325 &table, &address); 326 if (ACPI_FAILURE(status)) { 327 328 /* AE_LIMIT means that no more tables are available */ 329 330 if (status == AE_LIMIT) { 331 return (0); 332 } 333 334 fprintf(stderr, 335 "Could not get ACPI table with signature [%s], %s\n", 336 local_signature, acpi_format_exception(status)); 337 return (-1); 338 } 339 340 table_status = ap_dump_table_buffer(table, instance, address); 341 ACPI_FREE(table); 342 343 if (table_status) { 344 break; 345 } 346 } 347 348 /* Something seriously bad happened if the loop terminates here */ 349 350 return (-1); 351} 352 353/****************************************************************************** 354 * 355 * FUNCTION: ap_dump_table_from_file 356 * 357 * PARAMETERS: pathname - File containing the binary ACPI table 358 * 359 * RETURN: Status 360 * 361 * DESCRIPTION: Dump an ACPI table from a binary file 362 * 363 ******************************************************************************/ 364 365int ap_dump_table_from_file(char *pathname) 366{ 367 struct acpi_table_header *table; 368 u32 file_size = 0; 369 int table_status = -1; 370 371 /* Get the entire ACPI table from the file */ 372 373 table = ap_get_table_from_file(pathname, &file_size); 374 if (!table) { 375 return (-1); 376 } 377 378 if (!acpi_ut_valid_nameseg(table->signature)) { 379 fprintf(stderr, 380 "No valid ACPI signature was found in input file %s\n", 381 pathname); 382 } 383 384 /* File must be at least as long as the table length */ 385 386 if (table->length > file_size) { 387 fprintf(stderr, 388 "Table length (0x%X) is too large for input file (0x%X) %s\n", 389 table->length, file_size, pathname); 390 goto exit; 391 } 392 393 if (gbl_verbose_mode) { 394 fprintf(stderr, 395 "Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n", 396 pathname, table->signature, file_size, file_size); 397 } 398 399 table_status = ap_dump_table_buffer(table, 0, 0); 400 401exit: 402 ACPI_FREE(table); 403 return (table_status); 404} 405