• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2010 Intel Corporation; author: H. Peter Anvin
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8  *   Boston MA 02110-1301, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12 
13 /*
14  * Dump ACPI information
15  */
16 
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include "sysdump.h"
21 #include "rbtree.h"
22 
23 struct acpi_rsdp {
24     uint8_t  magic[8];		/* "RSD PTR " */
25     uint8_t  csum;
26     char     oemid[6];
27     uint8_t  rev;
28     uint32_t rsdt_addr;
29     uint32_t len;
30     uint64_t xsdt_addr;
31     uint8_t  xcsum;
32     uint8_t  rsvd[3];
33 };
34 
35 struct acpi_hdr {
36     char     sig[4];		/* Signature */
37     uint32_t len;
38     uint8_t  rev;
39     uint8_t  csum;
40     char     oemid[6];
41     char     oemtblid[16];
42     uint32_t oemrev;
43     uint32_t creatorid;
44     uint32_t creatorrev;
45 };
46 
47 struct acpi_rsdt {
48     struct acpi_hdr hdr;
49     uint32_t entry[0];
50 };
51 
52 struct acpi_xsdt {
53     struct acpi_hdr hdr;
54     uint64_t entry[0];
55 };
56 
57 static struct rbtree *rb_types, *rb_addrs;
58 
rb_has(struct rbtree ** tree,uint64_t key)59 static bool rb_has(struct rbtree **tree, uint64_t key)
60 {
61     struct rbtree *node;
62 
63     node = rb_search(*tree, key);
64     if (node && node->key == key)
65 	return true;
66 
67     node = malloc(sizeof *node);
68     if (node) {
69 	node->key = key;
70 	*tree = rb_insert(*tree, node);
71     }
72     return false;
73 }
74 
addr_ok(uint64_t addr)75 static inline bool addr_ok(uint64_t addr)
76 {
77     /* We can only handle 32-bit addresses for now... */
78     return addr <= 0xffffffff;
79 }
80 
81 enum tbl_errs {
82     ERR_NONE,			/* No errors */
83     ERR_CSUM,			/* Invalid checksum */
84     ERR_SIZE,			/* Impossibly large table */
85     ERR_NOSIG			/* No signature */
86 };
87 
checksum_range(const void * start,uint32_t size)88 static uint8_t checksum_range(const void *start, uint32_t size)
89 {
90     const uint8_t *p = start;
91     uint8_t csum = 0;
92 
93     while (size--)
94 	csum += *p++;
95 
96     return csum;
97 }
98 
is_valid_table(const void * ptr)99 static enum tbl_errs is_valid_table(const void *ptr)
100 {
101     const struct acpi_hdr *hdr = ptr;
102 
103     if (hdr->sig[0] == 0)
104 	return ERR_NOSIG;
105 
106     if (hdr->len < 10 || hdr->len > (1 << 20)) {
107 	/* Either insane or too large to dump */
108 	return ERR_SIZE;
109     }
110 
111     return checksum_range(hdr, hdr->len) == 0 ? ERR_NONE : ERR_CSUM;
112 }
113 
scan_for_rsdp(uint32_t base,uint32_t end)114 static const struct acpi_rsdp *scan_for_rsdp(uint32_t base, uint32_t end)
115 {
116     for (base &= ~15; base < end-20; base += 16) {
117 	const struct acpi_rsdp *rsdp = (const struct acpi_rsdp *)base;
118 
119 	if (memcmp(rsdp->magic, "RSD PTR ", 8))
120 	    continue;
121 
122 	if (checksum_range(rsdp, 20))
123 	    continue;
124 
125 	if (rsdp->rev > 0) {
126 	    if (base + rsdp->len >= end ||
127 		checksum_range(rsdp, rsdp->len))
128 		continue;
129 	}
130 
131 	return rsdp;
132     }
133 
134     return NULL;
135 }
136 
find_rsdp(void)137 static const struct acpi_rsdp *find_rsdp(void)
138 {
139     uint32_t ebda;
140     const struct acpi_rsdp *rsdp;
141 
142     ebda = (*(uint16_t *)0x40e) << 4;
143     if (ebda >= 0x70000 && ebda < 0xa0000) {
144 	rsdp = scan_for_rsdp(ebda, ebda+1024);
145 
146 	if (rsdp)
147 	    return rsdp;
148     }
149 
150     return scan_for_rsdp(0xe0000, 0x100000);
151 }
152 
dump_table(struct upload_backend * be,const char name[],const void * ptr,uint32_t len)153 static void dump_table(struct upload_backend *be,
154 		       const char name[], const void *ptr, uint32_t len)
155 {
156     char namebuf[64];
157     uint32_t name_key = *(uint32_t *)name;
158 
159     if (rb_has(&rb_addrs, (size_t)ptr))
160 	return;			/* Already dumped this table */
161 
162     if (!rb_has(&rb_types, name_key)) {
163 	snprintf(namebuf, sizeof namebuf, "acpi/%4.4s", name);
164 	cpio_mkdir(be, namebuf);
165     }
166 
167     snprintf(namebuf, sizeof namebuf, "acpi/%4.4s/%08x", name, (uint32_t)ptr);
168     cpio_hdr(be, MODE_FILE, len, namebuf);
169 
170     write_data(be, ptr, len);
171 }
172 
dump_rsdt(struct upload_backend * be,const struct acpi_rsdp * rsdp)173 static void dump_rsdt(struct upload_backend *be, const struct acpi_rsdp *rsdp)
174 {
175     const struct acpi_rsdt *rsdt;
176     uint32_t i, n;
177 
178     rsdt = (const struct acpi_rsdt *)rsdp->rsdt_addr;
179 
180     if (memcmp(rsdt->hdr.sig, "RSDT", 4) || is_valid_table(rsdt) > ERR_CSUM)
181 	return;
182 
183     dump_table(be, rsdt->hdr.sig, rsdt, rsdt->hdr.len);
184 
185     if (rsdt->hdr.len < 36)
186 	return;
187 
188     n = (rsdt->hdr.len - 36) >> 2;
189 
190     for (i = 0; i < n; i++) {
191 	const struct acpi_hdr *hdr = (const struct acpi_hdr *)(rsdt->entry[i]);
192 
193 	if (is_valid_table(hdr) <= ERR_CSUM)
194 	    dump_table(be, hdr->sig, hdr, hdr->len);
195     }
196 }
197 
dump_xsdt(struct upload_backend * be,const struct acpi_rsdp * rsdp)198 static void dump_xsdt(struct upload_backend *be, const struct acpi_rsdp *rsdp)
199 {
200     const struct acpi_xsdt *xsdt;
201     uint32_t rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
202     uint32_t i, n;
203 
204     if (rsdp_len < 34)
205 	return;
206 
207     if (!addr_ok(rsdp->xsdt_addr))
208 	return;
209 
210     xsdt = (const struct acpi_xsdt *)(size_t)rsdp->xsdt_addr;
211 
212     if (memcmp(xsdt->hdr.sig, "XSDT", 4) || is_valid_table(xsdt) > ERR_CSUM)
213 	return;
214 
215     dump_table(be, xsdt->hdr.sig, xsdt, xsdt->hdr.len);
216 
217     if (xsdt->hdr.len < 36)
218 	return;
219 
220     n = (xsdt->hdr.len - 36) >> 3;
221 
222     for (i = 0; i < n; i++) {
223 	const struct acpi_hdr *hdr;
224 	if (addr_ok(xsdt->entry[i])) {
225 	    hdr = (const struct acpi_hdr *)(size_t)(xsdt->entry[i]);
226 
227 	    if (is_valid_table(hdr) <= ERR_CSUM)
228 		dump_table(be, hdr->sig, hdr, hdr->len);
229 	}
230     }
231 }
232 
dump_acpi(struct upload_backend * be)233 void dump_acpi(struct upload_backend *be)
234 {
235     const struct acpi_rsdp *rsdp;
236     uint32_t rsdp_len;
237 
238     rsdp = find_rsdp();
239 
240     printf("Dumping ACPI... ");
241 
242     if (!rsdp)
243 	return;			/* No ACPI information found */
244 
245     cpio_mkdir(be, "acpi");
246 
247     rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
248 
249     dump_table(be, "RSDP", rsdp, rsdp_len);
250 
251     dump_rsdt(be, rsdp);
252     dump_xsdt(be, rsdp);
253 
254     rb_destroy(rb_types);
255     rb_destroy(rb_addrs);
256 
257     printf("done.\n");
258 }
259