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
25 uint8_t magic
[8]; /* "RSD PTR " */
37 char sig
[4]; /* Signature */
58 static struct rbtree
*rb_types
, *rb_addrs
;
60 static bool rb_has(struct rbtree
**tree
, uint64_t key
)
64 node
= rb_search(*tree
, key
);
65 if (node
&& node
->key
== key
)
68 node
= malloc(sizeof *node
);
71 *tree
= rb_insert(*tree
, node
);
76 static inline bool addr_ok(uint64_t addr
)
78 /* We can only handle 32-bit addresses for now... */
79 return addr
<= 0xffffffff;
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
;
100 static enum tbl_errs
is_valid_table(const void *ptr
)
102 const struct acpi_hdr
*hdr
= ptr
;
104 if (hdr
->sig
[0] == 0)
107 if (hdr
->len
< 10 || hdr
->len
> (1 << 20)) {
108 /* Either insane or too large to dump */
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))
123 if (checksum_range(rsdp
, 20))
127 if (base
+ rsdp
->len
>= end
||
128 checksum_range(rsdp
, rsdp
->len
))
138 static const struct acpi_rsdp
*find_rsdp(void)
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);
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
)
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
;
179 rsdt
= (const struct acpi_rsdt
*)rsdp
->rsdt_addr
;
181 if (memcmp(rsdt
->hdr
.sig
, "RSDT", 4) || is_valid_table(rsdt
) > ERR_CSUM
)
184 dump_table(be
, rsdt
->hdr
.sig
, rsdt
, rsdt
->hdr
.len
);
186 if (rsdt
->hdr
.len
< 36)
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;
208 if (!addr_ok(rsdp
->xsdt_addr
))
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
)
216 dump_table(be
, xsdt
->hdr
.sig
, xsdt
, xsdt
->hdr
.len
);
218 if (xsdt
->hdr
.len
< 36)
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
;
241 printf("Dumping ACPI... ");
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
);
255 rb_destroy(rb_types
);
256 rb_destroy(rb_addrs
);