aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2012-09-22 22:33:19 -0400
committerLen Brown <len.brown@intel.com>2012-09-22 22:33:19 -0400
commit0efea7b6b2ac2a6e7d7b223a6c70299099285103 (patch)
tree1e986cac111fe407839efa46b1d881a5c3dfa9d6 /tools/power
parent28a33cbc24e4256c143dce96c7d93bf423229f92 (diff)
tools/power/acpi/acpidump: version 20051111
This is unchanged version 20051111, plus a small bit in DEFINE_ALTERNATE_TYPES to enable building with latest kernel headers. Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools/power')
-rw-r--r--tools/power/acpi/Makefile15
-rw-r--r--tools/power/acpi/acpidump.c472
2 files changed, 487 insertions, 0 deletions
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
new file mode 100644
index 00000000000..faf5ff5c8f8
--- /dev/null
+++ b/tools/power/acpi/Makefile
@@ -0,0 +1,15 @@
1PROG= acpidump
2SRCS= acpidump.c
3KERNEL_INCLUDE := ../../../include
4CFLAGS += -Wall -Wstrict-prototypes -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE)
5
6all: acpidump
7
8acpidump : $(SRCS)
9 $(CC) $(CFLAGS) $(SRCS) -o $(PROG)
10
11CLEANFILES= $(PROG)
12
13clean :
14 rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~
15
diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/acpidump.c
new file mode 100644
index 00000000000..3f0a9da6df9
--- /dev/null
+++ b/tools/power/acpi/acpidump.c
@@ -0,0 +1,472 @@
1/*
2 * (c) Alexey Starikovskiy, Intel, 2005.
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
38#ifdef DEFINE_ALTERNATE_TYPES
39/* hack to enable building old application with new headers -lenb */
40#define acpi_fadt_descriptor acpi_table_fadt
41#define acpi_rsdp_descriptor acpi_table_rsdp
42#define DSDT_SIG ACPI_SIG_DSDT
43#define FACS_SIG ACPI_SIG_FACS
44#define FADT_SIG ACPI_SIG_FADT
45#define xfirmware_ctrl Xfacs
46#define firmware_ctrl facs
47
48typedef int s32;
49typedef unsigned char u8;
50typedef unsigned short u16;
51typedef unsigned int u32;
52typedef unsigned long long u64;
53typedef long long s64;
54#endif
55
56#include <sys/mman.h>
57#include <sys/types.h>
58#include <sys/stat.h>
59#include <fcntl.h>
60#include <stdio.h>
61#include <string.h>
62#include <unistd.h>
63#include <getopt.h>
64
65
66#include <acpi/acconfig.h>
67#include <acpi/platform/acenv.h>
68#include <acpi/actypes.h>
69#include <acpi/actbl.h>
70
71static inline u8 checksum(u8 * buffer, u32 length)
72{
73 u8 sum = 0, *i = buffer;
74 buffer += length;
75 for (; i < buffer; sum += *(i++));
76 return sum;
77}
78
79static unsigned long psz, addr, length;
80static int print, connect;
81static u8 select_sig[4];
82
83static unsigned long read_efi_systab( void )
84{
85 FILE *f = fopen("/sys/firmware/efi/systab", "r");
86 if (f) {
87 char buffer[80];
88 while (fgets(buffer, 80, f)) {
89 unsigned long addr;
90 if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1)
91 return addr;
92 }
93 fclose(f);
94 }
95 return 0;
96}
97
98static u8 *acpi_map_memory(unsigned long where, unsigned length)
99{
100 int fd = open("/dev/mem", O_RDONLY);
101 if (fd < 0) {
102 fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n");
103 exit(1);
104 }
105 unsigned long offset = where % psz;
106 u8 *there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE,
107 fd, where - offset);
108 close(fd);
109 if (there == MAP_FAILED) return 0;
110 return (there + offset);
111}
112
113static void acpi_unmap_memory(u8 * there, unsigned length)
114{
115 unsigned long offset = (unsigned long)there % psz;
116 munmap(there - offset, length + offset);
117}
118
119static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig)
120{
121 struct acpi_table_header *tbl = (struct acpi_table_header *)
122 acpi_map_memory(where, sizeof(struct acpi_table_header));
123 if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0;
124 unsigned size = tbl->length;
125 acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header));
126 return (struct acpi_table_header *)acpi_map_memory(where, size);
127}
128
129static void acpi_unmap_table(struct acpi_table_header *tbl)
130{
131 acpi_unmap_memory((u8 *)tbl, tbl->length);
132}
133
134static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length)
135{
136 u8 *i, *end = begin + length;
137 /* Search from given start address for the requested length */
138 for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) {
139 /* The signature and checksum must both be correct */
140 if (memcmp((char *)i, "RSD PTR ", 8)) continue;
141 struct acpi_rsdp_descriptor *rsdp = (struct acpi_rsdp_descriptor *)i;
142 /* Signature matches, check the appropriate checksum */
143 if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ?
144 ACPI_RSDP_CHECKSUM_LENGTH :
145 ACPI_RSDP_XCHECKSUM_LENGTH))
146 /* Checksum valid, we have found a valid RSDP */
147 return rsdp;
148 }
149 /* Searched entire block, no RSDP was found */
150 return 0;
151}
152
153/*
154 * Output data
155 */
156static void acpi_show_data(int fd, u8 * data, int size)
157{
158 char buffer[256];
159 int i, remain = size;
160 while (remain > 0) {
161 int len = snprintf(buffer, 256, " %04x:", size - remain);
162 for (i = 0; i < 16 && i < remain; i++) {
163 len +=
164 snprintf(&buffer[len], 256 - len, " %02x", data[i]);
165 }
166 for (; i < 16; i++) {
167 len += snprintf(&buffer[len], 256 - len, " ");
168 }
169 len += snprintf(&buffer[len], 256 - len, " ");
170 for (i = 0; i < 16 && i < remain; i++) {
171 buffer[len++] = (isprint(data[i])) ? data[i] : '.';
172 }
173 buffer[len++] = '\n';
174 write(fd, buffer, len);
175 data += 16;
176 remain -= 16;
177 }
178}
179
180/*
181 * Output ACPI table
182 */
183static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr)
184{
185 char buff[80];
186 int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr);
187 write(fd, buff, len);
188 acpi_show_data(fd, (u8 *) table, table->length);
189 buff[0] = '\n';
190 write(fd, buff, 1);
191}
192
193static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr)
194{
195 static int select_done = 0;
196 if (!select_sig[0]) {
197 if (print) {
198 acpi_show_table(fd, tbl, addr);
199 } else {
200 write(fd, tbl, tbl->length);
201 }
202 } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) {
203 if (print) {
204 acpi_show_table(fd, tbl, addr);
205 } else {
206 write(fd, tbl, tbl->length);
207 }
208 select_done = 1;
209 }
210}
211
212static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) {
213 struct acpi_fadt_descriptor x;
214 unsigned long addr;
215 size_t len = sizeof(struct acpi_fadt_descriptor);
216 if (len > tbl->length) len = tbl->length;
217 memcpy(&x, tbl, len);
218 x.header.length = len;
219 if (checksum((u8 *)tbl, len)) {
220 fprintf(stderr, "Wrong checksum for FADT!\n");
221 }
222 if (x.header.length >= 148 && x.Xdsdt) {
223 addr = (unsigned long)x.Xdsdt;
224 if (connect) {
225 x.Xdsdt = lseek(fd, 0, SEEK_CUR);
226 }
227 } else if (x.header.length >= 44 && x.dsdt) {
228 addr = (unsigned long)x.dsdt;
229 if (connect) {
230 x.dsdt = lseek(fd, 0, SEEK_CUR);
231 }
232 } else {
233 fprintf(stderr, "No DSDT in FADT!\n");
234 goto no_dsdt;
235 }
236 tbl = acpi_map_table(addr, DSDT_SIG);
237 if (!tbl) goto no_dsdt;
238 if (checksum((u8 *)tbl, tbl->length))
239 fprintf(stderr, "Wrong checksum for DSDT!\n");
240 write_table(fd, tbl, addr);
241 acpi_unmap_table(tbl);
242no_dsdt:
243 if (x.header.length >= 140 && x.xfirmware_ctrl) {
244 addr = (unsigned long)x.xfirmware_ctrl;
245 if (connect) {
246 x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR);
247 }
248 } else if (x.header.length >= 40 && x.firmware_ctrl) {
249 addr = (unsigned long)x.firmware_ctrl;
250 if (connect) {
251 x.firmware_ctrl = lseek(fd, 0, SEEK_CUR);
252 }
253 } else {
254 fprintf(stderr, "No FACS in FADT!\n");
255 goto no_facs;
256 }
257 tbl = acpi_map_table(addr, FACS_SIG);
258 if (!tbl) goto no_facs;
259 /* do not checksum FACS */
260 write_table(fd, tbl, addr);
261 acpi_unmap_table(tbl);
262no_facs:
263 write_table(fd, (struct acpi_table_header *)&x, xaddr);
264}
265
266static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp)
267{
268 struct acpi_table_header *tbl = 0;
269 int xsdt = 1;
270 if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
271 tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT");
272 }
273 if (!tbl && rsdp->rsdt_physical_address) {
274 xsdt = 0;
275 tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT");
276 }
277 if (!tbl) return 0;
278 struct acpi_table_header *sdt = malloc(tbl->length);
279 memcpy(sdt, tbl, tbl->length);
280 acpi_unmap_table(tbl);
281 if (checksum((u8 *)sdt, sdt->length))
282 fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT");
283 int i, num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32));
284 char *offset = (char *)sdt + sizeof(struct acpi_table_header);
285 unsigned long addr;
286 for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) {
287 addr = (xsdt) ? (unsigned long)(*(u64 *)offset):
288 (unsigned long)(*(u32 *)offset);
289 tbl = acpi_map_table(addr, 0);
290 if (!tbl) continue;
291 if (!memcmp(tbl->signature, FADT_SIG, 4)) {
292 acpi_dump_FADT(fd, tbl, addr);
293 } else {
294 if (checksum((u8 *)tbl, tbl->length))
295 fprintf(stderr, "Wrong checksum for generic table!\n");
296 write_table(fd, tbl, addr);
297 }
298 acpi_unmap_table(tbl);
299 if (connect) {
300 if (xsdt)
301 (*(u64*)offset) = lseek(fd, 0, SEEK_CUR);
302 else
303 (*(u32*)offset) = lseek(fd, 0, SEEK_CUR);
304 }
305 }
306 if (xsdt) {
307 addr = (unsigned long)rsdp->xsdt_physical_address;
308 if (connect) {
309 rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR);
310 }
311 } else {
312 addr = (unsigned long)rsdp->rsdt_physical_address;
313 if (connect) {
314 rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR);
315 }
316 }
317 write_table(fd, sdt, addr);
318 free (sdt);
319 return 1;
320}
321
322static void usage(const char *progname)
323{
324 puts("Usage:");
325 printf("%s [--addr 0x1234][--table DSDT][--output filename]"
326 "[--binary][--length 0x456][--help]\n", progname);
327 puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address");
328 puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature");
329 puts("\t--output filename or -o filename -- redirect output from stdin to filename");
330 puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format");
331 puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory"
332 "\n\t\tregion without trying to understand it's contents");
333 puts("\t--help or -h -- this help message");
334 exit(0);
335}
336
337int main(int argc, char **argv)
338{
339 memset(select_sig, 0, 4);
340 print = 1;
341 connect = 0;
342 char *filename = 0;
343 addr = length = 0;
344 while (1) {
345 int option_index = 0;
346 static struct option long_options[] = {
347 {"addr", 1, 0, 0},
348 {"table", 1, 0, 0},
349 {"output", 1, 0, 0},
350 {"binary", 0, 0, 0},
351 {"length", 1, 0, 0},
352 {"help", 0, 0, 0},
353 {0, 0, 0, 0}
354 };
355 int c = getopt_long(argc, argv, "a:t:o:bl:h",
356 long_options, &option_index);
357 if (c == -1)
358 break;
359
360 switch (c) {
361 case 0:
362 switch (option_index) {
363 case 0:
364 addr = strtoul(optarg, (char **)NULL, 16);
365 break;
366 case 1:
367 memcpy(select_sig, optarg, 4);
368 break;
369 case 2:
370 filename = optarg;
371 break;
372 case 3:
373 print = 0;
374 break;
375 case 4:
376 length = strtoul(optarg, (char **)NULL, 16);
377 break;
378 case 5:
379 usage(argv[0]);
380 exit(0);
381 }
382 break;
383 case 'a':
384 addr = strtoul(optarg, (char **)NULL, 16);
385 break;
386 case 't':
387 memcpy(select_sig, optarg, 4);
388 break;
389 case 'o':
390 filename = optarg;
391 break;
392 case 'b':
393 print = 0;
394 break;
395 case 'l':
396 length = strtoul(optarg, (char **)NULL, 16);
397 break;
398 case 'h':
399 usage(argv[0]);
400 exit(0);
401 default:
402 printf("Unknown option!\n");
403 usage(argv[0]);
404 exit(0);
405 }
406 }
407
408 int fd = STDOUT_FILENO;
409 if (filename) {
410 fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
411 if (fd < 0)
412 return fd;
413 }
414
415 if (!select_sig[0] && !print) {
416 connect = 1;
417 }
418
419 psz = sysconf(_SC_PAGESIZE);
420 u8 *raw;
421 if (length && addr) {
422 /* We know length and address, it means we just want a memory dump */
423 if (!(raw = acpi_map_memory(addr, length)))
424 goto not_found;
425 write(fd, raw, length);
426 acpi_unmap_memory(raw, length);
427 return 0;
428 }
429
430 length = sizeof(struct acpi_rsdp_descriptor);
431 if (!addr) {
432 addr = read_efi_systab();
433 if (!addr) {
434 addr = ACPI_HI_RSDP_WINDOW_BASE;
435 length = ACPI_HI_RSDP_WINDOW_SIZE;
436 }
437 }
438
439 struct acpi_rsdp_descriptor rsdpx, *x = 0;
440 if (!(raw = acpi_map_memory(addr, length)) ||
441 !(x = acpi_scan_for_rsdp(raw, length)))
442 goto not_found;
443
444 /* Find RSDP and print all found tables */
445 memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor));
446 acpi_unmap_memory(raw, length);
447 if (connect) {
448 lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET);
449 }
450 if (!acpi_dump_SDT(fd, &rsdpx))
451 goto not_found;
452 if (connect) {
453 lseek(fd, 0, SEEK_SET);
454 write(fd, x, (rsdpx.revision < 2) ?
455 ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
456 } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) {
457 char buff[80];
458 addr += (long)x - (long)raw;
459 length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr);
460 write(fd, buff, length);
461 acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ?
462 ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
463 buff[0] = '\n';
464 write(fd, buff, 1);
465 }
466 return 0;
467not_found:
468 fprintf(stderr, "ACPI tables were not found. If you know location "
469 "of RSD PTR table (from dmesg, etc), "
470 "supply it with either --addr or -a option\n");
471 return 1;
472}