diff options
author | Len Brown <len.brown@intel.com> | 2012-09-22 23:09:15 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-09-22 23:09:15 -0400 |
commit | d4bb1c90c850c5163f28b1c04d16c5d85aaaf815 (patch) | |
tree | f5b0918d472bd0c2ea48bff49034fdcff643df69 /tools/power | |
parent | 39a55ff2c34a11ab9bbc8ba6f4dfb5d366cb2532 (diff) |
tools/power/acpi/acpidump: version 20101221 - find dynamic tables in sysfs
This is unchanged version 20101221, plus a small bit in
DEFINE_ALTERNATE_TYPES to enable building with latest kernel headers.
This version finds dynamic tables exported by Linux in
/sys/firmware/acpi/tables/dynamic
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools/power')
-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"); |