source: bootcd/isolinux/syslinux-6.03/com32/sysdump/acpi.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 5.5 KB
Line 
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
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}
Note: See TracBrowser for help on using the repository browser.