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