[syslinux:master] sysdump: add support for dumping DMI tables

syslinux-bot for H. Peter Anvin hpa at zytor.com
Sat Feb 6 22:30:06 PST 2010


Commit-ID:  6f19ff5ce811655353712647e82f0dee22805108
Gitweb:     http://syslinux.zytor.com/commit/6f19ff5ce811655353712647e82f0dee22805108
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Sat, 6 Feb 2010 22:28:01 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Sat, 6 Feb 2010 22:28:01 -0800

sysdump: add support for dumping DMI tables

Add support for dumping DMI tables; hopefully in a way that is
compatible with dmidecode.

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


---
 com32/sysdump/backend.h |    4 ++
 com32/sysdump/cpio.c    |   12 +++--
 com32/sysdump/dmi.c     |  123 +++++++++++++++++++++++++++++++++++++++++++++++
 com32/sysdump/main.c    |   84 +-------------------------------
 com32/sysdump/memory.c  |    3 -
 com32/sysdump/sysdump.h |    1 +
 6 files changed, 136 insertions(+), 91 deletions(-)

diff --git a/com32/sysdump/backend.h b/com32/sysdump/backend.h
index 343d296..0be80c6 100644
--- a/com32/sysdump/backend.h
+++ b/com32/sysdump/backend.h
@@ -47,11 +47,15 @@ int init_data(struct backend *be, const char *argv[], size_t len);
 int write_data(struct backend *be, const void *buf, size_t len, bool flush);
 
 /* cpio.c */
+int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
+	     const char *filename);
 int cpio_init(struct backend *be, const char *argv[], size_t len);
 int cpio_mkdir(struct backend *be, const char *filename);
 int cpio_writefile(struct backend *be, const char *filename,
 		   const void *data, size_t len);
 int cpio_close(struct backend *be);
+#define MODE_FILE	0100644
+#define MODE_DIR	0040755
 
 /* backends.c */
 struct backend *get_backend(const char *name);
diff --git a/com32/sysdump/cpio.c b/com32/sysdump/cpio.c
index 120f7eb..30e3d49 100644
--- a/com32/sysdump/cpio.c
+++ b/com32/sysdump/cpio.c
@@ -14,7 +14,7 @@
 
 static uint32_t now;
 
-static int cpio_pad(struct backend *be)
+int cpio_pad(struct backend *be)
 {
     static char pad[4];		/* Up to 4 zero bytes */
     if (be->dbytes & 3)
@@ -23,14 +23,16 @@ static int cpio_pad(struct backend *be)
 	return 0;
 }
 
-static int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
-		    const char *filename)
+int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
+	     const char *filename)
 {
     static uint32_t inode = 2;
     char hdr[6+13*8+1];
     int nlen = strlen(filename)+1;
     int rv = 0;
 
+    cpio_pad(be);
+
     sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
 	    070701,		/* c_magic */
 	    inode++,		/* c_ino */
@@ -60,7 +62,7 @@ int cpio_init(struct backend *be, const char *argv[], size_t len)
 
 int cpio_mkdir(struct backend *be, const char *filename)
 {
-    return cpio_hdr(be, 0040755, 0, filename);
+    return cpio_hdr(be, MODE_DIR, 0, filename);
 }
 
 int cpio_writefile(struct backend *be, const char *filename,
@@ -68,7 +70,7 @@ int cpio_writefile(struct backend *be, const char *filename,
 {
     int rv;
 
-    rv = cpio_hdr(be, 0100644, len, filename);
+    rv = cpio_hdr(be, MODE_FILE, len, filename);
     rv |= write_data(be, data, len, false);
     rv |= cpio_pad(be);
 
diff --git a/com32/sysdump/dmi.c b/com32/sysdump/dmi.c
new file mode 100644
index 0000000..ad7c452
--- /dev/null
+++ b/com32/sysdump/dmi.c
@@ -0,0 +1,123 @@
+/*
+ * Dump DMI information in a way hopefully compatible with dmidecode
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/cpu.h>
+#include "sysdump.h"
+#include "backend.h"
+
+struct dmi_header {
+    char signature[5];
+    uint8_t csum;
+    uint16_t tbllen;
+    uint32_t tbladdr;
+    uint16_t nstruc;
+    uint8_t revision;
+    uint8_t reserved;
+};
+
+struct smbios_header {
+    char signature[4];
+    uint8_t csum;
+    uint8_t len;
+    uint8_t major;
+    uint8_t minor;
+    uint16_t maxsize;
+    uint8_t revision;
+    uint8_t fmt[5];
+
+    struct dmi_header dmi;
+};
+
+static uint8_t checksum(const void *buf, size_t len)
+{
+    const uint8_t *p = buf;
+    uint8_t csum = 0;
+
+    while (len--)
+	csum += *p++;
+
+    return csum;
+}
+
+static bool is_old_dmi(size_t dptr)
+{
+    const struct dmi_header *dmi = (void *)dptr;
+
+    return !memcmp(dmi->signature, "_DMI_", 5) &&
+	!checksum(dmi, 0x0f);
+    return false;
+}
+
+static bool is_smbios(size_t dptr)
+{
+    const struct smbios_header *smb = (void *)dptr;
+
+    return !memcmp(smb->signature, "_SM_", 4) &&
+	!checksum(smb, smb->len) &&
+	is_old_dmi(dptr+16);
+}
+
+static void dump_smbios(struct backend *be, size_t dptr)
+{
+    const struct smbios_header *smb = (void *)dptr;
+    struct smbios_header smx = *smb;
+
+    cpio_hdr(be, MODE_FILE, smb->dmi.tbllen + 32, "dmidata");
+
+    /*
+     * Adjust the address of the smbios table to be 32, to
+     * make dmidecode happy.  According to dmidecode, the checksum on
+     * the smbios structure doesn't need to be adjusted, for whatever
+     * reason...
+     */
+    smx.dmi.tbladdr = sizeof smx;
+    smx.dmi.csum -= checksum(&smb->dmi, 0x0f);
+
+    write_data(be, &smx, sizeof smx, false);
+    write_data(be, (const void *)smb->dmi.tbladdr, smb->dmi.tbllen, false);
+}
+
+static void dump_old_dmi(struct backend *be, size_t dptr)
+{
+    const struct dmi_header *dmi = (void *)dptr;
+    struct fake {
+	struct dmi_header dmi;
+	char pad[16];
+    } fake;
+
+    cpio_hdr(be, MODE_FILE, dmi->tbllen + 32, "dmidata");
+
+    /*
+     * Adjust the address of the smbios table to be 32, to
+     * make dmidecode happy.  According to dmidecode, the checksum on
+     * the smbios structure doesn't need to be adjusted, for whatever
+     * reason...
+     */
+    fake.dmi = *dmi;
+    memset(&fake.pad, 0, sizeof fake.pad);
+    fake.dmi.tbladdr = sizeof fake;
+    fake.dmi.csum -= checksum(&fake.dmi, 0x0f);
+
+    write_data(be, &fake, sizeof fake, false);
+    write_data(be, (const void *)dmi->tbladdr, dmi->tbllen, false);
+}
+
+void dump_dmi(struct backend *be)
+{
+    size_t dptr;
+
+    /* Search for _SM_ or _DMI_ structure */
+    for (dptr = 0xf0000 ; dptr < 0x100000 ; dptr += 16) {
+	if (is_smbios(dptr)) {
+	    dump_smbios(be, dptr);
+	    break;
+	} else if (is_old_dmi(dptr)) {
+	    dump_old_dmi(be, dptr);
+	    break;
+	}
+    }
+}
diff --git a/com32/sysdump/main.c b/com32/sysdump/main.c
index decb86d..ffe3430 100644
--- a/com32/sysdump/main.c
+++ b/com32/sysdump/main.c
@@ -30,95 +30,13 @@ __noreturn die(const char *msg)
     exit(1);
 }
 
-#if 0
-static void get_bytes(void *buf, size_t len, struct file_info *finfo,
-		      size_t pos)
-{
-    pos += (size_t) finfo->pvt;	/* Add base */
-    memcpy(buf, (void *)pos, len);
-}
-
-int main(int argc, char *argv[])
-{
-    uint16_t bios_ports[4];
-    const char *prefix;
-    char filename[1024];
-    int i;
-    static struct serial_if sif = {
-	.read = serial_read,
-	.write = serial_write,
-    };
-    struct file_info finfo;
-    const char ymodem_banner[] = "Now begin Ymodem download...\r\n";
-    bool srec = false;
-
-    if (argv[1][0] == '-') {
-	srec = argv[1][1] == 's';
-	argc--;
-	argv++;
-    }
-
-    if (argc < 4)
-	die("usage: memdump [-s] port prefix start,len...");
-
-    finfo.pvt = (void *)0x400;
-    get_bytes(bios_ports, 8, &finfo, 0);	/* Get BIOS serial ports */
-
-    for (i = 0; i < 4; i++)
-	printf("ttyS%i (COM%i) is at %#x\n", i, i + 1, bios_ports[i]);
-
-    sif.port = strtoul(argv[1], NULL, 0);
-    if (sif.port <= 3) {
-	sif.port = bios_ports[sif.port];
-    }
-
-    if (serial_init(&sif))
-	die("failed to initialize serial port");
-
-    prefix = argv[2];
-
-    if (!srec) {
-	puts("Printing prefix...");
-	sif.write(&sif, ymodem_banner, sizeof ymodem_banner - 1);
-    }
-
-    for (i = 3; i < argc; i++) {
-	uint32_t start, len;
-	char *ep;
-
-	start = strtoul(argv[i], &ep, 0);
-	if (*ep != ',')
-	    die("invalid range specification");
-	len = strtoul(ep + 1, NULL, 0);
-
-	sprintf(filename, "%s%#x-%#x.bin", prefix, start, len);
-	finfo.name = filename;
-	finfo.size = len;
-	finfo.pvt = (void *)start;
-
-	printf("Sending %s...\n", filename);
-
-	if (srec)
-	    send_srec(&sif, &finfo, get_bytes);
-	else
-	    send_ymodem(&sif, &finfo, get_bytes);
-    }
-
-    if (!srec) {
-	puts("Sending closing signature...");
-	end_ymodem(&sif);
-    }
-
-    return 0;
-}
-#endif
-
 static void dump_all(struct backend *be, const char *argv[], size_t len)
 {
 
     cpio_init(be, argv, len);
 
     dump_memory(be);
+    dump_dmi(be);
     dump_vesa_tables(be);
 
     cpio_close(be);
diff --git a/com32/sysdump/memory.c b/com32/sysdump/memory.c
index 9d391ec..e7108d1 100644
--- a/com32/sysdump/memory.c
+++ b/com32/sysdump/memory.c
@@ -44,7 +44,4 @@ void dump_memory(struct backend *be)
 
     if (lowmem)
 	dump_memory_range(be, lowmem, zero_addr, lowmem_len);
-    
-    /* Look for a DMI header */
 }
-
diff --git a/com32/sysdump/sysdump.h b/com32/sysdump/sysdump.h
index 87f7e2b..df9da31 100644
--- a/com32/sysdump/sysdump.h
+++ b/com32/sysdump/sysdump.h
@@ -4,6 +4,7 @@
 struct backend;
 
 void dump_memory(struct backend *);
+void dump_dmi(struct backend *);
 void dump_vesa_tables(struct backend *);
 
 #endif /* SYSDUMP_H */



More information about the Syslinux-commits mailing list