Merge branch 'wip-xinfo-fixed' into xseg
[archipelago] / xseg / sys / segtool.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <sys/ioctl.h>
8 #include <sys/mman.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <string.h>
12
13 #include "xsegdev.h"
14
15 int help(void)
16 {
17         printf("segtool [<command> <arg>]* \n"
18                 "commands:\n"
19                 "    create <size_in_bytes>\n"
20                 "    destroy\n"
21                 "    info\n"
22                 "    map <offset> <size_in_bytes>\n"
23                 "    unmap <size_in_bytes>\n"
24                 "    dump <offset> <size_in_bytes>\n"
25                 "    load <offset>\n"
26                 "    fill <offset> <size_in_bytes> <char_in_hex>\n"
27                 "    mark\n"
28                 "    checkmark\n"
29                 "    wait\n"
30         );
31         return 1;
32 }
33
34 #define ALLOC_MIN 4096
35 #define ALLOC_MAX 1048576
36
37 void inputbuf(FILE *fp, char **retbuf, uint64_t *retsize)
38 {
39         static uint64_t alloc_size;
40         static char *buf;
41         uint64_t size = 0;
42         char *p;
43         size_t r;
44
45         if (alloc_size < ALLOC_MIN)
46                 alloc_size = ALLOC_MIN;
47
48         if (alloc_size > ALLOC_MAX)
49                 alloc_size = ALLOC_MAX;
50
51         p = realloc(buf, alloc_size);
52         if (!p) {
53                 if (buf)
54                         free(buf);
55                 buf = NULL;
56                 goto out;
57         }
58
59         buf = p;
60
61         while (!feof(fp)) {
62                 r = fread(buf + size, 1, alloc_size - size, fp);
63                 if (!r)
64                         break;
65                 size += r;
66                 if (size >= alloc_size) {
67                         p = realloc(buf, alloc_size * 2);
68                         if (!p) {
69                                 if (buf)
70                                         free(buf);
71                                 buf = NULL;
72                                 size = 0;
73                                 goto out;
74                         }
75                         buf = p;
76                         alloc_size *= 2;
77                 }
78         }
79
80 out:
81         *retbuf = buf;
82         *retsize = size;
83 }
84
85 static int opendev(void)
86 {
87         int fd = open("/dev/xsegdev", O_RDWR);
88         if (fd < 0)
89                 perror("/dev/xsegdev");
90         return fd;
91 }
92
93 static char *segment;
94 static unsigned long mapped_size;
95
96 int cmd_create(uint64_t size)
97 {
98         int r, fd = opendev();
99         if (fd < 0)
100                 return fd;
101
102         r = ioctl(fd, XSEGDEV_IOC_CREATESEG, size);
103         if (r < 0)
104                 perror("CREATESEG");
105
106         close(fd);
107         return 0;
108 }
109
110 int cmd_destroy(void)
111 {
112         int r, fd = opendev();
113         if (fd < 0)
114                 return fd;
115
116         r = ioctl(fd, XSEGDEV_IOC_DESTROYSEG, 0);
117         if (r < 0)
118                 perror("DESTROYSEG");
119
120         close(fd);
121         return 0;
122 }
123
124 int cmd_info(void)
125 {
126         long r, fd = opendev();
127         if (fd < 0)
128                 return fd;
129
130         r = ioctl(fd, XSEGDEV_IOC_SEGSIZE, 0);
131         if (r < 0)
132                 perror("SEGSIZE");
133         else
134                 printf("Segment size: %lu bytes\n", r);
135         close(fd);
136         return 0;
137 }
138
139 int cmd_map(uint64_t offset, uint64_t size)
140 {
141         char *seg;
142         long r = -1, fd = opendev();
143         if (fd < 0)
144                 goto out;
145
146         r = 0;
147         if (segment)
148                 goto out;
149
150         if (!size) {
151                 r = ioctl(fd, XSEGDEV_IOC_SEGSIZE, 0);
152                 if (r < 0) {
153                         perror("SEGSIZE");
154                         goto out;
155                 }
156                 size = r - offset;
157         }
158
159         if (offset + size > r) {
160                 printf("segment size would be exceeded\n");
161                 goto out;
162         }
163
164         r = -1;
165         //seg = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
166         seg = mmap( (void*) 0x37fd0000, size,
167                         PROT_READ | PROT_WRITE,
168                         MAP_SHARED | MAP_FIXED,
169                         fd, offset);
170         if (seg == MAP_FAILED) {
171                 perror("mmap");
172                 goto out;
173         }
174
175         segment = seg;
176         mapped_size = size;
177 out:
178         close(fd);
179         return r;
180 }
181
182 int cmd_unmap(uint64_t size)
183 {
184         long r = -1, fd = opendev();
185         if (fd < 0)
186                 goto out;
187
188         r = 0;
189         if (!segment)
190                 goto out;
191
192         if (!size)
193                 size = mapped_size;
194
195         r = munmap(segment, size);
196         if (r < 0)
197                 perror("munmap");
198         else {
199                 segment = NULL;
200                 mapped_size = 0;
201         }
202
203 out:
204         close(fd);
205         return r;
206 }
207
208 int cmd_wait(void)
209 {
210         int c, fd = open("/dev/tty", O_RDONLY);
211         c = read(fd, &c, 1);
212         close(fd);
213         return 0;
214 }
215
216 int cmd_dump(uint64_t offset, uint64_t size)
217 {
218         long r = -1, fd = opendev();
219         if (fd < 0)
220                 goto out;
221
222         if (!segment) {
223                 printf("segment not mapped\n");
224                 goto out;
225         }
226
227         if (!size)
228                 size = mapped_size - offset;
229
230         if (offset + size > mapped_size) {
231                 printf("mapped segment size would be exceeded\n");
232                 goto out;
233         }
234
235         for (r = offset; r < offset + size; r++)
236                 if (fputc(segment[r], stdout) == EOF)
237                         break;
238
239         fflush(stdout);
240         r = 0;
241 out:
242         close(fd);
243         return r;
244 }
245
246 int cmd_load(uint64_t offset)
247 {
248         long r = -1, fd = opendev();
249         unsigned long pos;
250
251         if (fd < 0)
252                 goto out;
253
254         if (!segment) {
255                 printf("segment not mapped\n");
256                 goto out;
257         }
258
259         for (pos = offset; pos < mapped_size; pos++) {
260                 int c = fgetc(stdin);
261                 if (c == EOF)
262                         break;
263                 segment[pos] = c;
264         }
265 out:
266         close(fd);
267         return r;
268 }
269
270 int cmd_fill(uint64_t offset, uint64_t size, int fill)
271 {
272         long r = -1, fd = opendev();
273         uint64_t misscount = 0;
274
275         if (fd < 0)
276                 goto out;
277
278         if (!segment) {
279                 printf("segment not mapped\n");
280                 goto out;
281         }
282
283         if (size == 0)
284                 size = mapped_size - offset;
285
286         if (offset + size > mapped_size) {
287                 printf("mapped segment size would be exceeded\n");
288                 goto out;
289         }
290
291         memset(segment + offset, fill, size);
292         for (size += offset; offset < size; offset++)
293                 if (segment[offset] != (char)fill)
294                         misscount ++;
295
296         if (misscount)
297                 printf("fill misscount(!) %lu\n", misscount);
298 out:
299         close(fd);
300         return r;
301 }
302
303 int cmd_mark(void)
304 {
305         unsigned long i, count;
306         unsigned long *longs;
307
308         if (!segment) {
309                 printf("segment not mapped\n");
310                 return -1;
311         }
312
313         longs = (void *)segment;
314         count = mapped_size / sizeof(long);
315         for (i = 0; i < count; i++)
316                 longs[i] = i;
317
318         return 0;
319 }
320
321 int cmd_checkmark(void)
322 {
323         unsigned long i, count;
324         unsigned long *longs;
325
326         if (!segment) {
327                 printf("segment not mapped\n");
328                 return -1;
329         }
330
331         longs = (void *)segment;
332         count = mapped_size / sizeof(long);
333         for (i = 0; i < count; i++)
334                 if (longs[i] != i)
335                         printf("%lu != %lu\n", i, longs[i]);
336         return 0;
337 }
338
339 int main(int argc, char **argv) {
340
341         int i, ret = 0;
342
343         if (argc < 2)
344                 return help();
345
346         for (i = 1; i < argc; i++) {
347
348                 if (!strcmp(argv[i], "info")) {
349                         ret = cmd_info();
350                         continue;
351                 }
352
353                 if (!strcmp(argv[i], "create") && (i + 1 < argc)) {
354                         ret = cmd_create(atol(argv[i+1]));
355                         i += 1;
356                         continue;
357                 }
358
359                 if (!strcmp(argv[i], "destroy")) {
360                         ret = cmd_destroy();
361                         continue;
362                 }
363
364                 if (!strcmp(argv[i], "wait")) {
365                         ret = cmd_wait();
366                         continue;
367                 }
368
369                 if (!strcmp(argv[i], "mark")) {
370                         ret = cmd_mark();
371                         continue;
372                 }
373
374                 if (!strcmp(argv[i], "checkmark")) {
375                         ret = cmd_checkmark();
376                         continue;
377                 }
378
379                 if (!strcmp(argv[i], "map") && (i + 2 < argc)) {
380                         ret = cmd_map(atol(argv[i+1]), atol(argv[i+2]));
381                         i += 2;
382                         continue;
383                 }
384
385                 if (!strcmp(argv[i], "unmap") && (i + 1 < argc)) {
386                         ret = cmd_unmap(atol(argv[i+1]));
387                         i += 1;
388                         continue;
389                 }
390
391                 if (!strcmp(argv[i], "fill") && (i + 3 < argc)) {
392                         ret = cmd_fill( atol(argv[i+1]),
393                                         atol(argv[i+2]),
394                                         strtoul(argv[i+3], NULL, 16));
395                         i += 3;
396                         continue;
397                 }
398
399                 if (!strcmp(argv[i], "dump") && (i + 2 < argc)) {
400                         ret = cmd_dump(atol(argv[i+1]), atol(argv[i+2]));
401                         i += 2;
402                         continue;
403                 }
404
405                 if (!strcmp(argv[i], "load") && (i + 1 < argc)) {
406                         ret = cmd_load(atol(argv[i+1]));
407                         i += 1;
408                         continue;
409                 }
410
411                 return help();
412         }
413
414         return ret;
415 }