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
24 uint8_t magic
[8]; /* "RSD PTR " */
36 char sig
[4]; /* Signature */
57 static struct rbtree
*rb_types
, *rb_addrs
;
59 static bool rb_has(struct rbtree
**tree
, uint64_t key
)
63 node
= rb_search(*tree
, key
);
64 if (node
&& node
->key
== key
)
67 node
= malloc(sizeof *node
);
70 *tree
= rb_insert(*tree
, node
);
75 static inline bool addr_ok(uint64_t addr
)
77 /* We can only handle 32-bit addresses for now... */
78 return addr
<= 0xffffffff;
82 ERR_NONE
, /* No errors */
83 ERR_CSUM
, /* Invalid checksum */
84 ERR_SIZE
, /* Impossibly large table */
85 ERR_NOSIG
/* No signature */
88 static uint8_t checksum_range(const void *start
, uint32_t size
)
90 const uint8_t *p
= start
;
99 static enum tbl_errs
is_valid_table(const void *ptr
)
101 const struct acpi_hdr
*hdr
= ptr
;
103 if (hdr
->sig
[0] == 0)
106 if (hdr
->len
< 10 || hdr
->len
> (1 << 20)) {
107 /* Either insane or too large to dump */
111 return checksum_range(hdr
, hdr
->len
) == 0 ? ERR_NONE
: ERR_CSUM
;
114 static const struct acpi_rsdp
*scan_for_rsdp(uint32_t base
, uint32_t end
)
116 for (base
&= ~15; base
< end
-20; base
+= 16) {
117 const struct acpi_rsdp
*rsdp
= (const struct acpi_rsdp
*)base
;
119 if (memcmp(rsdp
->magic
, "RSD PTR ", 8))
122 if (checksum_range(rsdp
, 20))
126 if (base
+ rsdp
->len
>= end
||
127 checksum_range(rsdp
, rsdp
->len
))
137 static const struct acpi_rsdp
*find_rsdp(void)
140 const struct acpi_rsdp
*rsdp
;
142 ebda
= (*(uint16_t *)0x40e) << 4;
143 if (ebda
>= 0x70000 && ebda
< 0xa0000) {
144 rsdp
= scan_for_rsdp(ebda
, ebda
+1024);
150 return scan_for_rsdp(0xe0000, 0x100000);
153 static void dump_table(struct upload_backend
*be
,
154 const char name
[], const void *ptr
, uint32_t len
)
157 uint32_t name_key
= *(uint32_t *)name
;
159 if (rb_has(&rb_addrs
, (size_t)ptr
))
160 return; /* Already dumped this table */
162 if (!rb_has(&rb_types
, name_key
)) {
163 snprintf(namebuf
, sizeof namebuf
, "acpi/%4.4s", name
);
164 cpio_mkdir(be
, namebuf
);
167 snprintf(namebuf
, sizeof namebuf
, "acpi/%4.4s/%08x", name
, (uint32_t)ptr
);
168 cpio_hdr(be
, MODE_FILE
, len
, namebuf
);
170 write_data(be
, ptr
, len
);
173 static void dump_rsdt(struct upload_backend
*be
, const struct acpi_rsdp
*rsdp
)
175 const struct acpi_rsdt
*rsdt
;
178 rsdt
= (const struct acpi_rsdt
*)rsdp
->rsdt_addr
;
180 if (memcmp(rsdt
->hdr
.sig
, "RSDT", 4) || is_valid_table(rsdt
) > ERR_CSUM
)
183 dump_table(be
, rsdt
->hdr
.sig
, rsdt
, rsdt
->hdr
.len
);
185 if (rsdt
->hdr
.len
< 36)
188 n
= (rsdt
->hdr
.len
- 36) >> 2;
190 for (i
= 0; i
< n
; i
++) {
191 const struct acpi_hdr
*hdr
= (const struct acpi_hdr
*)(rsdt
->entry
[i
]);
193 if (is_valid_table(hdr
) <= ERR_CSUM
)
194 dump_table(be
, hdr
->sig
, hdr
, hdr
->len
);
198 static void dump_xsdt(struct upload_backend
*be
, const struct acpi_rsdp
*rsdp
)
200 const struct acpi_xsdt
*xsdt
;
201 uint32_t rsdp_len
= rsdp
->rev
> 0 ? rsdp
->len
: 20;
207 if (!addr_ok(rsdp
->xsdt_addr
))
210 xsdt
= (const struct acpi_xsdt
*)(size_t)rsdp
->xsdt_addr
;
212 if (memcmp(xsdt
->hdr
.sig
, "XSDT", 4) || is_valid_table(xsdt
) > ERR_CSUM
)
215 dump_table(be
, xsdt
->hdr
.sig
, xsdt
, xsdt
->hdr
.len
);
217 if (xsdt
->hdr
.len
< 36)
220 n
= (xsdt
->hdr
.len
- 36) >> 3;
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
]);
227 if (is_valid_table(hdr
) <= ERR_CSUM
)
228 dump_table(be
, hdr
->sig
, hdr
, hdr
->len
);
233 void dump_acpi(struct upload_backend
*be
)
235 const struct acpi_rsdp
*rsdp
;
240 printf("Dumping ACPI... ");
243 return; /* No ACPI information found */
245 cpio_mkdir(be
, "acpi");
247 rsdp_len
= rsdp
->rev
> 0 ? rsdp
->len
: 20;
249 dump_table(be
, "RSDP", rsdp
, rsdp_len
);
254 rb_destroy(rb_types
);
255 rb_destroy(rb_addrs
);