fat: Make mangle behavior similar to the standard one
[profile/ivi/syslinux.git] / utils / memdiskfind.c
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
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
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
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
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
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 }