1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <sys/memrange.h>
32
33 #include <err.h>
34 #include <fcntl.h>
35 #include <inttypes.h>
36 #include <paths.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 static 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 {"bogus", MDF_BOGUS, 0},
60 {NULL, 0, 0}
61 };
62
63 static void listfunc(int memfd, int argc, char *argv[]);
64 static void setfunc(int memfd, int argc, char *argv[]);
65 static void clearfunc(int memfd, int argc, char *argv[]);
66 static void helpfunc(int memfd, int argc, char *argv[]);
67 static void help(const char *what);
68
69 static struct {
70 const char *cmd;
71 const char *desc;
72 void (*func)(int memfd, int argc, char *argv[]);
73 } functions[] = {
74 {"list",
75 "List current memory range attributes\n"
76 " list [-a]\n"
77 " -a list all range slots, even those that are inactive",
78 listfunc},
79 {"set",
80 "Set memory range attributes\n"
81 " set -b <base> -l <length> -o <owner> <attribute>\n"
82 " <base> memory range base address\n"
83 " <length> length of memory range in bytes, power of 2\n"
84 " <owner> text identifier for this setting (7 char max)\n"
85 " <attribute> attribute(s) to be applied to this range:\n"
86 " uncacheable\n"
87 " write-combine\n"
88 " write-through\n"
89 " write-back\n"
90 " write-protect",
91 setfunc},
92 {"clear",
93 "Clear memory range attributes\n"
94 " clear -o <owner>\n"
95 " <owner> all ranges with this owner will be cleared\n"
96 " clear -b <base> -l <length>\n"
97 " <base> memory range base address\n"
98 " <length> length of memory range in bytes, power of 2\n"
99 " Base and length must exactly match an existing range",
100 clearfunc},
101 {NULL, NULL, helpfunc}
102 };
103
104 int
main(int argc,char * argv[])105 main(int argc, char *argv[])
106 {
107 int i, memfd;
108
109 if (argc < 2) {
110 help(NULL);
111 } else {
112 if ((memfd = open(_PATH_MEM, O_RDONLY)) == -1)
113 err(1, "can't open %s", _PATH_MEM);
114
115 for (i = 0; functions[i].cmd != NULL; i++)
116 if (!strcmp(argv[1], functions[i].cmd))
117 break;
118 functions[i].func(memfd, argc - 1, argv + 1);
119 close(memfd);
120 }
121 return(0);
122 }
123
124 static struct mem_range_desc *
mrgetall(int memfd,int * nmr)125 mrgetall(int memfd, int *nmr)
126 {
127 struct mem_range_desc *mrd;
128 struct mem_range_op mro;
129
130 mro.mo_arg[0] = 0;
131 if (ioctl(memfd, MEMRANGE_GET, &mro))
132 err(1, "can't size range descriptor array");
133
134 *nmr = mro.mo_arg[0];
135 mrd = malloc(*nmr * sizeof(struct mem_range_desc));
136 if (mrd == NULL)
137 errx(1, "can't allocate %zd bytes for %d range descriptors",
138 *nmr * sizeof(struct mem_range_desc), *nmr);
139
140 mro.mo_arg[0] = *nmr;
141 mro.mo_desc = mrd;
142 if (ioctl(memfd, MEMRANGE_GET, &mro))
143 err(1, "can't fetch range descriptor array");
144
145 return(mrd);
146 }
147
148
149 static void
listfunc(int memfd,int argc,char * argv[])150 listfunc(int memfd, int argc, char *argv[])
151 {
152 struct mem_range_desc *mrd;
153 int nd, i, j;
154 int ch;
155 int showall = 0;
156 char *owner;
157
158 owner = NULL;
159 while ((ch = getopt(argc, argv, "ao:")) != -1)
160 switch(ch) {
161 case 'a':
162 showall = 1;
163 break;
164 case 'o':
165 owner = strdup(optarg);
166 break;
167 case '?':
168 default:
169 help("list");
170 }
171
172 mrd = mrgetall(memfd, &nd);
173
174 for (i = 0; i < nd; i++) {
175 if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE))
176 continue;
177 if (owner && strcmp(mrd[i].mr_owner, owner))
178 continue;
179 printf("0x%" PRIx64 "/0x%" PRIx64 " %.8s ", mrd[i].mr_base, mrd[i].mr_len,
180 mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-");
181 for (j = 0; attrnames[j].name != NULL; j++)
182 if (mrd[i].mr_flags & attrnames[j].val)
183 printf("%s ", attrnames[j].name);
184 printf("\n");
185 }
186 free(mrd);
187 if (owner)
188 free(owner);
189 }
190
191 static void
setfunc(int memfd,int argc,char * argv[])192 setfunc(int memfd, int argc, char *argv[])
193 {
194 struct mem_range_desc mrd;
195 struct mem_range_op mro;
196 int i;
197 int ch;
198 char *ep;
199
200 mrd.mr_base = 0;
201 mrd.mr_len = 0;
202 mrd.mr_flags = 0;
203 strcpy(mrd.mr_owner, "user");
204 while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
205 switch(ch) {
206 case 'b':
207 mrd.mr_base = strtouq(optarg, &ep, 0);
208 if ((ep == optarg) || (*ep != 0))
209 help("set");
210 break;
211 case 'l':
212 mrd.mr_len = strtouq(optarg, &ep, 0);
213 if ((ep == optarg) || (*ep != 0))
214 help("set");
215 break;
216 case 'o':
217 if ((*optarg == 0) || (strlen(optarg) > 7))
218 help("set");
219 strcpy(mrd.mr_owner, optarg);
220 break;
221
222 case '?':
223 default:
224 help("set");
225 }
226
227 if (mrd.mr_len == 0)
228 help("set");
229
230 argc -= optind;
231 argv += optind;
232
233 while(argc--) {
234 for (i = 0; attrnames[i].name != NULL; i++) {
235 if (!strcmp(attrnames[i].name, argv[0])) {
236 if (!(attrnames[i].kind & MDF_SETTABLE))
237 help("flags");
238 mrd.mr_flags |= attrnames[i].val;
239 break;
240 }
241 }
242 if (attrnames[i].name == NULL)
243 help("flags");
244 argv++;
245 }
246
247 mro.mo_desc = &mrd;
248 mro.mo_arg[0] = 0;
249 if (ioctl(memfd, MEMRANGE_SET, &mro))
250 err(1, "can't set range");
251 }
252
253 static void
clearfunc(int memfd,int argc,char * argv[])254 clearfunc(int memfd, int argc, char *argv[])
255 {
256 struct mem_range_desc mrd, *mrdp;
257 struct mem_range_op mro;
258 int i, nd;
259 int ch;
260 char *ep, *owner;
261
262 mrd.mr_base = 0;
263 mrd.mr_len = 0;
264 owner = NULL;
265 while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
266 switch(ch) {
267 case 'b':
268 mrd.mr_base = strtouq(optarg, &ep, 0);
269 if ((ep == optarg) || (*ep != 0))
270 help("clear");
271 break;
272 case 'l':
273 mrd.mr_len = strtouq(optarg, &ep, 0);
274 if ((ep == optarg) || (*ep != 0))
275 help("clear");
276 break;
277 case 'o':
278 if ((*optarg == 0) || (strlen(optarg) > 7))
279 help("clear");
280 owner = strdup(optarg);
281 break;
282
283 case '?':
284 default:
285 help("clear");
286 }
287
288 if (owner != NULL) {
289 /* clear-by-owner */
290 if ((mrd.mr_base != 0) || (mrd.mr_len != 0))
291 help("clear");
292
293 mrdp = mrgetall(memfd, &nd);
294 mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
295 for (i = 0; i < nd; i++) {
296 if (!strcmp(owner, mrdp[i].mr_owner) &&
297 (mrdp[i].mr_flags & MDF_ACTIVE) &&
298 !(mrdp[i].mr_flags & MDF_FIXACTIVE)) {
299
300 mro.mo_desc = mrdp + i;
301 if (ioctl(memfd, MEMRANGE_SET, &mro))
302 warn("couldn't clear range owned by '%s'", owner);
303 }
304 }
305 } else if (mrd.mr_len != 0) {
306 /* clear-by-base/len */
307 mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
308 mro.mo_desc = &mrd;
309 if (ioctl(memfd, MEMRANGE_SET, &mro))
310 err(1, "couldn't clear range");
311 } else {
312 help("clear");
313 }
314 }
315
316 static void
helpfunc(__unused int memfd,__unused int argc,char * argv[])317 helpfunc(__unused int memfd, __unused int argc, char *argv[])
318 {
319 help(argv[1]);
320 }
321
322 static void
help(const char * what)323 help(const char *what)
324 {
325 int i;
326
327 if (what != NULL) {
328 /* find a function that matches */
329 for (i = 0; functions[i].cmd != NULL; i++)
330 if (!strcmp(what, functions[i].cmd)) {
331 fprintf(stderr, "%s\n", functions[i].desc);
332 return;
333 }
334 fprintf(stderr, "Unknown command '%s'\n", what);
335 }
336
337 /* print general help */
338 fprintf(stderr, "Valid commands are :\n");
339 for (i = 0; functions[i].cmd != NULL; i++)
340 fprintf(stderr, " %s\n", functions[i].cmd);
341 fprintf(stderr, "Use help <command> for command-specific help\n");
342 }
343