2 * (c) Alexey Starikovskiy, Intel, 2005-2006.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
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.
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
49 typedef unsigned char u8
;
50 typedef unsigned short u16
;
51 typedef unsigned int u32
;
52 typedef unsigned long long u64
;
53 typedef long long s64
;
57 #include <sys/types.h>
67 #include <acpi/acconfig.h>
68 #include <acpi/platform/acenv.h>
69 #include <acpi/actypes.h>
70 #include <acpi/actbl.h>
72 static inline u8
checksum(u8
* buffer
, u32 length
)
74 u8 sum
= 0, *i
= buffer
;
76 for (; i
< buffer
; sum
+= *(i
++));
80 static unsigned long psz
, addr
, length
;
81 static int print
, connect
, skip
;
82 static u8 select_sig
[4];
84 static unsigned long read_efi_systab( void )
88 FILE *f
= fopen("/sys/firmware/efi/systab", "r");
90 while (fgets(buffer
, 80, f
)) {
91 if (sscanf(buffer
, "ACPI20=0x%lx", &addr
) == 1)
99 static u8
*acpi_map_memory(unsigned long where
, unsigned length
)
101 unsigned long offset
;
103 int fd
= open("/dev/mem", O_RDONLY
);
105 fprintf(stderr
, "acpi_os_map_memory: cannot open /dev/mem\n");
108 offset
= where
% psz
;
109 there
= mmap(NULL
, length
+ offset
, PROT_READ
, MAP_PRIVATE
,
112 if (there
== MAP_FAILED
) return 0;
113 return (there
+ offset
);
116 static void acpi_unmap_memory(u8
* there
, unsigned length
)
118 unsigned long offset
= (unsigned long)there
% psz
;
119 munmap(there
- offset
, length
+ offset
);
122 static struct acpi_table_header
*acpi_map_table(unsigned long where
, char *sig
)
125 struct acpi_table_header
*tbl
= (struct acpi_table_header
*)
126 acpi_map_memory(where
, sizeof(struct acpi_table_header
));
127 if (!tbl
|| (sig
&& memcmp(sig
, tbl
->signature
, 4))) return 0;
129 acpi_unmap_memory((u8
*) tbl
, sizeof(struct acpi_table_header
));
130 return (struct acpi_table_header
*)acpi_map_memory(where
, size
);
133 static void acpi_unmap_table(struct acpi_table_header
*tbl
)
135 acpi_unmap_memory((u8
*)tbl
, tbl
->length
);
138 static struct acpi_rsdp_descriptor
*acpi_scan_for_rsdp(u8
*begin
, u32 length
)
140 struct acpi_rsdp_descriptor
*rsdp
;
141 u8
*i
, *end
= begin
+ length
;
142 /* Search from given start address for the requested length */
143 for (i
= begin
; i
< end
; i
+= ACPI_RSDP_SCAN_STEP
) {
144 /* The signature and checksum must both be correct */
145 if (memcmp((char *)i
, "RSD PTR ", 8)) continue;
146 rsdp
= (struct acpi_rsdp_descriptor
*)i
;
147 /* Signature matches, check the appropriate checksum */
148 if (!checksum((u8
*) rsdp
, (rsdp
->revision
< 2) ?
149 ACPI_RSDP_CHECKSUM_LENGTH
:
150 ACPI_RSDP_XCHECKSUM_LENGTH
))
151 /* Checksum valid, we have found a valid RSDP */
154 /* Searched entire block, no RSDP was found */
161 static void acpi_show_data(int fd
, u8
* data
, int size
)
165 int i
, remain
= size
;
167 len
= snprintf(buffer
, 256, " %04x:", size
- remain
);
168 for (i
= 0; i
< 16 && i
< remain
; i
++) {
170 snprintf(&buffer
[len
], 256 - len
, " %02x", data
[i
]);
172 for (; i
< 16; i
++) {
173 len
+= snprintf(&buffer
[len
], 256 - len
, " ");
175 len
+= snprintf(&buffer
[len
], 256 - len
, " ");
176 for (i
= 0; i
< 16 && i
< remain
; i
++) {
177 buffer
[len
++] = (isprint(data
[i
])) ? data
[i
] : '.';
179 buffer
[len
++] = '\n';
180 write(fd
, buffer
, len
);
189 static void acpi_show_table(int fd
, struct acpi_table_header
*table
, unsigned long addr
)
192 int len
= snprintf(buff
, 80, "%.4s @ %p\n", table
->signature
, (void *)addr
);
193 write(fd
, buff
, len
);
194 acpi_show_data(fd
, (u8
*) table
, table
->length
);
199 static void write_table(int fd
, struct acpi_table_header
*tbl
, unsigned long addr
)
201 static int select_done
= 0;
202 if (!select_sig
[0]) {
204 acpi_show_table(fd
, tbl
, addr
);
206 write(fd
, tbl
, tbl
->length
);
208 } else if (!select_done
&& !memcmp(select_sig
, tbl
->signature
, 4)) {
214 acpi_show_table(fd
, tbl
, addr
);
216 write(fd
, tbl
, tbl
->length
);
222 static void acpi_dump_FADT(int fd
, struct acpi_table_header
*tbl
, unsigned long xaddr
) {
223 struct acpi_fadt_descriptor x
;
225 size_t len
= sizeof(struct acpi_fadt_descriptor
);
226 if (len
> tbl
->length
) len
= tbl
->length
;
227 memcpy(&x
, tbl
, len
);
228 x
.header
.length
= len
;
229 if (checksum((u8
*)tbl
, len
)) {
230 fprintf(stderr
, "Wrong checksum for FADT!\n");
232 if (x
.header
.length
>= 148 && x
.Xdsdt
) {
233 addr
= (unsigned long)x
.Xdsdt
;
235 x
.Xdsdt
= lseek(fd
, 0, SEEK_CUR
);
237 } else if (x
.header
.length
>= 44 && x
.dsdt
) {
238 addr
= (unsigned long)x
.dsdt
;
240 x
.dsdt
= lseek(fd
, 0, SEEK_CUR
);
243 fprintf(stderr
, "No DSDT in FADT!\n");
246 tbl
= acpi_map_table(addr
, DSDT_SIG
);
247 if (!tbl
) goto no_dsdt
;
248 if (checksum((u8
*)tbl
, tbl
->length
))
249 fprintf(stderr
, "Wrong checksum for DSDT!\n");
250 write_table(fd
, tbl
, addr
);
251 acpi_unmap_table(tbl
);
253 if (x
.header
.length
>= 140 && x
.xfirmware_ctrl
) {
254 addr
= (unsigned long)x
.xfirmware_ctrl
;
256 x
.xfirmware_ctrl
= lseek(fd
, 0, SEEK_CUR
);
258 } else if (x
.header
.length
>= 40 && x
.firmware_ctrl
) {
259 addr
= (unsigned long)x
.firmware_ctrl
;
261 x
.firmware_ctrl
= lseek(fd
, 0, SEEK_CUR
);
264 fprintf(stderr
, "No FACS in FADT!\n");
267 tbl
= acpi_map_table(addr
, FACS_SIG
);
268 if (!tbl
) goto no_facs
;
269 /* do not checksum FACS */
270 write_table(fd
, tbl
, addr
);
271 acpi_unmap_table(tbl
);
273 write_table(fd
, (struct acpi_table_header
*)&x
, xaddr
);
276 static int acpi_dump_SDT(int fd
, struct acpi_rsdp_descriptor
*rsdp
)
278 struct acpi_table_header
*sdt
, *tbl
= 0;
279 int xsdt
= 1, i
, num
;
282 if (rsdp
->revision
> 1 && rsdp
->xsdt_physical_address
) {
283 tbl
= acpi_map_table(rsdp
->xsdt_physical_address
, "XSDT");
285 if (!tbl
&& rsdp
->rsdt_physical_address
) {
287 tbl
= acpi_map_table(rsdp
->rsdt_physical_address
, "RSDT");
290 sdt
= malloc(tbl
->length
);
291 memcpy(sdt
, tbl
, tbl
->length
);
292 acpi_unmap_table(tbl
);
293 if (checksum((u8
*)sdt
, sdt
->length
))
294 fprintf(stderr
, "Wrong checksum for %s!\n", (xsdt
)?"XSDT":"RSDT");
295 num
= (sdt
->length
- sizeof(struct acpi_table_header
))/((xsdt
)?sizeof(u64
):sizeof(u32
));
296 offset
= (char *)sdt
+ sizeof(struct acpi_table_header
);
297 for (i
= 0; i
< num
; ++i
, offset
+= ((xsdt
) ? sizeof(u64
) : sizeof(u32
))) {
298 addr
= (xsdt
) ? (unsigned long)(*(u64
*)offset
):
299 (unsigned long)(*(u32
*)offset
);
301 tbl
= acpi_map_table(addr
, 0);
303 if (!memcmp(tbl
->signature
, FADT_SIG
, 4)) {
304 acpi_dump_FADT(fd
, tbl
, addr
);
306 if (checksum((u8
*)tbl
, tbl
->length
))
307 fprintf(stderr
, "Wrong checksum for generic table!\n");
308 write_table(fd
, tbl
, addr
);
310 acpi_unmap_table(tbl
);
313 (*(u64
*)offset
) = lseek(fd
, 0, SEEK_CUR
);
315 (*(u32
*)offset
) = lseek(fd
, 0, SEEK_CUR
);
319 addr
= (unsigned long)rsdp
->xsdt_physical_address
;
321 rsdp
->xsdt_physical_address
= lseek(fd
, 0, SEEK_CUR
);
324 addr
= (unsigned long)rsdp
->rsdt_physical_address
;
326 rsdp
->rsdt_physical_address
= lseek(fd
, 0, SEEK_CUR
);
329 write_table(fd
, sdt
, addr
);
334 #define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic"
336 static void acpi_dump_dynamic_SSDT(int fd
)
338 struct stat file_stat
;
339 char filename
[256], *ptr
;
341 struct dirent
*entry
;
343 int count
, readcount
, length
;
344 struct acpi_table_header table_header
, *ptable
;
346 if (stat(DYNAMIC_SSDT
, &file_stat
) == -1) {
347 /* The directory doesn't exist */
350 tabledir
= opendir(DYNAMIC_SSDT
);
352 /*can't open the directory */
356 while ((entry
= readdir(tabledir
)) != 0){
357 /* skip the file of . /.. */
358 if (entry
->d_name
[0] == '.')
361 sprintf(filename
, "%s/%s", DYNAMIC_SSDT
, entry
->d_name
);
362 fp
= fopen(filename
, "r");
364 fprintf(stderr
, "Can't open the file of %s\n",
368 /* Read the Table header to parse the table length */
369 count
= fread(&table_header
, 1, sizeof(struct acpi_table_header
), fp
);
370 if (count
< sizeof(table_header
)) {
371 /* the length is lessn than ACPI table header. skip it */
375 length
= table_header
.length
;
376 ptr
= malloc(table_header
.length
);
377 fseek(fp
, 0, SEEK_SET
);
379 while(!feof(fp
) && readcount
< length
) {
380 count
= fread(ptr
+ readcount
, 1, 256, fp
);
384 ptable
= (struct acpi_table_header
*) ptr
;
385 if (checksum((u8
*) ptable
, ptable
->length
))
386 fprintf(stderr
, "Wrong checksum "
387 "for dynamic SSDT table!\n");
388 write_table(fd
, ptable
, 0);
395 static void usage(const char *progname
)
398 printf("%s [--addr 0x1234][--table DSDT][--output filename]"
399 "[--binary][--length 0x456][--help]\n", progname
);
400 puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address");
401 puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature");
402 puts("\t--output filename or -o filename -- redirect output from stdin to filename");
403 puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format");
404 puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory"
405 "\n\t\tregion without trying to understand it's contents");
406 puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one");
407 puts("\t--help or -h -- this help message");
411 static struct option long_options
[] = {
421 int main(int argc
, char **argv
)
423 int option_index
, c
, fd
;
425 struct acpi_rsdp_descriptor rsdpx
, *x
= 0;
428 memset(select_sig
, 0, 4);
435 c
= getopt_long(argc
, argv
, "a:t:o:bl:s:h",
436 long_options
, &option_index
);
442 switch (option_index
) {
444 addr
= strtoul(optarg
, (char **)NULL
, 16);
447 memcpy(select_sig
, optarg
, 4);
456 length
= strtoul(optarg
, (char **)NULL
, 16);
459 skip
= strtoul(optarg
, (char **)NULL
, 10);
467 addr
= strtoul(optarg
, (char **)NULL
, 16);
470 memcpy(select_sig
, optarg
, 4);
479 length
= strtoul(optarg
, (char **)NULL
, 16);
482 skip
= strtoul(optarg
, (char **)NULL
, 10);
488 printf("Unknown option!\n");
496 fd
= creat(filename
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
);
501 if (!select_sig
[0] && !print
) {
505 psz
= sysconf(_SC_PAGESIZE
);
506 if (length
&& addr
) {
507 /* We know length and address, it means we just want a memory dump */
508 if (!(raw
= acpi_map_memory(addr
, length
)))
510 write(fd
, raw
, length
);
511 acpi_unmap_memory(raw
, length
);
516 length
= sizeof(struct acpi_rsdp_descriptor
);
518 addr
= read_efi_systab();
520 addr
= ACPI_HI_RSDP_WINDOW_BASE
;
521 length
= ACPI_HI_RSDP_WINDOW_SIZE
;
525 if (!(raw
= acpi_map_memory(addr
, length
)) ||
526 !(x
= acpi_scan_for_rsdp(raw
, length
)))
529 /* Find RSDP and print all found tables */
530 memcpy(&rsdpx
, x
, sizeof(struct acpi_rsdp_descriptor
));
531 acpi_unmap_memory(raw
, length
);
533 lseek(fd
, sizeof(struct acpi_rsdp_descriptor
), SEEK_SET
);
535 if (!acpi_dump_SDT(fd
, &rsdpx
))
538 lseek(fd
, 0, SEEK_SET
);
539 write(fd
, x
, (rsdpx
.revision
< 2) ?
540 ACPI_RSDP_CHECKSUM_LENGTH
: ACPI_RSDP_XCHECKSUM_LENGTH
);
541 } else if (!select_sig
[0] || !memcmp("RSD PTR ", select_sig
, 4)) {
542 addr
+= (long)x
- (long)raw
;
543 length
= snprintf(buff
, 80, "RSD PTR @ %p\n", (void *)addr
);
544 write(fd
, buff
, length
);
545 acpi_show_data(fd
, (u8
*) & rsdpx
, (rsdpx
.revision
< 2) ?
546 ACPI_RSDP_CHECKSUM_LENGTH
: ACPI_RSDP_XCHECKSUM_LENGTH
);
550 acpi_dump_dynamic_SSDT(fd
);
555 fprintf(stderr
, "ACPI tables were not found. If you know location "
556 "of RSD PTR table (from dmesg, etc), "
557 "supply it with either --addr or -a option\n");