From 6f19ff5ce811655353712647e82f0dee22805108 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sat, 6 Feb 2010 22:28:01 -0800 Subject: [PATCH] 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 --- 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(-) create mode 100644 com32/sysdump/dmi.c 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 +#include +#include +#include +#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 */ -- 2.7.4