Releasing debian version 4.04+dfsg-9.
[syslinux-debian/hramrach.git] / com32 / sysdump / acpi.c
blob8671fc8a00543b55d0900210563bfa071422e05a
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2010 Intel Corporation; author: H. Peter Anvin
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.
11 * ----------------------------------------------------------------------- */
14 * Dump ACPI information
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include "sysdump.h"
21 #include "backend.h"
22 #include "rbtree.h"
24 struct acpi_rsdp {
25 uint8_t magic[8]; /* "RSD PTR " */
26 uint8_t csum;
27 char oemid[6];
28 uint8_t rev;
29 uint32_t rsdt_addr;
30 uint32_t len;
31 uint64_t xsdt_addr;
32 uint8_t xcsum;
33 uint8_t rsvd[3];
36 struct acpi_hdr {
37 char sig[4]; /* Signature */
38 uint32_t len;
39 uint8_t rev;
40 uint8_t csum;
41 char oemid[6];
42 char oemtblid[16];
43 uint32_t oemrev;
44 uint32_t creatorid;
45 uint32_t creatorrev;
48 struct acpi_rsdt {
49 struct acpi_hdr hdr;
50 uint32_t entry[0];
53 struct acpi_xsdt {
54 struct acpi_hdr hdr;
55 uint64_t entry[0];
58 static struct rbtree *rb_types, *rb_addrs;
60 static bool rb_has(struct rbtree **tree, uint64_t key)
62 struct rbtree *node;
64 node = rb_search(*tree, key);
65 if (node && node->key == key)
66 return true;
68 node = malloc(sizeof *node);
69 if (node) {
70 node->key = key;
71 *tree = rb_insert(*tree, node);
73 return false;
76 static inline bool addr_ok(uint64_t addr)
78 /* We can only handle 32-bit addresses for now... */
79 return addr <= 0xffffffff;
82 enum tbl_errs {
83 ERR_NONE, /* No errors */
84 ERR_CSUM, /* Invalid checksum */
85 ERR_SIZE, /* Impossibly large table */
86 ERR_NOSIG /* No signature */
89 static uint8_t checksum_range(const void *start, uint32_t size)
91 const uint8_t *p = start;
92 uint8_t csum = 0;
94 while (size--)
95 csum += *p++;
97 return csum;
100 static enum tbl_errs is_valid_table(const void *ptr)
102 const struct acpi_hdr *hdr = ptr;
104 if (hdr->sig[0] == 0)
105 return ERR_NOSIG;
107 if (hdr->len < 10 || hdr->len > (1 << 20)) {
108 /* Either insane or too large to dump */
109 return ERR_SIZE;
112 return checksum_range(hdr, hdr->len) == 0 ? ERR_NONE : ERR_CSUM;
115 static const struct acpi_rsdp *scan_for_rsdp(uint32_t base, uint32_t end)
117 for (base &= ~15; base < end-20; base += 16) {
118 const struct acpi_rsdp *rsdp = (const struct acpi_rsdp *)base;
120 if (memcmp(rsdp->magic, "RSD PTR ", 8))
121 continue;
123 if (checksum_range(rsdp, 20))
124 continue;
126 if (rsdp->rev > 0) {
127 if (base + rsdp->len >= end ||
128 checksum_range(rsdp, rsdp->len))
129 continue;
132 return rsdp;
135 return NULL;
138 static const struct acpi_rsdp *find_rsdp(void)
140 uint32_t ebda;
141 const struct acpi_rsdp *rsdp;
143 ebda = (*(uint16_t *)0x40e) << 4;
144 if (ebda >= 0x70000 && ebda < 0xa0000) {
145 rsdp = scan_for_rsdp(ebda, ebda+1024);
147 if (rsdp)
148 return rsdp;
151 return scan_for_rsdp(0xe0000, 0x100000);
154 static void dump_table(struct backend *be,
155 const char name[], const void *ptr, uint32_t len)
157 char namebuf[64];
158 uint32_t name_key = *(uint32_t *)name;
160 if (rb_has(&rb_addrs, (size_t)ptr))
161 return; /* Already dumped this table */
163 if (!rb_has(&rb_types, name_key)) {
164 snprintf(namebuf, sizeof namebuf, "acpi/%4.4s", name);
165 cpio_mkdir(be, namebuf);
168 snprintf(namebuf, sizeof namebuf, "acpi/%4.4s/%08x", name, (uint32_t)ptr);
169 cpio_hdr(be, MODE_FILE, len, namebuf);
171 write_data(be, ptr, len);
174 static void dump_rsdt(struct backend *be, const struct acpi_rsdp *rsdp)
176 const struct acpi_rsdt *rsdt;
177 uint32_t i, n;
179 rsdt = (const struct acpi_rsdt *)rsdp->rsdt_addr;
181 if (memcmp(rsdt->hdr.sig, "RSDT", 4) || is_valid_table(rsdt) > ERR_CSUM)
182 return;
184 dump_table(be, rsdt->hdr.sig, rsdt, rsdt->hdr.len);
186 if (rsdt->hdr.len < 36)
187 return;
189 n = (rsdt->hdr.len - 36) >> 2;
191 for (i = 0; i < n; i++) {
192 const struct acpi_hdr *hdr = (const struct acpi_hdr *)(rsdt->entry[i]);
194 if (is_valid_table(hdr) <= ERR_CSUM)
195 dump_table(be, hdr->sig, hdr, hdr->len);
199 static void dump_xsdt(struct backend *be, const struct acpi_rsdp *rsdp)
201 const struct acpi_xsdt *xsdt;
202 uint32_t rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
203 uint32_t i, n;
205 if (rsdp_len < 34)
206 return;
208 if (!addr_ok(rsdp->xsdt_addr))
209 return;
211 xsdt = (const struct acpi_xsdt *)(size_t)rsdp->xsdt_addr;
213 if (memcmp(xsdt->hdr.sig, "XSDT", 4) || is_valid_table(xsdt) > ERR_CSUM)
214 return;
216 dump_table(be, xsdt->hdr.sig, xsdt, xsdt->hdr.len);
218 if (xsdt->hdr.len < 36)
219 return;
221 n = (xsdt->hdr.len - 36) >> 3;
223 for (i = 0; i < n; i++) {
224 const struct acpi_hdr *hdr;
225 if (addr_ok(xsdt->entry[i])) {
226 hdr = (const struct acpi_hdr *)(size_t)(xsdt->entry[i]);
228 if (is_valid_table(hdr) <= ERR_CSUM)
229 dump_table(be, hdr->sig, hdr, hdr->len);
234 void dump_acpi(struct backend *be)
236 const struct acpi_rsdp *rsdp;
237 uint32_t rsdp_len;
239 rsdp = find_rsdp();
241 printf("Dumping ACPI... ");
243 if (!rsdp)
244 return; /* No ACPI information found */
246 cpio_mkdir(be, "acpi");
248 rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
250 dump_table(be, "RSDP", rsdp, rsdp_len);
252 dump_rsdt(be, rsdp);
253 dump_xsdt(be, rsdp);
255 rb_destroy(rb_types);
256 rb_destroy(rb_addrs);
258 printf("done.\n");