Home | History | Annotate | Download | only in sysdump
      1 /*
      2  * Dump DMI information in a way hopefully compatible with dmidecode
      3  */
      4 
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 #include "sysdump.h"
      9 
     10 struct dmi_header {
     11     char signature[5];
     12     uint8_t csum;
     13     uint16_t tbllen;
     14     uint32_t tbladdr;
     15     uint16_t nstruc;
     16     uint8_t revision;
     17     uint8_t reserved;
     18 };
     19 
     20 struct smbios_header {
     21     char signature[4];
     22     uint8_t csum;
     23     uint8_t len;
     24     uint8_t major;
     25     uint8_t minor;
     26     uint16_t maxsize;
     27     uint8_t revision;
     28     uint8_t fmt[5];
     29 
     30     struct dmi_header dmi;
     31 };
     32 
     33 static uint8_t checksum(const void *buf, size_t len)
     34 {
     35     const uint8_t *p = buf;
     36     uint8_t csum = 0;
     37 
     38     while (len--)
     39 	csum += *p++;
     40 
     41     return csum;
     42 }
     43 
     44 static bool is_old_dmi(size_t dptr)
     45 {
     46     const struct dmi_header *dmi = (void *)dptr;
     47 
     48     return !memcmp(dmi->signature, "_DMI_", 5) &&
     49 	!checksum(dmi, 0x0f);
     50     return false;
     51 }
     52 
     53 static bool is_smbios(size_t dptr)
     54 {
     55     const struct smbios_header *smb = (void *)dptr;
     56 
     57     return !memcmp(smb->signature, "_SM_", 4) &&
     58 	!checksum(smb, smb->len) &&
     59 	is_old_dmi(dptr+16);
     60 }
     61 
     62 static void dump_smbios(struct upload_backend *be, size_t dptr)
     63 {
     64     const struct smbios_header *smb = (void *)dptr;
     65     struct smbios_header smx = *smb;
     66     char filename[32];
     67 
     68     snprintf(filename, sizeof filename, "dmi/%05x.%08x",
     69 	     dptr, smb->dmi.tbladdr);
     70     cpio_hdr(be, MODE_FILE, smb->dmi.tbllen + 32, filename);
     71 
     72     /*
     73      * Adjust the address of the smbios table to be 32, to
     74      * make dmidecode happy.  The checksum on the smbios table is unchanged,
     75      * since it includes the checksum on the dmi table.
     76      */
     77     smx.dmi.tbladdr = sizeof smx;
     78     smx.dmi.csum -= checksum(&smx.dmi, 0x0f);
     79 
     80     write_data(be, &smx, sizeof smx);
     81     write_data(be, (const void *)smb->dmi.tbladdr, smb->dmi.tbllen);
     82 }
     83 
     84 static void dump_old_dmi(struct upload_backend *be, size_t dptr)
     85 {
     86     const struct dmi_header *dmi = (void *)dptr;
     87     struct fake {
     88 	struct dmi_header dmi;
     89 	char pad[16];
     90     } fake;
     91     char filename[32];
     92 
     93     snprintf(filename, sizeof filename, "dmi/%05x.%08x",
     94 	     dptr, dmi->tbladdr);
     95     cpio_hdr(be, MODE_FILE, dmi->tbllen + 32, filename);
     96 
     97     /*
     98      * Adjust the address of the smbios table to be 32, to
     99      * make dmidecode happy.
    100      */
    101     fake.dmi = *dmi;
    102     memset(&fake.pad, 0, sizeof fake.pad);
    103     fake.dmi.tbladdr = sizeof fake;
    104     fake.dmi.csum -= checksum(&fake.dmi, 0x0f);
    105 
    106     write_data(be, &fake, sizeof fake);
    107     write_data(be, (const void *)dmi->tbladdr, dmi->tbllen);
    108 }
    109 
    110 void dump_dmi(struct upload_backend *be)
    111 {
    112     size_t dptr;
    113 
    114     cpio_mkdir(be, "dmi");
    115 
    116     /* Search for _SM_ or _DMI_ structure */
    117     for (dptr = 0xf0000 ; dptr < 0x100000 ; dptr += 16) {
    118 	if (is_smbios(dptr)) {
    119 	    dump_smbios(be, dptr);
    120 	    dptr += 16;		/* Skip the subsequent DMI header */
    121 	} else if (is_old_dmi(dptr)) {
    122 	    dump_old_dmi(be, dptr);
    123 	}
    124     }
    125 }
    126