acpidump.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*
  2. * (c) Alexey Starikovskiy, Intel, 2005-2006.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions, and the following disclaimer,
  10. * without modification.
  11. * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  12. * substantially similar to the "NO WARRANTY" disclaimer below
  13. * ("Disclaimer") and any redistribution must be conditioned upon
  14. * including a substantially similar Disclaimer requirement for further
  15. * binary redistribution.
  16. * 3. Neither the names of the above-listed copyright holders nor the names
  17. * of any contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * Alternatively, this software may be distributed under the terms of the
  21. * GNU General Public License ("GPL") version 2 as published by the Free
  22. * Software Foundation.
  23. *
  24. * NO WARRANTY
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  28. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  33. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  34. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35. * POSSIBILITY OF SUCH DAMAGES.
  36. */
  37. #ifdef DEFINE_ALTERNATE_TYPES
  38. /* hack to enable building old application with new headers -lenb */
  39. #define acpi_fadt_descriptor acpi_table_fadt
  40. #define acpi_rsdp_descriptor acpi_table_rsdp
  41. #define DSDT_SIG ACPI_SIG_DSDT
  42. #define FACS_SIG ACPI_SIG_FACS
  43. #define FADT_SIG ACPI_SIG_FADT
  44. #define xfirmware_ctrl Xfacs
  45. #define firmware_ctrl facs
  46. typedef int s32;
  47. typedef unsigned char u8;
  48. typedef unsigned short u16;
  49. typedef unsigned int u32;
  50. typedef unsigned long long u64;
  51. typedef long long s64;
  52. #endif
  53. #include <sys/mman.h>
  54. #include <sys/types.h>
  55. #include <sys/stat.h>
  56. #include <fcntl.h>
  57. #include <stdio.h>
  58. #include <string.h>
  59. #include <unistd.h>
  60. #include <getopt.h>
  61. #include <sys/types.h>
  62. #include <dirent.h>
  63. #include <acpi/acconfig.h>
  64. #include <acpi/platform/acenv.h>
  65. #include <acpi/actypes.h>
  66. #include <acpi/actbl.h>
  67. static inline u8 checksum(u8 * buffer, u32 length)
  68. {
  69. u8 sum = 0, *i = buffer;
  70. buffer += length;
  71. for (; i < buffer; sum += *(i++));
  72. return sum;
  73. }
  74. static unsigned long psz, addr, length;
  75. static int print, connect, skip;
  76. static u8 select_sig[4];
  77. static unsigned long read_efi_systab( void )
  78. {
  79. char buffer[80];
  80. unsigned long addr;
  81. FILE *f = fopen("/sys/firmware/efi/systab", "r");
  82. if (f) {
  83. while (fgets(buffer, 80, f)) {
  84. if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1)
  85. return addr;
  86. }
  87. fclose(f);
  88. }
  89. return 0;
  90. }
  91. static u8 *acpi_map_memory(unsigned long where, unsigned length)
  92. {
  93. unsigned long offset;
  94. u8 *there;
  95. int fd = open("/dev/mem", O_RDONLY);
  96. if (fd < 0) {
  97. fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n");
  98. exit(1);
  99. }
  100. offset = where % psz;
  101. there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE,
  102. fd, where - offset);
  103. close(fd);
  104. if (there == MAP_FAILED) return 0;
  105. return (there + offset);
  106. }
  107. static void acpi_unmap_memory(u8 * there, unsigned length)
  108. {
  109. unsigned long offset = (unsigned long)there % psz;
  110. munmap(there - offset, length + offset);
  111. }
  112. static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig)
  113. {
  114. unsigned size;
  115. struct acpi_table_header *tbl = (struct acpi_table_header *)
  116. acpi_map_memory(where, sizeof(struct acpi_table_header));
  117. if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0;
  118. size = tbl->length;
  119. acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header));
  120. return (struct acpi_table_header *)acpi_map_memory(where, size);
  121. }
  122. static void acpi_unmap_table(struct acpi_table_header *tbl)
  123. {
  124. acpi_unmap_memory((u8 *)tbl, tbl->length);
  125. }
  126. static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length)
  127. {
  128. struct acpi_rsdp_descriptor *rsdp;
  129. u8 *i, *end = begin + length;
  130. /* Search from given start address for the requested length */
  131. for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) {
  132. /* The signature and checksum must both be correct */
  133. if (memcmp((char *)i, "RSD PTR ", 8)) continue;
  134. rsdp = (struct acpi_rsdp_descriptor *)i;
  135. /* Signature matches, check the appropriate checksum */
  136. if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ?
  137. ACPI_RSDP_CHECKSUM_LENGTH :
  138. ACPI_RSDP_XCHECKSUM_LENGTH))
  139. /* Checksum valid, we have found a valid RSDP */
  140. return rsdp;
  141. }
  142. /* Searched entire block, no RSDP was found */
  143. return 0;
  144. }
  145. /*
  146. * Output data
  147. */
  148. static void acpi_show_data(int fd, u8 * data, int size)
  149. {
  150. char buffer[256];
  151. int len;
  152. int i, remain = size;
  153. while (remain > 0) {
  154. len = snprintf(buffer, 256, " %04x:", size - remain);
  155. for (i = 0; i < 16 && i < remain; i++) {
  156. len +=
  157. snprintf(&buffer[len], 256 - len, " %02x", data[i]);
  158. }
  159. for (; i < 16; i++) {
  160. len += snprintf(&buffer[len], 256 - len, " ");
  161. }
  162. len += snprintf(&buffer[len], 256 - len, " ");
  163. for (i = 0; i < 16 && i < remain; i++) {
  164. buffer[len++] = (isprint(data[i])) ? data[i] : '.';
  165. }
  166. buffer[len++] = '\n';
  167. write(fd, buffer, len);
  168. data += 16;
  169. remain -= 16;
  170. }
  171. }
  172. /*
  173. * Output ACPI table
  174. */
  175. static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr)
  176. {
  177. char buff[80];
  178. int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr);
  179. write(fd, buff, len);
  180. acpi_show_data(fd, (u8 *) table, table->length);
  181. buff[0] = '\n';
  182. write(fd, buff, 1);
  183. }
  184. static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr)
  185. {
  186. static int select_done = 0;
  187. if (!select_sig[0]) {
  188. if (print) {
  189. acpi_show_table(fd, tbl, addr);
  190. } else {
  191. write(fd, tbl, tbl->length);
  192. }
  193. } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) {
  194. if (skip > 0) {
  195. --skip;
  196. return;
  197. }
  198. if (print) {
  199. acpi_show_table(fd, tbl, addr);
  200. } else {
  201. write(fd, tbl, tbl->length);
  202. }
  203. select_done = 1;
  204. }
  205. }
  206. static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) {
  207. struct acpi_fadt_descriptor x;
  208. unsigned long addr;
  209. size_t len = sizeof(struct acpi_fadt_descriptor);
  210. if (len > tbl->length) len = tbl->length;
  211. memcpy(&x, tbl, len);
  212. x.header.length = len;
  213. if (checksum((u8 *)tbl, len)) {
  214. fprintf(stderr, "Wrong checksum for FADT!\n");
  215. }
  216. if (x.header.length >= 148 && x.Xdsdt) {
  217. addr = (unsigned long)x.Xdsdt;
  218. if (connect) {
  219. x.Xdsdt = lseek(fd, 0, SEEK_CUR);
  220. }
  221. } else if (x.header.length >= 44 && x.dsdt) {
  222. addr = (unsigned long)x.dsdt;
  223. if (connect) {
  224. x.dsdt = lseek(fd, 0, SEEK_CUR);
  225. }
  226. } else {
  227. fprintf(stderr, "No DSDT in FADT!\n");
  228. goto no_dsdt;
  229. }
  230. tbl = acpi_map_table(addr, DSDT_SIG);
  231. if (!tbl) goto no_dsdt;
  232. if (checksum((u8 *)tbl, tbl->length))
  233. fprintf(stderr, "Wrong checksum for DSDT!\n");
  234. write_table(fd, tbl, addr);
  235. acpi_unmap_table(tbl);
  236. no_dsdt:
  237. if (x.header.length >= 140 && x.xfirmware_ctrl) {
  238. addr = (unsigned long)x.xfirmware_ctrl;
  239. if (connect) {
  240. x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR);
  241. }
  242. } else if (x.header.length >= 40 && x.firmware_ctrl) {
  243. addr = (unsigned long)x.firmware_ctrl;
  244. if (connect) {
  245. x.firmware_ctrl = lseek(fd, 0, SEEK_CUR);
  246. }
  247. } else {
  248. fprintf(stderr, "No FACS in FADT!\n");
  249. goto no_facs;
  250. }
  251. tbl = acpi_map_table(addr, FACS_SIG);
  252. if (!tbl) goto no_facs;
  253. /* do not checksum FACS */
  254. write_table(fd, tbl, addr);
  255. acpi_unmap_table(tbl);
  256. no_facs:
  257. write_table(fd, (struct acpi_table_header *)&x, xaddr);
  258. }
  259. static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp)
  260. {
  261. struct acpi_table_header *sdt, *tbl = 0;
  262. int xsdt = 1, i, num;
  263. char *offset;
  264. unsigned long addr;
  265. if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
  266. tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT");
  267. }
  268. if (!tbl && rsdp->rsdt_physical_address) {
  269. xsdt = 0;
  270. tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT");
  271. }
  272. if (!tbl) return 0;
  273. sdt = malloc(tbl->length);
  274. memcpy(sdt, tbl, tbl->length);
  275. acpi_unmap_table(tbl);
  276. if (checksum((u8 *)sdt, sdt->length))
  277. fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT");
  278. num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32));
  279. offset = (char *)sdt + sizeof(struct acpi_table_header);
  280. for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) {
  281. addr = (xsdt) ? (unsigned long)(*(u64 *)offset):
  282. (unsigned long)(*(u32 *)offset);
  283. if (!addr) continue;
  284. tbl = acpi_map_table(addr, 0);
  285. if (!tbl) continue;
  286. if (!memcmp(tbl->signature, FADT_SIG, 4)) {
  287. acpi_dump_FADT(fd, tbl, addr);
  288. } else {
  289. if (checksum((u8 *)tbl, tbl->length))
  290. fprintf(stderr, "Wrong checksum for generic table!\n");
  291. write_table(fd, tbl, addr);
  292. }
  293. acpi_unmap_table(tbl);
  294. if (connect) {
  295. if (xsdt)
  296. (*(u64*)offset) = lseek(fd, 0, SEEK_CUR);
  297. else
  298. (*(u32*)offset) = lseek(fd, 0, SEEK_CUR);
  299. }
  300. }
  301. if (xsdt) {
  302. addr = (unsigned long)rsdp->xsdt_physical_address;
  303. if (connect) {
  304. rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR);
  305. }
  306. } else {
  307. addr = (unsigned long)rsdp->rsdt_physical_address;
  308. if (connect) {
  309. rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR);
  310. }
  311. }
  312. write_table(fd, sdt, addr);
  313. free (sdt);
  314. return 1;
  315. }
  316. #define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic"
  317. static void acpi_dump_dynamic_SSDT(int fd)
  318. {
  319. struct stat file_stat;
  320. char filename[256], *ptr;
  321. DIR *tabledir;
  322. struct dirent *entry;
  323. FILE *fp;
  324. int count, readcount, length;
  325. struct acpi_table_header table_header, *ptable;
  326. if (stat(DYNAMIC_SSDT, &file_stat) == -1) {
  327. /* The directory doesn't exist */
  328. return;
  329. }
  330. tabledir = opendir(DYNAMIC_SSDT);
  331. if(!tabledir){
  332. /*can't open the directory */
  333. return;
  334. }
  335. while ((entry = readdir(tabledir)) != 0){
  336. /* skip the file of . /.. */
  337. if (entry->d_name[0] == '.')
  338. continue;
  339. sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name);
  340. fp = fopen(filename, "r");
  341. if (fp == NULL) {
  342. fprintf(stderr, "Can't open the file of %s\n",
  343. filename);
  344. continue;
  345. }
  346. /* Read the Table header to parse the table length */
  347. count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp);
  348. if (count < sizeof(table_header)) {
  349. /* the length is lessn than ACPI table header. skip it */
  350. fclose(fp);
  351. continue;
  352. }
  353. length = table_header.length;
  354. ptr = malloc(table_header.length);
  355. fseek(fp, 0, SEEK_SET);
  356. readcount = 0;
  357. while(!feof(fp) && readcount < length) {
  358. count = fread(ptr + readcount, 1, 256, fp);
  359. readcount += count;
  360. }
  361. fclose(fp);
  362. ptable = (struct acpi_table_header *) ptr;
  363. if (checksum((u8 *) ptable, ptable->length))
  364. fprintf(stderr, "Wrong checksum "
  365. "for dynamic SSDT table!\n");
  366. write_table(fd, ptable, 0);
  367. free(ptr);
  368. }
  369. closedir(tabledir);
  370. return;
  371. }
  372. static void usage(const char *progname)
  373. {
  374. puts("Usage:");
  375. printf("%s [--addr 0x1234][--table DSDT][--output filename]"
  376. "[--binary][--length 0x456][--help]\n", progname);
  377. puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address");
  378. puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature");
  379. puts("\t--output filename or -o filename -- redirect output from stdin to filename");
  380. puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format");
  381. puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory"
  382. "\n\t\tregion without trying to understand it's contents");
  383. puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one");
  384. puts("\t--help or -h -- this help message");
  385. exit(0);
  386. }
  387. static struct option long_options[] = {
  388. {"addr", 1, 0, 0},
  389. {"table", 1, 0, 0},
  390. {"output", 1, 0, 0},
  391. {"binary", 0, 0, 0},
  392. {"length", 1, 0, 0},
  393. {"skip", 1, 0, 0},
  394. {"help", 0, 0, 0},
  395. {0, 0, 0, 0}
  396. };
  397. int main(int argc, char **argv)
  398. {
  399. int option_index, c, fd;
  400. u8 *raw;
  401. struct acpi_rsdp_descriptor rsdpx, *x = 0;
  402. char *filename = 0;
  403. char buff[80];
  404. memset(select_sig, 0, 4);
  405. print = 1;
  406. connect = 0;
  407. addr = length = 0;
  408. skip = 0;
  409. while (1) {
  410. option_index = 0;
  411. c = getopt_long(argc, argv, "a:t:o:bl:s:h",
  412. long_options, &option_index);
  413. if (c == -1)
  414. break;
  415. switch (c) {
  416. case 0:
  417. switch (option_index) {
  418. case 0:
  419. addr = strtoul(optarg, (char **)NULL, 16);
  420. break;
  421. case 1:
  422. memcpy(select_sig, optarg, 4);
  423. break;
  424. case 2:
  425. filename = optarg;
  426. break;
  427. case 3:
  428. print = 0;
  429. break;
  430. case 4:
  431. length = strtoul(optarg, (char **)NULL, 16);
  432. break;
  433. case 5:
  434. skip = strtoul(optarg, (char **)NULL, 10);
  435. break;
  436. case 6:
  437. usage(argv[0]);
  438. exit(0);
  439. }
  440. break;
  441. case 'a':
  442. addr = strtoul(optarg, (char **)NULL, 16);
  443. break;
  444. case 't':
  445. memcpy(select_sig, optarg, 4);
  446. break;
  447. case 'o':
  448. filename = optarg;
  449. break;
  450. case 'b':
  451. print = 0;
  452. break;
  453. case 'l':
  454. length = strtoul(optarg, (char **)NULL, 16);
  455. break;
  456. case 's':
  457. skip = strtoul(optarg, (char **)NULL, 10);
  458. break;
  459. case 'h':
  460. usage(argv[0]);
  461. exit(0);
  462. default:
  463. printf("Unknown option!\n");
  464. usage(argv[0]);
  465. exit(0);
  466. }
  467. }
  468. fd = STDOUT_FILENO;
  469. if (filename) {
  470. fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
  471. if (fd < 0)
  472. return fd;
  473. }
  474. if (!select_sig[0] && !print) {
  475. connect = 1;
  476. }
  477. psz = sysconf(_SC_PAGESIZE);
  478. if (length && addr) {
  479. /* We know length and address, it means we just want a memory dump */
  480. if (!(raw = acpi_map_memory(addr, length)))
  481. goto not_found;
  482. write(fd, raw, length);
  483. acpi_unmap_memory(raw, length);
  484. close(fd);
  485. return 0;
  486. }
  487. length = sizeof(struct acpi_rsdp_descriptor);
  488. if (!addr) {
  489. addr = read_efi_systab();
  490. if (!addr) {
  491. addr = ACPI_HI_RSDP_WINDOW_BASE;
  492. length = ACPI_HI_RSDP_WINDOW_SIZE;
  493. }
  494. }
  495. if (!(raw = acpi_map_memory(addr, length)) ||
  496. !(x = acpi_scan_for_rsdp(raw, length)))
  497. goto not_found;
  498. /* Find RSDP and print all found tables */
  499. memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor));
  500. acpi_unmap_memory(raw, length);
  501. if (connect) {
  502. lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET);
  503. }
  504. if (!acpi_dump_SDT(fd, &rsdpx))
  505. goto not_found;
  506. if (connect) {
  507. lseek(fd, 0, SEEK_SET);
  508. write(fd, x, (rsdpx.revision < 2) ?
  509. ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
  510. } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) {
  511. addr += (long)x - (long)raw;
  512. length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr);
  513. write(fd, buff, length);
  514. acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ?
  515. ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
  516. buff[0] = '\n';
  517. write(fd, buff, 1);
  518. }
  519. acpi_dump_dynamic_SSDT(fd);
  520. close(fd);
  521. return 0;
  522. not_found:
  523. close(fd);
  524. fprintf(stderr, "ACPI tables were not found. If you know location "
  525. "of RSD PTR table (from dmesg, etc), "
  526. "supply it with either --addr or -a option\n");
  527. return 1;
  528. }