GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/memconfig/memconfig.c Lines: 0 136 0.0 %
Date: 2017-11-13 Branches: 0 127 0.0 %

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