diff options
| -rw-r--r-- | tools/power/acpi/acpidump.c | 187 |
1 files changed, 89 insertions, 98 deletions
diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/acpidump.c index a63dee960311..07779871421c 100644 --- a/tools/power/acpi/acpidump.c +++ b/tools/power/acpi/acpidump.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * (c) Alexey Starikovskiy, Intel, 2005-2006. | 2 | * (c) Alexey Starikovskiy, Intel, 2005-2006. |
| 3 | * (c) Len Brown, Intel, 2007. | ||
| 4 | * All rights reserved. | 3 | * All rights reserved. |
| 5 | * | 4 | * |
| 6 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
| @@ -63,6 +62,8 @@ typedef long long s64; | |||
| 63 | #include <unistd.h> | 62 | #include <unistd.h> |
| 64 | #include <getopt.h> | 63 | #include <getopt.h> |
| 65 | 64 | ||
| 65 | #include <sys/types.h> | ||
| 66 | #include <dirent.h> | ||
| 66 | 67 | ||
| 67 | #include <acpi/acconfig.h> | 68 | #include <acpi/acconfig.h> |
| 68 | #include <acpi/platform/acenv.h> | 69 | #include <acpi/platform/acenv.h> |
| @@ -186,40 +187,6 @@ static void acpi_show_data(int fd, u8 * data, int size) | |||
| 186 | /* | 187 | /* |
| 187 | * Output ACPI table | 188 | * Output ACPI table |
| 188 | */ | 189 | */ |
| 189 | |||
| 190 | #define MAX_TABLES 128 | ||
| 191 | int next_table_dump; | ||
| 192 | u64 dumped_tables[MAX_TABLES]; | ||
| 193 | |||
| 194 | void | ||
| 195 | set_table_dumped(u64 address) { | ||
| 196 | if (next_table_dump >= MAX_TABLES) { | ||
| 197 | printf("increase MAX_TABLES\n"); | ||
| 198 | exit(1); | ||
| 199 | } | ||
| 200 | dumped_tables[next_table_dump++] = address; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* | ||
| 204 | * list the tables as they are dumped | ||
| 205 | * check the list so that they are not dumped twice. | ||
| 206 | * | ||
| 207 | * this is needed because we follow both the XSDT and RSDT | ||
| 208 | * which generally point to all duplicate tables | ||
| 209 | * except the FADT | ||
| 210 | */ | ||
| 211 | int | ||
| 212 | check_table_dumped(u64 address) { | ||
| 213 | int i; | ||
| 214 | |||
| 215 | for (i = 0; i < MAX_TABLES; ++i) { | ||
| 216 | if (address == dumped_tables[i]) | ||
| 217 | return 1; | ||
| 218 | if (dumped_tables[i] == 0) | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr) | 190 | static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr) |
| 224 | { | 191 | { |
| 225 | char buff[80]; | 192 | char buff[80]; |
| @@ -233,10 +200,6 @@ static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned lo | |||
| 233 | static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr) | 200 | static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr) |
| 234 | { | 201 | { |
| 235 | static int select_done = 0; | 202 | static int select_done = 0; |
| 236 | |||
| 237 | if (check_table_dumped((u64)addr)) | ||
| 238 | return; | ||
| 239 | |||
| 240 | if (!select_sig[0]) { | 203 | if (!select_sig[0]) { |
| 241 | if (print) { | 204 | if (print) { |
| 242 | acpi_show_table(fd, tbl, addr); | 205 | acpi_show_table(fd, tbl, addr); |
| @@ -255,7 +218,6 @@ static void write_table(int fd, struct acpi_table_header *tbl, unsigned long add | |||
| 255 | } | 218 | } |
| 256 | select_done = 1; | 219 | select_done = 1; |
| 257 | } | 220 | } |
| 258 | set_table_dumped((u64) addr); | ||
| 259 | } | 221 | } |
| 260 | 222 | ||
| 261 | static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) { | 223 | static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) { |
| @@ -312,26 +274,30 @@ no_facs: | |||
| 312 | write_table(fd, (struct acpi_table_header *)&x, xaddr); | 274 | write_table(fd, (struct acpi_table_header *)&x, xaddr); |
| 313 | } | 275 | } |
| 314 | 276 | ||
| 315 | 277 | static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp) | |
| 316 | static int acpi_dump_RSDT(int fd, struct acpi_rsdp_descriptor *rsdp) | ||
| 317 | { | 278 | { |
| 318 | struct acpi_table_header *sdt, *tbl = 0; | 279 | struct acpi_table_header *sdt, *tbl = 0; |
| 319 | int i, num; | 280 | int xsdt = 1, i, num; |
| 320 | char *offset; | 281 | char *offset; |
| 321 | unsigned long addr; | 282 | unsigned long addr; |
| 322 | 283 | if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { | |
| 323 | tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT"); | 284 | tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT"); |
| 285 | } | ||
| 286 | if (!tbl && rsdp->rsdt_physical_address) { | ||
| 287 | xsdt = 0; | ||
| 288 | tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT"); | ||
| 289 | } | ||
| 324 | if (!tbl) return 0; | 290 | if (!tbl) return 0; |
| 325 | |||
| 326 | sdt = malloc(tbl->length); | 291 | sdt = malloc(tbl->length); |
| 327 | memcpy(sdt, tbl, tbl->length); | 292 | memcpy(sdt, tbl, tbl->length); |
| 328 | acpi_unmap_table(tbl); | 293 | acpi_unmap_table(tbl); |
| 329 | if (checksum((u8 *)sdt, sdt->length)) | 294 | if (checksum((u8 *)sdt, sdt->length)) |
| 330 | fprintf(stderr, "Wrong checksum for %s!\n", "RSDT"); | 295 | fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT"); |
| 331 | num = (sdt->length - sizeof(struct acpi_table_header))/sizeof(u32); | 296 | num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32)); |
| 332 | offset = (char *)sdt + sizeof(struct acpi_table_header); | 297 | offset = (char *)sdt + sizeof(struct acpi_table_header); |
| 333 | for (i = 0; i < num; ++i, offset += sizeof(u32)) { | 298 | for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) { |
| 334 | addr = (unsigned long)(*(u32 *)offset); | 299 | addr = (xsdt) ? (unsigned long)(*(u64 *)offset): |
| 300 | (unsigned long)(*(u32 *)offset); | ||
| 335 | if (!addr) continue; | 301 | if (!addr) continue; |
| 336 | tbl = acpi_map_table(addr, 0); | 302 | tbl = acpi_map_table(addr, 0); |
| 337 | if (!tbl) continue; | 303 | if (!tbl) continue; |
| @@ -339,66 +305,92 @@ static int acpi_dump_RSDT(int fd, struct acpi_rsdp_descriptor *rsdp) | |||
| 339 | acpi_dump_FADT(fd, tbl, addr); | 305 | acpi_dump_FADT(fd, tbl, addr); |
| 340 | } else { | 306 | } else { |
| 341 | if (checksum((u8 *)tbl, tbl->length)) | 307 | if (checksum((u8 *)tbl, tbl->length)) |
| 342 | fprintf(stderr, "Wrong checksum for %.4s!\n", tbl->signature); | 308 | fprintf(stderr, "Wrong checksum for generic table!\n"); |
| 343 | write_table(fd, tbl, addr); | 309 | write_table(fd, tbl, addr); |
| 344 | } | 310 | } |
| 345 | acpi_unmap_table(tbl); | 311 | acpi_unmap_table(tbl); |
| 346 | if (connect) { | 312 | if (connect) { |
| 347 | (*(u32*)offset) = lseek(fd, 0, SEEK_CUR); | 313 | if (xsdt) |
| 314 | (*(u64*)offset) = lseek(fd, 0, SEEK_CUR); | ||
| 315 | else | ||
| 316 | (*(u32*)offset) = lseek(fd, 0, SEEK_CUR); | ||
| 348 | } | 317 | } |
| 349 | } | 318 | } |
| 350 | addr = (unsigned long)rsdp->rsdt_physical_address; | 319 | if (xsdt) { |
| 351 | if (connect) { | 320 | addr = (unsigned long)rsdp->xsdt_physical_address; |
| 352 | rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR); | 321 | if (connect) { |
| 322 | rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR); | ||
| 323 | } | ||
| 324 | } else { | ||
| 325 | addr = (unsigned long)rsdp->rsdt_physical_address; | ||
| 326 | if (connect) { | ||
| 327 | rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR); | ||
| 328 | } | ||
| 353 | } | 329 | } |
| 354 | write_table(fd, sdt, addr); | 330 | write_table(fd, sdt, addr); |
| 355 | free (sdt); | 331 | free (sdt); |
| 356 | return 1; | 332 | return 1; |
| 357 | } | 333 | } |
| 358 | 334 | ||
| 335 | #define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic" | ||
| 359 | 336 | ||
| 360 | static int acpi_dump_XSDT(int fd, struct acpi_rsdp_descriptor *rsdp) | 337 | static void acpi_dump_dynamic_SSDT(int fd) |
| 361 | { | 338 | { |
| 362 | struct acpi_table_header *sdt, *tbl = 0; | 339 | struct stat file_stat; |
| 363 | int i, num; | 340 | char filename[256], *ptr; |
| 364 | char *offset; | 341 | DIR *tabledir; |
| 365 | unsigned long addr; | 342 | struct dirent *entry; |
| 366 | if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { | 343 | FILE *fp; |
| 367 | tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT"); | 344 | int count, readcount, length; |
| 345 | struct acpi_table_header table_header, *ptable; | ||
| 346 | |||
| 347 | if (stat(DYNAMIC_SSDT, &file_stat) == -1) { | ||
| 348 | /* The directory doesn't exist */ | ||
| 349 | return; | ||
| 368 | } | 350 | } |
| 369 | if (!tbl) return 0; | 351 | tabledir = opendir(DYNAMIC_SSDT); |
| 370 | 352 | if(!tabledir){ | |
| 371 | sdt = malloc(tbl->length); | 353 | /*can't open the directory */ |
| 372 | memcpy(sdt, tbl, tbl->length); | 354 | return; |
| 373 | acpi_unmap_table(tbl); | 355 | } |
| 374 | if (checksum((u8 *)sdt, sdt->length)) | 356 | |
| 375 | fprintf(stderr, "Wrong checksum for %s!\n", "XSDT"); | 357 | while ((entry = readdir(tabledir)) != 0){ |
| 376 | num = (sdt->length - sizeof(struct acpi_table_header))/sizeof(u64); | 358 | /* skip the file of . /.. */ |
| 377 | offset = (char *)sdt + sizeof(struct acpi_table_header); | 359 | if (entry->d_name[0] == '.') |
| 378 | for (i = 0; i < num; ++i, offset += sizeof(u64)) { | 360 | continue; |
| 379 | addr = (unsigned long)(*(u64 *)offset); | 361 | |
| 380 | if (!addr) continue; | 362 | sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name); |
| 381 | tbl = acpi_map_table(addr, 0); | 363 | fp = fopen(filename, "r"); |
| 382 | if (!tbl) continue; | 364 | if (fp == NULL) { |
| 383 | if (!memcmp(tbl->signature, FADT_SIG, 4)) { | 365 | fprintf(stderr, "Can't open the file of %s\n", |
| 384 | acpi_dump_FADT(fd, tbl, addr); | 366 | filename); |
| 385 | } else { | 367 | continue; |
| 386 | if (checksum((u8 *)tbl, tbl->length)) | ||
| 387 | fprintf(stderr, "Wrong checksum for %.4s\n", tbl->signature); | ||
| 388 | write_table(fd, tbl, addr); | ||
| 389 | } | 368 | } |
| 390 | acpi_unmap_table(tbl); | 369 | /* Read the Table header to parse the table length */ |
| 391 | if (connect) { | 370 | count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); |
| 392 | (*(u64*)offset) = lseek(fd, 0, SEEK_CUR); | 371 | if (count < sizeof(table_header)) { |
| 372 | /* the length is lessn than ACPI table header. skip it */ | ||
| 373 | fclose(fp); | ||
| 374 | continue; | ||
| 393 | } | 375 | } |
| 376 | length = table_header.length; | ||
| 377 | ptr = malloc(table_header.length); | ||
| 378 | fseek(fp, 0, SEEK_SET); | ||
| 379 | readcount = 0; | ||
| 380 | while(!feof(fp) && readcount < length) { | ||
| 381 | count = fread(ptr + readcount, 1, 256, fp); | ||
| 382 | readcount += count; | ||
| 383 | } | ||
| 384 | fclose(fp); | ||
| 385 | ptable = (struct acpi_table_header *) ptr; | ||
| 386 | if (checksum((u8 *) ptable, ptable->length)) | ||
| 387 | fprintf(stderr, "Wrong checksum " | ||
| 388 | "for dynamic SSDT table!\n"); | ||
| 389 | write_table(fd, ptable, 0); | ||
| 390 | free(ptr); | ||
| 394 | } | 391 | } |
| 395 | addr = (unsigned long)rsdp->xsdt_physical_address; | 392 | closedir(tabledir); |
| 396 | if (connect) { | 393 | return; |
| 397 | rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR); | ||
| 398 | } | ||
| 399 | write_table(fd, sdt, addr); | ||
| 400 | free (sdt); | ||
| 401 | return 1; | ||
| 402 | } | 394 | } |
| 403 | 395 | ||
| 404 | static void usage(const char *progname) | 396 | static void usage(const char *progname) |
| @@ -518,6 +510,7 @@ int main(int argc, char **argv) | |||
| 518 | goto not_found; | 510 | goto not_found; |
| 519 | write(fd, raw, length); | 511 | write(fd, raw, length); |
| 520 | acpi_unmap_memory(raw, length); | 512 | acpi_unmap_memory(raw, length); |
| 513 | close(fd); | ||
| 521 | return 0; | 514 | return 0; |
| 522 | } | 515 | } |
| 523 | 516 | ||
| @@ -540,12 +533,7 @@ int main(int argc, char **argv) | |||
| 540 | if (connect) { | 533 | if (connect) { |
| 541 | lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET); | 534 | lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET); |
| 542 | } | 535 | } |
| 543 | if (rsdpx.revision > 1 && rsdpx.xsdt_physical_address) { | 536 | if (!acpi_dump_SDT(fd, &rsdpx)) |
| 544 | /* ACPIDUMP uses xsdt table */ | ||
| 545 | if (!acpi_dump_XSDT(fd, &rsdpx)) | ||
| 546 | goto not_found; | ||
| 547 | } | ||
| 548 | if (!acpi_dump_RSDT(fd, &rsdpx)) | ||
| 549 | goto not_found; | 537 | goto not_found; |
| 550 | if (connect) { | 538 | if (connect) { |
| 551 | lseek(fd, 0, SEEK_SET); | 539 | lseek(fd, 0, SEEK_SET); |
| @@ -560,8 +548,11 @@ int main(int argc, char **argv) | |||
| 560 | buff[0] = '\n'; | 548 | buff[0] = '\n'; |
| 561 | write(fd, buff, 1); | 549 | write(fd, buff, 1); |
| 562 | } | 550 | } |
| 551 | acpi_dump_dynamic_SSDT(fd); | ||
| 552 | close(fd); | ||
| 563 | return 0; | 553 | return 0; |
| 564 | not_found: | 554 | not_found: |
| 555 | close(fd); | ||
| 565 | fprintf(stderr, "ACPI tables were not found. If you know location " | 556 | fprintf(stderr, "ACPI tables were not found. If you know location " |
| 566 | "of RSD PTR table (from dmesg, etc), " | 557 | "of RSD PTR table (from dmesg, etc), " |
| 567 | "supply it with either --addr or -a option\n"); | 558 | "supply it with either --addr or -a option\n"); |
