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