xref: /openbsd-src/usr.sbin/memconfig/memconfig.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /* $OpenBSD: memconfig.c,v 1.3 2001/07/27 20:34:36 pvalchev Exp $ */
2 /*-
3  * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/usr.sbin/memcontrol/memcontrol.c,v 1.3 1999/08/28 01:17:00 peter Exp $
28  */
29 
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #include <sys/memrange.h>
33 
34 #include <err.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 struct
42 {
43 	char	*name;
44 	int		val;
45 	int		kind;
46 #define MDF_SETTABLE	(1<<0)
47 } attrnames[] = {
48 	{"uncacheable",		MDF_UNCACHEABLE,	MDF_SETTABLE},
49 	{"write-combine",	MDF_WRITECOMBINE,	MDF_SETTABLE},
50 	{"write-through",	MDF_WRITETHROUGH,	MDF_SETTABLE},
51 	{"write-back",		MDF_WRITEBACK,		MDF_SETTABLE},
52 	{"write-protect",	MDF_WRITEPROTECT,	MDF_SETTABLE},
53 	{"fixed-base",		MDF_FIXBASE,		0},
54 	{"fixed-length",	MDF_FIXLEN,		0},
55 	{"set-by-firmware",	MDF_FIRMWARE,		0},
56 	{"active",		MDF_ACTIVE,		MDF_SETTABLE},
57 	{"bogus",		MDF_BOGUS,		0},
58 	{NULL,			0,			0}
59 };
60 
61 static void	listfunc __P((int, int, char *[]));
62 static void	setfunc __P((int, int, char *[]));
63 static void	clearfunc __P((int, int, char *[]));
64 static void	helpfunc __P((int, int, char *[]));
65 static void	help __P((char *));
66 
67 struct
68 {
69 	char	*cmd;
70 	char	*desc;
71 	void	(*func) __P((int, int, char *[]));
72 } functions[] = {
73 	{"list",
74 	 "List current memory range attributes\n"
75 	 "    list [-a]\n"
76 	 "        -a    list all range slots, even those that are inactive",
77 	 listfunc},
78 	{"set",
79 	 "Set memory range attributes\n"
80 	 "    set -b <base> -l <length> -o <owner> <attribute>\n"
81 	 "        <base>      memory range base address\n"
82 	 "        <length>    length of memory range in bytes, power of 2\n"
83 	 "        <owner>     text identifier for this setting (7 char max)\n"
84 	 "        <attribute> attribute(s) to be applied to this range:\n"
85 	 "                        uncacheable\n"
86 	 "                        write-combine\n"
87 	 "                        write-through\n"
88 	 "                        write-back\n"
89 	 "                        write-protect",
90 	 setfunc},
91 	{"clear",
92 	 "Clear memory range attributes\n"
93 	 "    clear -o <owner>\n"
94 	 "        <owner>     all ranges with this owner will be cleared\n"
95 	 "    clear -b <base> -l <length>\n"
96 	 "        <base>      memory range base address\n"
97 	 "        <length>    length of memory range in bytes, power of 2\n"
98 	 "                    Base and length must exactly match an existing range",
99 	 clearfunc},
100 	{NULL,	NULL,					helpfunc}
101 };
102 
103 int
104 main(argc, argv)
105 	int 	 argc;
106 	char 	*argv[];
107 {
108 	int	 i, memfd;
109 
110 	if (argc < 2) {
111 		help(NULL);
112 	} else {
113 		if ((memfd = open("/dev/mem", O_RDONLY)) == -1)
114 			err(1, "can't open /dev/mem");
115 
116 		for (i = 0; functions[i].cmd != NULL; i++)
117 			if (!strcmp(argv[1], functions[i].cmd))
118 				break;
119 		functions[i].func(memfd, argc - 1, argv + 1);
120 		close(memfd);
121 	}
122 	return(0);
123 }
124 
125 static struct mem_range_desc *
126 mrgetall(memfd, nmr)
127 	int 	 memfd;
128 	int 	*nmr;
129 {
130 	struct mem_range_desc	*mrd;
131 	struct mem_range_op		mro;
132 
133 	mro.mo_arg[0] = 0;
134 	if (ioctl(memfd, MEMRANGE_GET, &mro))
135 		err(1, "can't size range descriptor array");
136 
137 	*nmr = mro.mo_arg[0];
138 	mrd = malloc(*nmr * sizeof(struct mem_range_desc));
139 	if (mrd == NULL)
140 		errx(1, "can't allocate %d bytes for %d range descriptors",
141 		     *nmr * sizeof(struct mem_range_desc), *nmr);
142 
143 	mro.mo_arg[0] = *nmr;
144 	mro.mo_desc = mrd;
145 	if (ioctl(memfd, MEMRANGE_GET, &mro))
146 		err(1, "can't fetch range descriptor array");
147 
148 	return(mrd);
149 }
150 
151 
152 static void
153 listfunc(memfd, argc, argv)
154 	int 	 memfd;
155 	int 	 argc;
156 	char 	*argv[];
157 {
158 	struct mem_range_desc	*mrd;
159 	int			 nd, i, j;
160 	int			 ch;
161 	int			 showall = 0;
162 	char			*owner;
163 
164 	owner = NULL;
165 	while ((ch = getopt(argc, argv, "ao:")) != -1)
166 		switch(ch) {
167 		case 'a':
168 			showall = 1;
169 			break;
170 		case 'o':
171 			owner = strdup(optarg);
172 			break;
173 		case '?':
174 		default:
175 			help("list");
176 		}
177 
178 	mrd = mrgetall(memfd, &nd);
179 
180 	for (i = 0; i < nd; i++) {
181 		if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE))
182 			continue;
183 		if (owner && strcmp(mrd[i].mr_owner, owner))
184 			continue;
185 		printf("%qx/%qx %.8s ", mrd[i].mr_base, mrd[i].mr_len,
186 		       mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-");
187 		for (j = 0; attrnames[j].name != NULL; j++)
188 			if (mrd[i].mr_flags & attrnames[j].val)
189 				printf("%s ", attrnames[j].name);
190 		printf("\n");
191 	}
192 	free(mrd);
193 	if (owner)
194 		free(owner);
195 }
196 
197 static void
198 setfunc(memfd, argc, argv)
199 	int 	 memfd;
200 	int 	 argc;
201 	char 	*argv[];
202 {
203 	struct mem_range_desc	 mrd;
204 	struct mem_range_op	 mro;
205 	int			 i;
206 	int			 ch;
207 	char			*ep;
208 
209 	mrd.mr_base = 0;
210 	mrd.mr_len = 0;
211 	mrd.mr_flags = 0;
212 	strcpy(mrd.mr_owner, "user");
213 	while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
214 		switch(ch) {
215 		case 'b':
216 			mrd.mr_base = strtouq(optarg, &ep, 0);
217 			if ((ep == optarg) || (*ep != 0))
218 				help("set");
219 			break;
220 		case 'l':
221 			mrd.mr_len = strtouq(optarg, &ep, 0);
222 			if ((ep == optarg) || (*ep != 0))
223 				help("set");
224 			break;
225 		case 'o':
226 			if (*optarg == 0 ||
227 			    strlen(optarg) > sizeof(mrd.mr_owner)-1)
228 				help("set");
229 			strcpy(mrd.mr_owner, optarg);
230 			break;
231 
232 		case '?':
233 		default:
234 			help("set");
235 		}
236 
237 	if (mrd.mr_len == 0)
238 		help("set");
239 
240 	argc -= optind;
241 	argv += optind;
242 
243 	while(argc--) {
244 		for (i = 0; attrnames[i].name != NULL; i++) {
245 			if (!strcmp(attrnames[i].name, argv[0])) {
246 				if (!attrnames[i].kind & MDF_SETTABLE)
247 					help("flags");
248 				mrd.mr_flags |= attrnames[i].val;
249 				break;
250 			}
251 		}
252 		if (attrnames[i].name == NULL)
253 			help("flags");
254 		argv++;
255 	}
256 
257 	mro.mo_desc = &mrd;
258 	mro.mo_arg[0] = 0;
259 	if (ioctl(memfd, MEMRANGE_SET, &mro))
260 		err(1, "can't set range");
261 }
262 
263 static void
264 clearfunc(memfd, argc, argv)
265 	int 	 memfd;
266 	int 	 argc;
267 	char 	*argv[];
268 {
269 	struct mem_range_desc	 mrd, *mrdp;
270 	struct mem_range_op      mro;
271 	int			 i, nd;
272 	int			 ch;
273 	char			*ep, *owner;
274 
275 	mrd.mr_base = 0;
276 	mrd.mr_len = 0;
277 	owner = NULL;
278 	while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
279 		switch(ch) {
280 		case 'b':
281 			mrd.mr_base = strtouq(optarg, &ep, 0);
282 			if ((ep == optarg) || (*ep != 0))
283 				help("clear");
284 			break;
285 		case 'l':
286 			mrd.mr_len = strtouq(optarg, &ep, 0);
287 			if ((ep == optarg) || (*ep != 0))
288 				help("clear");
289 			break;
290 		case 'o':
291 			if ((*optarg == 0) || (strlen(optarg) > 7))
292 				help("clear");
293 			owner = strdup(optarg);
294 			break;
295 
296 		case '?':
297 		default:
298 			help("clear");
299 		}
300 
301 	if (owner != NULL) {
302 		/* clear-by-owner */
303 		if ((mrd.mr_base != 0) || (mrd.mr_len != 0))
304 			help("clear");
305 
306 		mrdp = mrgetall(memfd, &nd);
307 		mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
308 		for (i = 0; i < nd; i++) {
309 			if (!strcmp(owner, mrdp[i].mr_owner) &&
310 			    (mrdp[i].mr_flags & MDF_ACTIVE) &&
311 			    !(mrdp[i].mr_flags & MDF_FIXACTIVE)) {
312 
313 				mro.mo_desc = mrdp + i;
314 				if (ioctl(memfd, MEMRANGE_SET, &mro))
315 					warn("couldn't clear range owned by '%s'", owner);
316 			}
317 		}
318 	} else if ((mrd.mr_base != 0) && (mrd.mr_len != 0)) {
319 		/* clear-by-base/len */
320 		mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
321 		mro.mo_desc = &mrd;
322 		if (ioctl(memfd, MEMRANGE_SET, &mro))
323 			err(1, "couldn't clear range");
324 	} else {
325 		help("clear");
326 	}
327 }
328 
329 static void
330 helpfunc(memfd, argc, argv)
331 	int 	 memfd;
332 	int 	 argc;
333 	char 	*argv[];
334 {
335 	help(argv[1]);
336 }
337 
338 static void
339 help(what)
340 	char 	*what;
341 {
342 	int	 i;
343 
344 	if (what != NULL) {
345 		/* find a function that matches */
346 		for (i = 0; functions[i].cmd != NULL; i++)
347 			if (!strcmp(what, functions[i].cmd)) {
348 				fprintf(stderr, "%s\n", functions[i].desc);
349 				return;
350 			}
351 		fprintf(stderr, "Unknown command '%s'\n", what);
352 	}
353 
354 	/* print general help */
355 	fprintf(stderr, "Valid commands are :\n");
356 	for (i = 0; functions[i].cmd != NULL; i++)
357 		fprintf(stderr, "    %s\n", functions[i].cmd);
358 	fprintf(stderr, "Use help <command> for command-specific help\n");
359 }
360