• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2010 Intel Corporation; author: H. Peter Anvin
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8  *   Boston MA 02110-1301, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12 
13 /*
14  * memdiskfind.c
15  *
16  * Simple utility to search for a MEMDISK instance and output the parameters
17  * needed to use the "phram" driver in Linux to map it.
18  */
19 
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30 #include "../memdisk/mstructs.h"
31 
32 #define MBFT_MIN_LENGTH	(36+4+26)
33 
valid_mbft(const struct mBFT * mbft,size_t space)34 static bool valid_mbft(const struct mBFT *mbft, size_t space)
35 {
36     uint8_t csum;
37     size_t i;
38 
39     if (memcmp(mbft->acpi.signature, "mBFT", 4))
40 	return false;
41 
42     if (mbft->acpi.length < MBFT_MIN_LENGTH)
43 	return false;
44 
45     if (mbft->acpi.length > space)
46 	return false;
47 
48     if ((size_t)mbft->acpi.length != (size_t)mbft->mdi.bytes + 36+4)
49 	return false;
50 
51     csum = 0;
52     for (i = 0; i < mbft->acpi.length; i++)
53 	csum += ((const uint8_t *)mbft)[i];
54 
55     if (csum)
56 	return false;
57 
58     return true;
59 }
60 
output_params(const struct mBFT * mbft)61 static void output_params(const struct mBFT *mbft)
62 {
63     int sector_shift = mbft->mdi.sector_shift;
64 
65     if (!sector_shift)
66 	sector_shift = 9;
67 
68     printf("%#x,%#x\n",
69 	   mbft->mdi.diskbuf, mbft->mdi.disksize << sector_shift);
70 }
71 
memlimit(void)72 static size_t memlimit(void)
73 {
74     char txtline[256], user[256];
75     size_t maxram = 0;
76     unsigned long long start, end;
77     FILE *iomem;
78 
79     iomem = fopen("/proc/iomem", "r");
80     if (!iomem)
81 	return 0;
82 
83     while (fgets(txtline, sizeof txtline, iomem) != NULL) {
84 	if (sscanf(txtline, "%llx-%llx : %[^\n]", &start, &end, user) != 3)
85 	    continue;
86 	if (strcmp(user, "System RAM"))
87 	    continue;
88 	if (start >= 0xa0000)
89 	    continue;
90 	maxram = (end >= 0xa0000) ? 0xa0000 : end+1;
91     }
92     fclose(iomem);
93 
94     return maxram;
95 }
96 
get_page_size(void)97 static inline size_t get_page_size(void)
98 {
99 #ifdef _SC_PAGESIZE
100     return sysconf(_SC_PAGESIZE);
101 #else
102     /* klibc, for one, doesn't have sysconf() due to excessive multiplex */
103     return getpagesize();
104 #endif
105 }
106 
main(int argc,char * argv[])107 int main(int argc, char *argv[])
108 {
109     const char *map;
110     int memfd;
111     size_t fbm;
112     const char *ptr, *end;
113     size_t page = get_page_size();
114     size_t mapbase, maplen;
115     int err = 1;
116 
117     (void)argc;
118 
119     mapbase = memlimit() & ~(page - 1);
120     if (!mapbase)
121 	return 2;
122 
123     memfd = open("/dev/mem", O_RDONLY);
124     if (memfd < 0) {
125 	fprintf(stderr, "%s: cannot open /dev/mem: %s\n",
126 		argv[0], strerror(errno));
127 	return 2;
128     }
129 
130     map = mmap(NULL, page, PROT_READ, MAP_SHARED, memfd, 0);
131     if (map == MAP_FAILED) {
132 	fprintf(stderr, "%s: cannot map page 0: %s\n",
133 		argv[0], strerror(errno));
134 	return 2;
135     }
136 
137     fbm = *(uint16_t *)(map + 0x413) << 10;
138     if (fbm < mapbase)
139 	fbm = mapbase;
140 
141     munmap((void *)map, page);
142 
143     if (fbm < 64*1024 || fbm >= 640*1024)
144 	return 1;
145 
146     maplen  = 0xa0000 - mapbase;
147     map = mmap(NULL, maplen, PROT_READ, MAP_SHARED, memfd, mapbase);
148     if (map == MAP_FAILED) {
149 	fprintf(stderr, "%s: cannot map base memory: %s\n",
150 		argv[0], strerror(errno));
151 	return 2;
152     }
153 
154     ptr = map + (fbm - mapbase);
155     end = map + (0xa0000 - mapbase);
156     while (ptr < end) {
157 	if (valid_mbft((const struct mBFT *)ptr, end-ptr)) {
158 	    output_params((const struct mBFT *)ptr);
159 	    err = 0;
160 	    break;
161 	}
162 	ptr += 16;
163     }
164 
165     munmap((void *)map, maplen);
166 
167     return err;
168 }
169