summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perl-install/c/smp-dmi.c155
1 files changed, 89 insertions, 66 deletions
diff --git a/perl-install/c/smp-dmi.c b/perl-install/c/smp-dmi.c
index 241d8f464..60a92b9d6 100644
--- a/perl-install/c/smp-dmi.c
+++ b/perl-install/c/smp-dmi.c
@@ -12,6 +12,7 @@
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
+#include <sys/mman.h>
typedef unsigned char u8;
typedef unsigned short u16;
@@ -50,6 +51,34 @@ dump_raw_data(void *data, unsigned int length)
}
+#define DEFAULT_MEM_DEV "/dev/mem"
+
+void *mem_chunk(u32 base, u32 len, const char *devmem)
+{
+ void *p;
+ int fd;
+ off_t mmoffset;
+ void *mmp;
+
+ if ((fd = open(devmem, O_RDONLY)) < 0)
+ return NULL;
+
+ if ((p = malloc(len)) == NULL)
+ return NULL;
+
+ mmoffset = base % getpagesize();
+ mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset);
+ if (mmp == MAP_FAILED) {
+ free(p);
+ return NULL;
+ }
+
+ memcpy(p, (u8 *)mmp + mmoffset, len);
+ munmap(mmp, mmoffset + len);
+ close(fd);
+ return p;
+}
+
struct dmi_header
{
@@ -135,78 +164,65 @@ static char *dmi_processor_family(u8 code)
typedef int (*dmi_decode)(u8 * data);
-static int decode_handle(int fd, u32 base, int len, int num, dmi_decode decode)
+static int decode_handle(u32 base, int len, int num, dmi_decode decode)
{
- u8 *buf = malloc(len);
- struct dmi_header *dm;
- u8 *data;
- int i = 0;
- int ret = 0;
-
- if (lseek(fd, (long)base, 0) == -1) {
- perror("dmi: lseek");
- return;
- }
- if (read(fd, buf, len)!=len) {
- perror("dmi: read");
- return;
- }
- data = buf;
- while(i<num && data+sizeof(struct dmi_header)<=buf+len)
- {
- u8 *next;
- struct dmi_header *dm = (struct dmi_header *)data;
-
- /* look for the next handle */
- next=data+dm->length;
- while(next-buf+1<len && (next[0]!=0 || next[1]!=0))
- next++;
- next+=2;
- if(next-buf<=len)
- ret += decode(data);
- else {
- ret = 0; /* TRUNCATED */
- break;
- }
- data=next;
- i++;
+ u8 *buf;
+ u8 *data;
+ int i = 0;
+ int ret = 0;
+
+ if ((buf = mem_chunk(base, len, DEFAULT_MEM_DEV)) == NULL)
+ return 0;
+
+ data = buf;
+ while(i<num && data+sizeof(struct dmi_header)<=buf+len)
+ {
+ u8 *next;
+ struct dmi_header *dm = (struct dmi_header *)data;
+
+ /* look for the next handle */
+ next=data+dm->length;
+ while(next-buf+1<len && (next[0]!=0 || next[1]!=0))
+ next++;
+ next+=2;
+ if(next-buf<=len)
+ ret += decode(data);
+ else {
+ ret = 0; /* TRUNCATED */
+ break;
}
- free(buf);
- return ret;
+ data=next;
+ i++;
+ }
+
+ free(buf);
+ return ret;
}
static int dmi_detect(dmi_decode decode) {
- unsigned char buf[20];
- int fd = open("/dev/mem", O_RDONLY);
- long fp = 0xE0000L;
- int ret = 0;
-
- if (fd == -1) {
- perror("/dev/mem");
- exit(1);
- }
- if (lseek(fd, fp, 0) == -1) {
- perror("seek");
- exit(1);
- }
-
- while (fp < 0xFFFFF)
- {
- if (read(fd, buf, 16) != 16)
- perror("read");
-
- if (memcmp(buf, "_DMI_", 5) == 0) {
- u16 num = buf[13]<<8|buf[12];
- u16 len = buf[7]<<8|buf[6];
- u32 base = buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
-
- ret = decode_handle(fd, base, len, num, decode);
- break;
- }
- fp += 16;
+ u8 *buf;
+ long fp;
+ int ret;
+
+ if ((buf = mem_chunk(0xf0000, 0x10000, DEFAULT_MEM_DEV)) == NULL) {
+ perror("dmi_detect");
+ exit(1);
+ }
+
+ for (fp = 0; fp <= 0xfff0; fp += 16) {
+ if (memcmp(buf + fp, "_DMI_", 5) == 0) {
+ u8 *p = buf + fp;
+ u16 num = p[13]<<8|p[12];
+ u16 len = p[7]<<8|p[6];
+ u32 base = p[11]<<24|p[10]<<16|p[9]<<8|p[8];
+
+ ret = decode_handle(base, len, num, decode);
+ break;
}
- close(fd);
- return ret;
+ }
+
+ free(buf);
+ return ret;
}
static int processor(u8 *data) {
@@ -300,3 +316,10 @@ int dmiDetectMemory(void) {
int s2 = dmi_detect(memory_in_MB_type17);
return s1 > s2 ? s1 : s2;
}
+
+#ifdef TEST
+int main(void)
+{
+ printf("Memory Size: %d MB\n", dmiDetectMemory());
+}
+#endif