blob: 502223357cd15da9279355a5467b4a2f5587aaff [file] [log] [blame]
Greg Hartman76d05dc2016-11-23 15:51:27 -08001/* ----------------------------------------------------------------------- *
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
23struct 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
35struct 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
47struct acpi_rsdt {
48 struct acpi_hdr hdr;
49 uint32_t entry[0];
50};
51
52struct acpi_xsdt {
53 struct acpi_hdr hdr;
54 uint64_t entry[0];
55};
56
57static struct rbtree *rb_types, *rb_addrs;
58
59static 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
75static inline bool addr_ok(uint64_t addr)
76{
77 /* We can only handle 32-bit addresses for now... */
78 return addr <= 0xffffffff;
79}
80
81enum 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
88static 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
99static 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
114static 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
137static 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
153static 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
173static 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
198static 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
233void 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}