xref: /netbsd-src/usr.sbin/memswitch/memswitch.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: memswitch.c,v 1.15 2018/01/26 09:38:26 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Minoura Makoto.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /* memswitch.c */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <err.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 
42 #include <sys/ioctl.h>
43 
44 #ifndef SRAMDEBUG
45 #include <machine/sram.h>
46 #else
47 /*
48  * SRAMDEBUG -- works on other (faster) platforms;
49  *   store in a regular file instead of actual non-volatile static RAM.
50  */
51 #define PATH_RAMFILE "/tmp/sramfile"
52 #endif
53 
54 #include "memswitch.h"
55 
56 char *progname;
57 int nflag = 0;
58 u_int8_t *current_values = 0;
59 u_int8_t *modified_values = 0;
60 
61 static void
62 usage(void)
63 {
64 	fprintf(stderr, "usage: %s -a\n", progname);
65 	fprintf(stderr, "       %s [-h] variable ...\n", progname);
66 	fprintf(stderr, "       %s -w variable=value ...\n", progname);
67 	fprintf(stderr, "       %s [-rs] filename\n", progname);
68 	exit(1);
69 }
70 
71 int
72 main(int argc, char *argv[])
73 {
74 	int ch;
75 	enum md {
76 		MD_NONE, MD_WRITE, MD_HELP, MD_SHOWALL, MD_SAVE, MD_RESTORE
77 	} mode = MD_NONE;
78 
79 	progname = argv[0];
80 
81 	while ((ch = getopt(argc, argv, "whanrs")) != -1) {
82 		switch (ch) {
83 		case 'w':	/* write */
84 			mode = MD_WRITE;
85 			break;
86 		case 'h':
87 			mode = MD_HELP;
88 			break;
89 		case 'a':
90 			mode = MD_SHOWALL;
91 			break;
92 		case 'n':
93 			nflag = 1;
94 			break;
95 		case 's':
96 			mode = MD_SAVE;
97 			break;
98 		case 'r':
99 			mode = MD_RESTORE;
100 			break;
101 		}
102 	}
103 	argc -= optind;
104 	argv += optind;
105 
106 	switch (mode) {
107 	case MD_NONE:
108 		if (argc == 0)
109 			usage();
110 		while (argv[0]) {
111 			show_single(argv[0]);
112 			argv++;
113 		}
114 		break;
115 	case MD_SHOWALL:
116 		if (argc)
117 			usage();
118 		show_all();
119 		break;
120 	case MD_WRITE:
121 		if (argc == 0)
122 			usage();
123 		while (argv[0]) {
124 			modify_single (argv[0]);
125 			argv++;
126 		}
127 		flush();
128 		break;
129 	case MD_HELP:
130 		if (argc == 0)
131 			usage();
132 		while (argv[0]) {
133 			help_single(argv[0]);
134 			argv++;
135 		}
136 		break;
137 	case MD_SAVE:
138 		if (argc != 1)
139 			usage();
140 		save(argv[0]);
141 		break;
142 	case MD_RESTORE:
143 		if (argc != 1)
144 			usage();
145 		restore(argv[0]);
146 		break;
147 
148 	}
149 
150 	return 0;
151 }
152 
153 void
154 show_single(const char *name)
155 {
156 	int i;
157 	int n = 0;
158 	char fullname[50];
159 	char valuestr[MAXVALUELEN];
160 
161 	for (i = 0; i < number_of_props; i++) {
162 		snprintf(fullname, sizeof(fullname), "%s.%s",
163 			 properties[i].class, properties[i].node);
164 		if (strcmp(name, fullname) == 0 || strcmp(name, properties[i].class) == 0) {
165 			properties[i].print(&properties[i], valuestr);
166 			if (!nflag)
167 				printf("%s=%s\n", fullname, valuestr);
168 			n++;
169 		}
170 	}
171 	if (n == 0) {
172 		errx(1, "No such %s: %s", strstr(name, ".")?"property":"class", name);
173 	}
174 
175 	return;
176 }
177 
178 void
179 show_all(void)
180 {
181 	int i;
182 	char valuestr[MAXVALUELEN];
183 
184 	for (i = 0; i < number_of_props; i++) {
185 		properties[i].print(&properties[i], valuestr);
186 		if (!nflag)
187 			printf("%s.%s=",
188 			       properties[i].class, properties[i].node);
189 		printf("%s\n", valuestr);
190 	}
191 
192 	return;
193 }
194 
195 void
196 modify_single(const char *expr)
197 {
198 	int i, l, n;
199 	char *class = NULL, *node = NULL;
200 	const char *value;
201 	char valuestr[MAXVALUELEN];
202 
203 	l = 0;
204 	n = strlen(expr);
205 	for (i = 0; i < n; i++) {
206 		if (expr[i] == '.') {
207 			l = i + 1;
208 			class = alloca(l);
209 			if (class == 0)
210 				err(1, "alloca");
211 			strncpy(class, expr, i);
212 			class[i] = 0;
213 			break;
214 		}
215 	}
216 	if (i >= n)
217 		errx(1, "Invalid expression: %s", expr);
218 
219 	for ( ; i < n; i++) {
220 		if (expr[i] == '=') {
221 			node = alloca(i - l + 1);
222 			if (node == 0)
223 				err(1, "alloca");
224 			strncpy(node, &(expr[l]), i - l);
225 			node[i - l] = 0;
226 			break;
227 		}
228 	}
229 	if (i >= n)
230 		errx(1, "Invalid expression: %s", expr);
231 
232 	value = &(expr[++i]);
233 
234 	for (i = 0; i < number_of_props; i++) {
235 		if (strcmp(properties[i].class, class) == 0 &&
236 		    strcmp(properties[i].node, node) == 0) {
237 			if (properties[i].parse(&properties[i], value) < 0) {
238 				/* error: do nothing */
239 			} else {
240 				properties[i].print(&properties[i], valuestr);
241 				printf("%s.%s -> %s\n", class, node, valuestr);
242 			}
243 			break;
244 		}
245 	}
246 	if (i >= number_of_props) {
247 		errx(1, "No such property: %s.%s", class, node);
248 	}
249 
250 	return;
251 }
252 
253 void
254 help_single(const char *name)
255 {
256 	int i;
257 	char fullname[50];
258 	char valuestr[MAXVALUELEN];
259 
260 	for (i = 0; i < number_of_props; i++) {
261 		snprintf(fullname, sizeof(fullname), "%s.%s",
262 		    properties[i].class, properties[i].node);
263 		if (strcmp(name, fullname) == 0) {
264 			properties[i].print(&properties[i], valuestr);
265 			if (!nflag)
266 				printf("%s=", fullname);
267 			printf("%s\n", valuestr);
268 			printf("%s", properties[i].descr);
269 			break;
270 		}
271 	}
272 	if (i >= number_of_props) {
273 		errx(1, "No such property: %s", name);
274 	}
275 
276 	return;
277 }
278 
279 void
280 alloc_modified_values(void)
281 {
282 	if (current_values == 0)
283 		alloc_current_values();
284 	modified_values = malloc(256);
285 	if (modified_values == 0)
286 		err(1, "malloc");
287 	memcpy(modified_values, current_values, 256);
288 }
289 
290 void
291 alloc_current_values(void)
292 {
293 #ifndef SRAMDEBUG
294 	int i;
295 	int sramfd = 0;
296 	struct sram_io buffer;
297 
298 	current_values = malloc(256);
299 	if (current_values == 0)
300 		err(1, "malloc");
301 
302 	sramfd = open(_PATH_DEVSRAM, O_RDONLY);
303 	if (sramfd < 0)
304 		err(1, "Opening %s", _PATH_DEVSRAM);
305 
306 	/* Assume SRAM_IO_SIZE = n * 16. */
307 	for (i = 0; i < 256; i += SRAM_IO_SIZE) {
308 		buffer.offset = i;
309 		if (ioctl(sramfd, SIOGSRAM, &buffer) < 0)
310 			err(1, "ioctl");
311 		memcpy(&current_values[i], buffer.sram, SRAM_IO_SIZE);
312 	}
313 
314 	close(sramfd);
315 #else
316 	int i;
317 	int fd;
318 	struct stat st;
319 
320 	current_values = malloc(256);
321 	if (current_values == 0)
322 		err(1, "malloc");
323 
324 	fd = open(PATH_RAMFILE, O_RDONLY);
325 	if (fd < 0 && errno == ENOENT) {
326 		modified_values = malloc(256);
327 		if (modified_values == 0)
328 			err(1, NULL);
329 		for (i = 0; i < number_of_props; i++) {
330 			properties[i].modified_value
331 			    = properties[i].default_value;
332 			properties[i].modified = 1;
333 			properties[i].flush(&properties[i]);
334 		}
335 
336 		fd = creat(PATH_RAMFILE, 0666);
337 		if (fd < 0)
338 			err(1, "Creating %s", PATH_RAMFILE);
339 		if (write(fd, modified_values, 256) != 256)
340 			err(1, "Writing %s", PATH_RAMFILE);
341 		close(fd);
342 		free(modified_values);
343 		modified_values = 0;
344 
345 		fd = open(PATH_RAMFILE, O_RDONLY);
346 	}
347 	if (fd < 0)
348 		err(1, "Opening %s", PATH_RAMFILE);
349 	if (fstat(fd, &st) < 0)
350 		err(1, "fstat");
351 	if (st.st_size != 256)
352 		errx(1, "PANIC! INVALID RAMFILE");
353 	if (read(fd, current_values, 256) != 256)
354 		err(1, "reading %s", PATH_RAMFILE);
355 	close(fd);
356 #endif
357 
358 	properties[PROP_MAGIC1].fill(&properties[PROP_MAGIC1]);
359 	properties[PROP_MAGIC2].fill(&properties[PROP_MAGIC2]);
360 	if ((properties[PROP_MAGIC1].current_value.longword != MAGIC1) ||
361 	    (properties[PROP_MAGIC2].current_value.longword != MAGIC2))
362 		errx(1, "PANIC! INVALID MAGIC");
363 }
364 
365 void
366 flush(void)
367 {
368 	int i;
369 	int sramfd = 0;
370 #ifndef SRAMDEBUG
371 	struct sram_io buffer;
372 #endif
373 
374 	for (i = 0; i < number_of_props; i++) {
375 		if (properties[i].modified)
376 			properties[i].flush(&properties[i]);
377 	}
378 
379 	if (modified_values == 0)
380 		/* Not modified at all. */
381 		return;
382 
383 #ifndef SRAMDEBUG
384 	/* Assume SRAM_IO_SIZE = n * 16. */
385 	for (i = 0; i < 256; i += SRAM_IO_SIZE) {
386 		if (memcmp(&current_values[i], &modified_values[i],
387 			   SRAM_IO_SIZE) == 0)
388 			continue;
389 
390 		if (sramfd == 0) {
391 			sramfd = open(_PATH_DEVSRAM, O_RDWR);
392 			if (sramfd < 0)
393 				err(1, "Opening %s", _PATH_DEVSRAM);
394 		}
395 		buffer.offset = i;
396 		memcpy(buffer.sram, &modified_values[i], SRAM_IO_SIZE);
397 		if (ioctl(sramfd, SIOPSRAM, &buffer) < 0)
398 			err(1, "ioctl");
399 	}
400 #else
401 	sramfd = open(PATH_RAMFILE, O_WRONLY);
402 	if (sramfd < 0)
403 		err(1, "Opening %s", PATH_RAMFILE);
404 	if (write(sramfd, modified_values, 256) != 256)
405 		err(1, "Writing %s", PATH_RAMFILE);
406 #endif
407 
408 	if (sramfd != 0)
409 		close(sramfd);
410 
411 	return;
412 }
413 
414 int
415 save(const char *name)
416 {
417 #ifndef SRAMDEBUG
418 	int fd;
419 
420 	alloc_current_values();
421 
422 	if (strcmp(name, "-") == 0)
423 		fd = 1;		/* standard output */
424 	else {
425 		fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
426 		if (fd < 0)
427 			err(1, "Opening output file");
428 	}
429 
430 	if (write(fd, current_values, 256) != 256)
431 		err(1, "Writing output file");
432 
433 	if (fd != 1)
434 		close(fd);
435 #else
436 	fprintf(stderr, "Skipping save...\n");
437 #endif
438 
439 	return 0;
440 }
441 
442 int
443 restore(const char *name)
444 {
445 #ifndef SRAMDEBUG
446 	int sramfd, fd, i;
447 	struct sram_io buffer;
448 
449 	modified_values = malloc(256);
450 	if (modified_values == 0)
451 		err(1, "Opening %s", _PATH_DEVSRAM);
452 
453 	if (strcmp(name, "-") == 0)
454 		fd = 0;		/* standard input */
455 	else {
456 		fd = open(name, O_RDONLY);
457 		if (fd < 0)
458 			err(1, "Opening input file");
459 	}
460 
461 	if (read(fd, modified_values, 256) != 256)
462 		err(1, "Reading input file");
463 
464 	if (fd != 0)
465 		close(fd);
466 
467 	sramfd = open(_PATH_DEVSRAM, O_RDWR);
468 	if (sramfd < 0)
469 		err(1, "Opening %s", _PATH_DEVSRAM);
470 
471 	/* Assume SRAM_IO_SIZE = n * 16. */
472 	for (i = 0; i < 256; i += SRAM_IO_SIZE) {
473 		buffer.offset = i;
474 		memcpy(buffer.sram, &modified_values[i], SRAM_IO_SIZE);
475 		if (ioctl(sramfd, SIOPSRAM, &buffer) < 0)
476 			err(1, "ioctl");
477 	}
478 
479 	close(sramfd);
480 #else
481 	fprintf(stderr, "Skipping restore...\n");
482 #endif
483 
484 	return 0;
485 }
486