"Fossies" - the Fresh Open Source Software Archive

Member "syslinux-6.03/com32/sysdump/acpi.c" (6 Oct 2014, 5655 Bytes) of package /linux/misc/syslinux-6.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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 }