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