Adding upstream version 4.00~pre53+dfsg.
[syslinux-debian/hramrach.git] / com32 / sysdump / acpi.c
blob48b890aef514615370e5430d73d219992007c8f7
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
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include "sysdump.h"
21 #include "backend.h"
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 xdst_addr;
31 uint8_t xcsum;
32 uint8_t rsvd[3];
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;
47 struct acpi_rsdt {
48 struct acpi_hdr hdr;
49 uint32_t entry[0];
52 enum tbl_errs {
53 ERR_NONE, /* No errors */
54 ERR_CSUM, /* Invalid checksum */
55 ERR_SIZE, /* Impossibly large table */
56 ERR_NOSIG /* No signature */
59 static uint8_t checksum_range(const void *start, uint32_t size)
61 const uint8_t *p = start;
62 uint8_t csum = 0;
64 while (size--)
65 csum += *p++;
67 return csum;
70 static enum tbl_errs is_valid_table(const void *ptr)
72 const struct acpi_hdr *hdr = ptr;
74 if (hdr->sig[0] == 0)
75 return ERR_NOSIG;
77 if (hdr->len < 10 || hdr->len > (1 << 20)) {
78 /* Either insane or too large to dump */
79 return ERR_SIZE;
82 return checksum_range(hdr, hdr->len) == 0 ? ERR_NONE : ERR_CSUM;
85 static const struct acpi_rsdp *scan_for_rsdp(uint32_t base, uint32_t end)
87 for (base &= ~15; base < end-20; base += 16) {
88 const struct acpi_rsdp *rsdp = (const struct acpi_rsdp *)base;
90 if (memcmp(rsdp->magic, "RSD PTR ", 8))
91 continue;
93 if (checksum_range(rsdp, 20))
94 continue;
96 if (rsdp->rev > 0) {
97 if (base + rsdp->len >= end ||
98 checksum_range(rsdp, rsdp->len))
99 continue;
102 return rsdp;
105 return NULL;
108 static const struct acpi_rsdp *find_rsdp(void)
110 uint32_t ebda;
111 const struct acpi_rsdp *rsdp;
113 ebda = (*(uint16_t *)0x40e) << 4;
114 if (ebda >= 0x70000 && ebda < 0xa0000) {
115 rsdp = scan_for_rsdp(ebda, ebda+1024);
117 if (rsdp)
118 return rsdp;
121 return scan_for_rsdp(0xe0000, 0x100000);
124 static void dump_table(struct backend *be,
125 const char name[], const void *ptr, uint32_t len)
127 char namebuf[64];
129 /* XXX: this make cause the same directory to show up more than once */
130 snprintf(namebuf, sizeof namebuf, "acpi/%4.4s", name);
131 cpio_mkdir(be, namebuf);
133 snprintf(namebuf, sizeof namebuf, "acpi/%4.4s/%08x", name, (uint32_t)ptr);
134 cpio_hdr(be, MODE_FILE, len, namebuf);
136 write_data(be, ptr, len);
139 void dump_acpi(struct backend *be)
141 const struct acpi_rsdp *rsdp;
142 const struct acpi_rsdt *rsdt;
143 uint32_t rsdp_len;
144 uint32_t i, n;
146 rsdp = find_rsdp();
148 if (!rsdp)
149 return; /* No ACPI information found */
151 cpio_mkdir(be, "acpi");
153 rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
155 dump_table(be, "RSDP", rsdp, rsdp_len);
157 rsdt = (const struct acpi_rsdt *)rsdp->rsdt_addr;
159 if (memcmp(rsdt->hdr.sig, "RSDT", 4) || is_valid_table(rsdt) != ERR_NONE)
160 return;
162 dump_table(be, rsdt->hdr.sig, rsdt, rsdt->hdr.len);
164 if (rsdt->hdr.len < 36)
165 return;
167 n = (rsdt->hdr.len - 36) >> 2;
169 for (i = 0; i < n; i++) {
170 const struct acpi_hdr *hdr = (const struct acpi_hdr *)(rsdt->entry[i]);
172 if (is_valid_table(hdr) <= ERR_CSUM)
173 dump_table(be, hdr->sig, hdr, hdr->len);