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 10struct 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 20struct 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 33static 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 44static 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 53static 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 62static 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 84static 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 110void 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