[syslinux:pathbased] sysdump: dump ACPI information

syslinux-bot for H. Peter Anvin hpa at linux.intel.com
Fri Jun 18 18:30:22 PDT 2010


Commit-ID:  e32525782abedebbd97a3bb6fe518a8c4c817b48
Gitweb:     http://syslinux.zytor.com/commit/e32525782abedebbd97a3bb6fe518a8c4c817b48
Author:     H. Peter Anvin <hpa at linux.intel.com>
AuthorDate: Fri, 18 Jun 2010 18:28:43 -0700
Committer:  H. Peter Anvin <hpa at linux.intel.com>
CommitDate: Fri, 18 Jun 2010 18:28:43 -0700

sysdump: dump ACPI information

Dump ACPI tables.

Signed-off-by: H. Peter Anvin <hpa at linux.intel.com>


---
 com32/sysdump/acpi.c    |  175 +++++++++++++++++++++++++++++++++++++++++++++++
 com32/sysdump/main.c    |    1 +
 com32/sysdump/sysdump.h |    1 +
 3 files changed, 177 insertions(+), 0 deletions(-)

diff --git a/com32/sysdump/acpi.c b/com32/sysdump/acpi.c
new file mode 100644
index 0000000..48b890a
--- /dev/null
+++ b/com32/sysdump/acpi.c
@@ -0,0 +1,175 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Dump ACPI information
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "sysdump.h"
+#include "backend.h"
+
+struct acpi_rsdp {
+    uint8_t  magic[8];		/* "RSD PTR " */
+    uint8_t  csum;
+    char     oemid[6];
+    uint8_t  rev;
+    uint32_t rsdt_addr;
+    uint32_t len;
+    uint64_t xdst_addr;
+    uint8_t  xcsum;
+    uint8_t  rsvd[3];
+};
+
+struct acpi_hdr {
+    char     sig[4];		/* Signature */
+    uint32_t len;
+    uint8_t  rev;
+    uint8_t  csum;
+    char     oemid[6];
+    char     oemtblid[16];
+    uint32_t oemrev;
+    uint32_t creatorid;
+    uint32_t creatorrev;
+};
+
+struct acpi_rsdt {
+    struct acpi_hdr hdr;
+    uint32_t entry[0];
+};
+
+enum tbl_errs {
+    ERR_NONE,			/* No errors */
+    ERR_CSUM,			/* Invalid checksum */
+    ERR_SIZE,			/* Impossibly large table */
+    ERR_NOSIG			/* No signature */
+};
+
+static uint8_t checksum_range(const void *start, uint32_t size)
+{
+    const uint8_t *p = start;
+    uint8_t csum = 0;
+
+    while (size--)
+	csum += *p++;
+
+    return csum;
+}
+
+static enum tbl_errs is_valid_table(const void *ptr)
+{
+    const struct acpi_hdr *hdr = ptr;
+
+    if (hdr->sig[0] == 0)
+	return ERR_NOSIG;
+
+    if (hdr->len < 10 || hdr->len > (1 << 20)) {
+	/* Either insane or too large to dump */
+	return ERR_SIZE;
+    }
+
+    return checksum_range(hdr, hdr->len) == 0 ? ERR_NONE : ERR_CSUM;
+}
+
+static const struct acpi_rsdp *scan_for_rsdp(uint32_t base, uint32_t end)
+{
+    for (base &= ~15; base < end-20; base += 16) {
+	const struct acpi_rsdp *rsdp = (const struct acpi_rsdp *)base;
+
+	if (memcmp(rsdp->magic, "RSD PTR ", 8))
+	    continue;
+
+	if (checksum_range(rsdp, 20))
+	    continue;
+
+	if (rsdp->rev > 0) {
+	    if (base + rsdp->len >= end ||
+		checksum_range(rsdp, rsdp->len))
+		continue;
+	}
+
+	return rsdp;
+    }
+
+    return NULL;
+}
+
+static const struct acpi_rsdp *find_rsdp(void)
+{
+    uint32_t ebda;
+    const struct acpi_rsdp *rsdp;
+
+    ebda = (*(uint16_t *)0x40e) << 4;
+    if (ebda >= 0x70000 && ebda < 0xa0000) {
+	rsdp = scan_for_rsdp(ebda, ebda+1024);
+
+	if (rsdp)
+	    return rsdp;
+    }
+
+    return scan_for_rsdp(0xe0000, 0x100000);
+}
+
+static void dump_table(struct backend *be,
+		       const char name[], const void *ptr, uint32_t len)
+{
+    char namebuf[64];
+
+    /* XXX: this make cause the same directory to show up more than once */
+    snprintf(namebuf, sizeof namebuf, "acpi/%4.4s", name);
+    cpio_mkdir(be, namebuf);
+
+    snprintf(namebuf, sizeof namebuf, "acpi/%4.4s/%08x", name, (uint32_t)ptr);
+    cpio_hdr(be, MODE_FILE, len, namebuf);
+
+    write_data(be, ptr, len);
+}
+
+void dump_acpi(struct backend *be)
+{
+    const struct acpi_rsdp *rsdp;
+    const struct acpi_rsdt *rsdt;
+    uint32_t rsdp_len;
+    uint32_t i, n;
+
+    rsdp = find_rsdp();
+
+    if (!rsdp)
+	return;			/* No ACPI information found */
+
+    cpio_mkdir(be, "acpi");
+
+    rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
+
+    dump_table(be, "RSDP", rsdp, rsdp_len);
+
+    rsdt = (const struct acpi_rsdt *)rsdp->rsdt_addr;
+
+    if (memcmp(rsdt->hdr.sig, "RSDT", 4) || is_valid_table(rsdt) != ERR_NONE)
+	return;
+
+    dump_table(be, rsdt->hdr.sig, rsdt, rsdt->hdr.len);
+
+    if (rsdt->hdr.len < 36)
+	return;
+
+    n = (rsdt->hdr.len - 36) >> 2;
+
+    for (i = 0; i < n; i++) {
+	const struct acpi_hdr *hdr = (const struct acpi_hdr *)(rsdt->entry[i]);
+
+	if (is_valid_table(hdr) <= ERR_CSUM)
+	    dump_table(be, hdr->sig, hdr, hdr->len);
+    }
+}
diff --git a/com32/sysdump/main.c b/com32/sysdump/main.c
index d4a0320..26f562b 100644
--- a/com32/sysdump/main.c
+++ b/com32/sysdump/main.c
@@ -41,6 +41,7 @@ static void dump_all(struct backend *be, const char *argv[])
     dump_memory_map(be);
     dump_memory(be);
     dump_dmi(be);
+    dump_acpi(be);
     dump_cpuid(be);
     dump_pci(be);
     dump_vesa_tables(be);
diff --git a/com32/sysdump/sysdump.h b/com32/sysdump/sysdump.h
index 61a04a2..a5b963f 100644
--- a/com32/sysdump/sysdump.h
+++ b/com32/sysdump/sysdump.h
@@ -7,6 +7,7 @@ void dump_memory_map(struct backend *);
 void snapshot_lowmem(void);
 void dump_memory(struct backend *);
 void dump_dmi(struct backend *);
+void dump_acpi(struct backend *);
 void dump_cpuid(struct backend *);
 void dump_pci(struct backend *);
 void dump_vesa_tables(struct backend *);



More information about the Syslinux-commits mailing list