blob: a0b793b135b08eb6823521af99a707a4a45745e5 [file] [log] [blame]
/*
* DMI decoder for s2ram
*
* (C) 2000,2001 Alan Cox <alan@redhat.com>
*
* 2-July-2001 Matt Domsch <Matt_Domsch@dell.com>
* Additional structures displayed per SMBIOS 2.3.1 spec
*
* (C) 2006 Pavel Machek <pavel@suse.cz>
*
* Licensed under the GNU General Public license v2.
*/
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <s2ram.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
struct dmi_header
{
u8 type;
u8 length;
u16 handle;
};
#ifdef S2RAM
#define PRINTF(a...)
#else
#define PRINTF printf
#endif
static char *dmi_string(struct dmi_header *dm, u8 s)
{
char *bp=(char *)dm;
if (!s) return "";
bp+=dm->length;
while (s>1) {
bp+=strlen(bp);
bp++;
s--;
}
return bp;
}
/*
* Copy a physical memory chunk into a memory buffer.
* This function allocates memory.
*/
void *mem_chunk(size_t base, size_t len)
{
void *p;
int fd;
size_t mmoffset;
void *mmp;
if((fd=open("/dev/mem", O_RDONLY))==-1){
perror("/dev/mem");
return NULL;
}
if((p=malloc(len))==NULL) {
perror("/dev/mem malloc");
return NULL;
}
mmoffset=base%getpagesize();
/*
* 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) {
perror("mmap");
free(p);
return NULL;
}
memcpy(p, (u8 *)mmp+mmoffset, len);
if(munmap(mmp, mmoffset+len)==-1)
perror("/dev/mem munmap");
if(close(fd)==-1)
perror("/dev/mem");
return p;
}
static void dmi_table(u32 base, int len, int num)
{
char *buf;
struct dmi_header *dm;
char *data;
int i=0;
if ((buf=mem_chunk(base, len))==0) {
printf("DMI Table is unreachable\n");
return;
}
data = buf;
while (i<num) {
u32 u;
u32 u2;
dm=(struct dmi_header *)data;
switch(dm->type)
{
case 0:
PRINTF("\tBIOS Information Block\n");
PRINTF("\t\tVendor: %s\n",
dmi_string(dm, data[4]));
strcpy(bios_version, dmi_string(dm, data[5]));
PRINTF("\t\tVersion: %s\n", bios_version);
PRINTF("\t\tRelease: %s\n",
dmi_string(dm, data[8]));
PRINTF("\t\tBIOS base: 0x%04X0\n",
data[7]<<8|data[6]);
PRINTF("\t\tROM size: %dK\n",
64*data[9]);
PRINTF("\t\tCapabilities:\n");
u=data[13]<<24|data[12]<<16|data[11]<<8|data[10];
u2=data[17]<<24|data[16]<<16|data[15]<<8|data[14];
PRINTF("\t\t\tFlags: 0x%08X%08X\n",
u2,u);
break;
case 1:
PRINTF("\tSystem Information Block\n");
strcpy(sys_vendor, dmi_string(dm, data[4]));
strcpy(sys_product, dmi_string(dm, data[5]));
strcpy(sys_version, dmi_string(dm, data[6]));
PRINTF("\t\tVendor: %s\n", sys_vendor);
PRINTF("\t\tProduct: %s\n", sys_product);
PRINTF("\t\tVersion: %s\n", sys_version);
PRINTF("\t\tSerial Number: %s\n",
dmi_string(dm, data[7]));
break;
case 2:
PRINTF("\tBoard Information Block\n");
PRINTF("\t\tVendor: %s\n",
dmi_string(dm, data[4]));
PRINTF("\t\tProduct: %s\n",
dmi_string(dm, data[5]));
PRINTF("\t\tVersion: %s\n",
dmi_string(dm, data[6]));
PRINTF("\t\tSerial Number: %s\n",
dmi_string(dm, data[7]));
break;
default:
break;
}
data+=dm->length;
while(*data || data[1])
data++;
data+=2;
i++;
}
free(buf);
}
void dmi_scan(void)
{
size_t fp;
u8 *buf;
if((buf=mem_chunk(0xF0000, 0x10000))==NULL)
return;
for(fp=0; fp<=0xFFF0; fp+=16) {
if(memcmp(buf+fp, "_DMI_", 5)==0) {
u8 *cur = buf+fp;
u16 num=cur[13]<<8|cur[12];
u16 len=cur[7]<<8|cur[6];
u32 base=cur[11]<<24|cur[10]<<16|cur[9]<<8|cur[8];
PRINTF("DMI %d.%d present.\n",
cur[14]>>4, cur[14]&0x0F);
PRINTF("%d structures occupying %d bytes.\n",
cur[13]<<8|cur[12],
cur[7]<<8|cur[6]);
PRINTF("DMI table at 0x%08X.\n",
cur[11]<<24|cur[10]<<16|cur[9]<<8|cur[8]);
dmi_table(base,len,num);
}
}
free(buf);
return;
}
#ifndef S2RAM
int main(int argc, char *argv[])
{
dmi_scan();
}
#endif