summaryrefslogtreecommitdiff
path: root/src/dmidecode
diff options
context:
space:
mode:
Diffstat (limited to 'src/dmidecode')
-rw-r--r--src/dmidecode/config.h29
-rw-r--r--src/dmidecode/dmidecode.c382
-rw-r--r--src/dmidecode/dmidecode.h55
-rw-r--r--src/dmidecode/dmioem.c120
-rw-r--r--src/dmidecode/dmioem.h26
-rw-r--r--src/dmidecode/types.h27
-rw-r--r--src/dmidecode/util.c165
-rw-r--r--src/dmidecode/util.h8
8 files changed, 812 insertions, 0 deletions
diff --git a/src/dmidecode/config.h b/src/dmidecode/config.h
new file mode 100644
index 0000000..52fd3c3
--- /dev/null
+++ b/src/dmidecode/config.h
@@ -0,0 +1,29 @@
+/*
+ * Configuration
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Default memory device file */
+#ifdef __BEOS__
+#define DEFAULT_MEM_DEV "/dev/misc/mem"
+#else
+#ifdef __sun
+#define DEFAULT_MEM_DEV "/dev/xsvc"
+#else
+#define DEFAULT_MEM_DEV "/dev/mem"
+#endif
+#endif
+
+/* Use mmap or not */
+#ifndef __BEOS__
+#define USE_MMAP
+#endif
+
+/* Use memory alignment workaround or not */
+#ifdef __ia64__
+#define ALIGNMENT_WORKAROUND
+#endif
+
+#endif
diff --git a/src/dmidecode/dmidecode.c b/src/dmidecode/dmidecode.c
new file mode 100644
index 0000000..5c542a6
--- /dev/null
+++ b/src/dmidecode/dmidecode.c
@@ -0,0 +1,382 @@
+/*
+ * Trimmed from DMI Decode http://savannah.nongnu.org/projects/dmidecode
+ *
+ * (C) 2000-2002 Alan Cox <alan@redhat.com>
+ * (C) 2002-2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmioem.h"
+#include "../state.h"
+#include "../pci.h"
+
+static const char *out_of_spec = "<OUT OF SPEC>";
+static const char *bad_index = "<BAD INDEX>";
+
+/*
+ * Type-independant Stuff
+ */
+
+const char *dmi_string(struct dmi_header *dm, u8 s)
+{
+ char *bp=(char *)dm->data;
+ size_t i, len;
+
+ if(s==0)
+ return "Not Specified";
+
+ bp+=dm->length;
+ while(s>1 && *bp)
+ {
+ bp+=strlen(bp);
+ bp++;
+ s--;
+ }
+
+ if(!*bp)
+ return bad_index;
+
+ /* ASCII filtering */
+ len=strlen(bp);
+ for(i=0; i<len; i++)
+ if(bp[i]<32 || bp[i]==127)
+ bp[i]='.';
+
+ return bp;
+}
+
+static const char *dmi_slot_current_usage(u8 code)
+{
+ /* 3.3.10.3 */
+ static const char *usage[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Available",
+ "In Use" /* 0x04 */
+ };
+
+ if(code>=0x01 && code<=0x04)
+ return usage[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_slot_segment_bus_func(u16 code1, u8 code2, u8 code3, u8 type, const char *prefix)
+{
+ /* 3.3.10.8 */
+ if (!(code1==0xFFFF && code2==0xFF && code3==0xFF))
+ printf("%sSegment Group %u, Bus %u, Device %u, Function %u ",
+ prefix, code1, code2, (code3>>3)&0x1F, (code3&0x7));
+ switch(type)
+ {
+ case 0x06: /* PCI */
+ case 0x0E: /* PCI */
+ case 0x0F: /* AGP */
+ case 0x10: /* AGP */
+ case 0x11: /* AGP */
+ case 0x12: /* PCI-X */
+ case 0x13: /* AGP */
+ case 0xA5: /* PCI Express */
+ printf("\n");
+ break;
+ default:
+ if (code1 != 0xFF || code2 != 0xFF || code3 != 0xFF)
+ printf("%s\n", out_of_spec);
+ break;
+ }
+}
+
+static u8 onboard_device_type(u8 code, const char *prefix)
+{
+ /* 3.3.x.2 */
+ u8 e = (code & 0x80)>>7;
+ static const char *type[]={
+ "Other", /* 1 */
+ "Unknown",
+ "Video",
+ "SCSI Controller",
+ "Ethernet",
+ "Token Ring",
+ "Sound",
+ "PATA Controller",
+ "SATA Controller",
+ "SAS Controller" /* 0x0A */
+ };
+ code = code & 0x7F;
+ if(code>=0x01 && code<=0x0A) {
+ printf("%sStatus: %s\n", prefix, e?"Enabled":"Disabled");
+ printf("%sDevice Type: %s\n", prefix, type[code-0x01]);
+ }
+ else
+ printf("%sDevice Type: %s\n", prefix, out_of_spec);
+}
+
+/*
+ * Main
+ */
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+static void dmi_decode(struct dmi_header *h, u16 ver, const struct libbiosdevname_state *state)
+{
+ u8 *data=h->data;
+ int domain, bus, device, function;
+ struct pci_device *pdev;
+ switch(h->type)
+ {
+ case 9: /* 3.3.10 System Slots */
+ if (h->length >= 0x0E && h->length >=0x11) {
+ domain = WORD(data+0x0D);
+ bus = data[0x0F];
+ device = (data[0x10]>>3)&0x1F;
+ function = data[0x10] & 7;
+ if (! (domain == 0xFFFF && bus == 0xFF && data[0x10] == 0xFF)) {
+ device = (data[0x10]>>3)&0x1F;
+ function = data[0x10] & 7;
+ pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function);
+ if (pdev) {
+ pdev->physical_slot = WORD(data+0x09);
+ pdev->smbios_type = 0;
+ pdev->smbios_instance = 0;
+ }
+ }
+ }
+ break;
+ case 41: /* 3.3.xx Onboard Device Information */
+ domain = WORD(data+0x07);
+ bus = data[0x09];
+ device = (data[0xa]>>3) & 0x1F;
+ function = data[0xa] & 0x7;
+ pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function);
+ if (pdev) {
+ pdev->physical_slot = 0;
+ pdev->smbios_enabled = !!(data[0x05] & 0x80);
+ pdev->smbios_type = data[0x05] & 0x7F;
+ pdev->smbios_instance = data[0x06];
+ }
+ break;
+
+ default:
+ if(dmi_decode_oem(h, state))
+ break;
+ }
+}
+
+static void to_dmi_header(struct dmi_header *h, u8 *data)
+{
+ h->type=data[0];
+ h->length=data[1];
+ h->handle=WORD(data+2);
+ h->data=data;
+}
+
+static void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem, const struct libbiosdevname_state *state)
+{
+ u8 *buf;
+ u8 *data;
+ int i=0;
+
+ if((buf=mem_chunk(base, len, devmem))==NULL)
+ {
+#ifndef USE_MMAP
+ printf("Table is unreachable, sorry. Try compiling dmidecode with -DUSE_MMAP.\n");
+#endif
+ return;
+ }
+
+ data=buf;
+ while(i<num && data+4<=buf+len) /* 4 is the length of an SMBIOS structure header */
+ {
+ u8 *next;
+ struct dmi_header h;
+
+ to_dmi_header(&h, data);
+
+ /*
+ * If a short entry is found (less than 4 bytes), not only it
+ * is invalid, but we cannot reliably locate the next entry.
+ * Better stop at this point, and let the user know his/her
+ * table is broken.
+ */
+ if(h.length<4)
+ break;
+
+ /* assign vendor for vendor-specific decodes later */
+ if(h.type==0 && h.length>=5)
+ dmi_set_vendor(dmi_string(&h, data[0x04]));
+
+ /* look for the next handle */
+ next=data+h.length;
+ while(next-buf+1<len && (next[0]!=0 || next[1]!=0))
+ next++;
+ next+=2;
+ if(next-buf<=len)
+ dmi_decode(&h, ver, state);
+
+ data=next;
+ i++;
+ }
+ free(buf);
+}
+
+
+static int smbios_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
+{
+ if(checksum(buf, buf[0x05])
+ && memcmp(buf+0x10, "_DMI_", 5)==0
+ && checksum(buf+0x10, 0x0F))
+ {
+ dmi_table(DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C),
+ (buf[0x06]<<8)+buf[0x07], devmem, state);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int legacy_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
+{
+ if(checksum(buf, 0x0F))
+ {
+ dmi_table(DWORD(buf+0x08), WORD(buf+0x06), WORD(buf+0x0C),
+ ((buf[0x0E]&0xF0)<<4)+(buf[0x0E]&0x0F), devmem, state);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Probe for EFI interface
+ */
+#define EFI_NOT_FOUND (-1)
+#define EFI_NO_SMBIOS (-2)
+static int address_from_efi(size_t *address)
+{
+ FILE *efi_systab;
+ const char *filename;
+ char linebuf[64];
+ int ret;
+
+ *address=0; /* Prevent compiler warning */
+
+ /*
+ * Linux up to 2.6.6: /proc/efi/systab
+ * Linux 2.6.7 and up: /sys/firmware/efi/systab
+ */
+ if((efi_systab=fopen(filename="/sys/firmware/efi/systab", "r"))==NULL
+ && (efi_systab=fopen(filename="/proc/efi/systab", "r"))==NULL)
+ {
+ /* No EFI interface, fallback to memory scan */
+ return EFI_NOT_FOUND;
+ }
+ ret=EFI_NO_SMBIOS;
+ while((fgets(linebuf, sizeof(linebuf)-1, efi_systab))!=NULL)
+ {
+ char *addrp=strchr(linebuf, '=');
+ *(addrp++)='\0';
+ if(strcmp(linebuf, "SMBIOS")==0)
+ {
+ *address=strtoul(addrp, NULL, 0);
+ ret=0;
+ break;
+ }
+ }
+ if(fclose(efi_systab)!=0)
+ perror(filename);
+
+ if(ret==EFI_NO_SMBIOS)
+ fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
+ return ret;
+}
+
+static const char *devmem = "/dev/mem";
+
+int dmidecode_main(const struct libbiosdevname_state *state)
+{
+ int ret=0; /* Returned value */
+ int found=0;
+ size_t fp;
+ int efi;
+ u8 *buf;
+
+ /* First try EFI (ia64, Intel-based Mac) */
+ efi=address_from_efi(&fp);
+ switch(efi)
+ {
+ case EFI_NOT_FOUND:
+ goto memory_scan;
+ case EFI_NO_SMBIOS:
+ ret=1;
+ goto exit_free;
+ }
+
+ if((buf=mem_chunk(fp, 0x20, devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ if(smbios_decode(buf, devmem, state))
+ found++;
+ goto done;
+
+memory_scan:
+ /* Fallback to memory scan (x86, x86_64) */
+ if((buf=mem_chunk(0xF0000, 0x10000, devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ for(fp=0; fp<=0xFFF0; fp+=16)
+ {
+ if(memcmp(buf+fp, "_SM_", 4)==0 && fp<=0xFFE0)
+ {
+ if(smbios_decode(buf+fp, devmem, state))
+ {
+ found++;
+ fp+=16;
+ }
+ }
+ else if(memcmp(buf+fp, "_DMI_", 5)==0)
+ {
+ if (legacy_decode(buf+fp, devmem, state))
+ found++;
+ }
+ }
+
+done:
+ free(buf);
+
+
+exit_free:
+ return ret;
+}
diff --git a/src/dmidecode/dmidecode.h b/src/dmidecode/dmidecode.h
new file mode 100644
index 0000000..db8f7bd
--- /dev/null
+++ b/src/dmidecode/dmidecode.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2005-2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+struct dmi_header
+{
+ u8 type;
+ u8 length;
+ u16 handle;
+ u8 *data;
+};
+
+const char *dmi_string(struct dmi_header *dm, u8 s);
+
+struct dmi_embedded_device
+{
+ u8 type;
+ u8 instance;
+ u16 domain;
+ u8 bus;
+ u8 device;
+ u8 function;
+ const char *reference_designation;
+};
+
+struct dmi_addon_device
+{
+ u8 type;
+ u8 instance;
+ u16 domain;
+ u8 bus;
+ u8 device;
+ u8 function;
+ const char *reference_designation;
+};
+
+struct libbiosdevname_state;
+int dmidecode_main(const struct libbiosdevname_state *state);
+
diff --git a/src/dmidecode/dmioem.c b/src/dmidecode/dmioem.c
new file mode 100644
index 0000000..217c13a
--- /dev/null
+++ b/src/dmidecode/dmioem.c
@@ -0,0 +1,120 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "types.h"
+#include "dmidecode.h"
+#include "dmioem.h"
+#include "../pci.h"
+
+/*
+ * Globals for vendor-specific decodes
+ */
+
+enum DMI_VENDORS { VENDOR_UNKNOWN, VENDOR_HP };
+
+static enum DMI_VENDORS dmi_vendor=VENDOR_UNKNOWN;
+
+/*
+ * Remember the system vendor for later use. We only actually store the
+ * value if we know how to decode at least one specific entry type for
+ * that vendor.
+ */
+void dmi_set_vendor(const char *s)
+{
+ if(strcmp(s, "HP")==0)
+ dmi_vendor=VENDOR_HP;
+}
+
+/*
+ * HP-specific data structures are decoded here.
+ *
+ * Code contributed by John Cagle.
+ */
+
+static int dmi_decode_hp(struct dmi_header *h, const struct libbiosdevname_state *state)
+{
+ u8 *data=h->data;
+ int nic, ptr;
+ u8 smbios_type = 0;
+ u8 bus, device, func;
+ struct pci_device *pdev;
+
+ switch(h->type)
+ {
+ case 209:
+ case 221:
+ /*
+ * Vendor Specific: HP ProLiant NIC MAC Information
+ *
+ * This prints the BIOS NIC number,
+ * PCI bus/device/function, and MAC address
+ */
+ if (h->type == 221)
+ smbios_type=0;
+ else
+ smbios_type=0x05;
+
+ nic=1;
+ ptr=4;
+ while(h->length>=ptr+8)
+ {
+ bus = data[ptr+1];
+ device = data[ptr]>>3;
+ func = data[ptr]&7;
+ pdev = find_pci_dev_by_pci_addr(state, 0, bus, device, func);
+ if (pdev) {
+ if((data[ptr]==0x00 && data[ptr+1]==0x00) ||
+ (data[ptr]==0xFF && data[ptr+1]==0xFF))
+ pdev->smbios_enabled = 0;
+ else {
+ pdev->smbios_enabled = 1;
+ pdev->smbios_type = smbios_type;
+ pdev->smbios_instance = nic;
+ }
+ }
+ nic++;
+ ptr+=8;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Dispatch vendor-specific entries decoding
+ * Return 1 if decoding was successful, 0 otherwise
+ */
+int dmi_decode_oem(struct dmi_header *h, const struct libbiosdevname_state *state)
+{
+ switch(dmi_vendor)
+ {
+ case VENDOR_HP:
+ return dmi_decode_hp(h, state);
+ default:
+ return 0;
+ }
+}
diff --git a/src/dmidecode/dmioem.h b/src/dmidecode/dmioem.h
new file mode 100644
index 0000000..bacdab7
--- /dev/null
+++ b/src/dmidecode/dmioem.h
@@ -0,0 +1,26 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "../state.h"
+struct dmi_header;
+
+void dmi_set_vendor(const char *s);
+int dmi_decode_oem(struct dmi_header *h, const struct libbiosdevname_state *state);
diff --git a/src/dmidecode/types.h b/src/dmidecode/types.h
new file mode 100644
index 0000000..12f3c65
--- /dev/null
+++ b/src/dmidecode/types.h
@@ -0,0 +1,27 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+#include "config.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef signed short i16;
+typedef unsigned int u32;
+
+#ifdef ALIGNMENT_WORKAROUND
+# ifdef BIGENDIAN
+# define WORD(x) (u16)((x)[1]+((x)[0]<<8))
+# define DWORD(x) (u32)((x)[3]+((x)[2]<<8)+((x)[1]<<16)+((x)[0]<<24))
+# define QWORD(x) (U64(DWORD(x+4), DWORD(x)))
+# else /* BIGENDIAN */
+# define WORD(x) (u16)((x)[0]+((x)[1]<<8))
+# define DWORD(x) (u32)((x)[0]+((x)[1]<<8)+((x)[2]<<16)+((x)[3]<<24))
+# define QWORD(x) (U64(DWORD(x), DWORD(x+4)))
+# endif /* BIGENDIAN */
+#else /* ALIGNMENT_WORKAROUND */
+#define WORD(x) (u16)(*(const u16 *)(x))
+#define DWORD(x) (u32)(*(const u32 *)(x))
+#define QWORD(x) (*(const u64 *)(x))
+#endif /* ALIGNMENT_WORKAROUND */
+
+#endif
diff --git a/src/dmidecode/util.c b/src/dmidecode/util.c
new file mode 100644
index 0000000..9eda714
--- /dev/null
+++ b/src/dmidecode/util.c
@@ -0,0 +1,165 @@
+/*
+ * Common "util" functions
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2002-2005 Jean Delvare <khali@linux-fr>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifdef USE_MMAP
+#include <sys/mman.h>
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif /* !MAP_FAILED */
+#endif /* USE MMAP */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "types.h"
+#include "util.h"
+
+#ifndef USE_MMAP
+static int myread(int fd, u8 *buf, size_t count, const char *prefix)
+{
+ ssize_t r=1;
+ size_t r2=0;
+
+ while(r2!=count && r!=0)
+ {
+ r=read(fd, buf+r2, count-r2);
+ if(r==-1)
+ {
+ if(errno!=EINTR)
+ {
+ close(fd);
+ perror(prefix);
+ return -1;
+ }
+ }
+ else
+ r2+=r;
+ }
+
+ if(r2!=count)
+ {
+ close(fd);
+ fprintf(stderr, "%s: Unexpected end of file\n", prefix);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+int checksum(const u8 *buf, size_t len)
+{
+ u8 sum=0;
+ size_t a;
+
+ for(a=0; a<len; a++)
+ sum+=buf[a];
+ return (sum==0);
+}
+
+/*
+ * Copy a physical memory chunk into a memory buffer.
+ * This function allocates memory.
+ */
+void *mem_chunk(size_t base, size_t len, const char *devmem)
+{
+ void *p;
+ int fd;
+#ifdef USE_MMAP
+ size_t mmoffset;
+ void *mmp;
+#endif
+
+ if((fd=open(devmem, O_RDONLY))==-1)
+ {
+ perror(devmem);
+ return NULL;
+ }
+
+ if((p=malloc(len))==NULL)
+ {
+ perror("malloc");
+ return NULL;
+ }
+
+#ifdef USE_MMAP
+#ifdef _SC_PAGESIZE
+ mmoffset=base%sysconf(_SC_PAGESIZE);
+#else
+ mmoffset=base%getpagesize();
+#endif /* _SC_PAGESIZE */
+ /*
+ * Please note that we don't use mmap() for performance reasons here,
+ * but to workaround problems many people encountered when trying
+ * to read from /dev/mem using regular read() calls.
+ */
+ mmp=mmap(0, mmoffset+len, PROT_READ, MAP_SHARED, fd, base-mmoffset);
+ if(mmp==MAP_FAILED)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("mmap");
+ free(p);
+ return NULL;
+ }
+
+ memcpy(p, (u8 *)mmp+mmoffset, len);
+
+ if(munmap(mmp, mmoffset+len)==-1)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("munmap");
+ }
+#else /* USE_MMAP */
+ if(lseek(fd, base, SEEK_SET)==-1)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("lseek");
+ free(p);
+ return NULL;
+ }
+
+ if(myread(fd, p, len, devmem)==-1)
+ {
+ free(p);
+ return NULL;
+ }
+#endif /* USE_MMAP */
+
+ if(close(fd)==-1)
+ perror(devmem);
+
+ return p;
+}
diff --git a/src/dmidecode/util.h b/src/dmidecode/util.h
new file mode 100644
index 0000000..b546f64
--- /dev/null
+++ b/src/dmidecode/util.h
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+
+#include "types.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+int checksum(const u8 *buf, size_t len);
+void *mem_chunk(size_t base, size_t len, const char *devmem);