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 |
|
|
} |