]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/memcontrol/memcontrol.c
WARNS=2 cleanup.
[FreeBSD/FreeBSD.git] / usr.sbin / memcontrol / memcontrol.c
1 /*-
2  * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
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 <paths.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(int memfd, int argc, char *argv[]);
62 static void     setfunc(int memfd, int argc, char *argv[]);
63 static void     clearfunc(int memfd, int argc, char *argv[]);
64 static void     helpfunc(int memfd, int argc, char *argv[]);
65 static void     help(char *what);
66
67 struct 
68 {
69     char        *cmd;
70     char        *desc;
71     void        (*func)(int memfd, int argc, char *argv[]);
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(int argc, char *argv[])
105 {
106     int         i, memfd;
107
108     if (argc < 2) {
109         help(NULL);
110     } else {
111         if ((memfd = open(_PATH_MEM, O_RDONLY)) == -1)
112             err(1, "can't open %s", _PATH_MEM);
113
114         for (i = 0; functions[i].cmd != NULL; i++)
115             if (!strcmp(argv[1], functions[i].cmd))
116                 break;
117         functions[i].func(memfd, argc - 1, argv + 1);
118         close(memfd);
119     }
120     return(0);
121 }
122
123 static struct mem_range_desc *
124 mrgetall(int memfd, int *nmr)
125 {
126     struct mem_range_desc       *mrd;
127     struct mem_range_op         mro;
128
129     mro.mo_arg[0] = 0;
130     if (ioctl(memfd, MEMRANGE_GET, &mro))
131         err(1, "can't size range descriptor array");
132     
133     *nmr = mro.mo_arg[0];
134     mrd = malloc(*nmr * sizeof(struct mem_range_desc));
135     if (mrd == NULL)
136         errx(1, "can't allocate %d bytes for %d range descriptors", 
137              *nmr * sizeof(struct mem_range_desc), *nmr);
138
139     mro.mo_arg[0] = *nmr;
140     mro.mo_desc = mrd;
141     if (ioctl(memfd, MEMRANGE_GET, &mro))
142         err(1, "can't fetch range descriptor array");
143
144     return(mrd);
145 }
146
147
148 static void
149 listfunc(int memfd, int argc, char *argv[])
150 {
151     struct mem_range_desc       *mrd;
152     int                         nd, i, j;
153     int                         ch;
154     int                         showall = 0;
155     char                        *owner;
156
157     owner = NULL;
158     while ((ch = getopt(argc, argv, "ao:")) != -1)
159         switch(ch) {
160         case 'a':
161             showall = 1;
162             break;
163         case 'o':
164             owner = strdup(optarg);
165             break;
166         case '?':
167         default:
168             help("list");
169         }
170
171     mrd = mrgetall(memfd, &nd);
172     
173     for (i = 0; i < nd; i++) {
174         if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE))
175             continue;
176         if (owner && strcmp(mrd[i].mr_owner, owner))
177             continue;
178         printf("%qx/%qx %.8s ", mrd[i].mr_base, mrd[i].mr_len, 
179                mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-");
180         for (j = 0; attrnames[j].name != NULL; j++)
181             if (mrd[i].mr_flags & attrnames[j].val)
182                 printf("%s ", attrnames[j].name);
183         printf("\n");
184     }
185     free(mrd);
186     if (owner)
187         free(owner);
188 }
189
190 static void
191 setfunc(int memfd, int argc, char *argv[])
192 {
193     struct mem_range_desc       mrd;
194     struct mem_range_op         mro;
195     int                         i;
196     int                         ch;
197     char                        *ep;
198
199     mrd.mr_base = 0;
200     mrd.mr_len = 0;
201     mrd.mr_flags = 0;
202     strcpy(mrd.mr_owner, "user");
203     while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
204         switch(ch) {
205         case 'b':
206             mrd.mr_base = strtouq(optarg, &ep, 0);
207             if ((ep == optarg) || (*ep != 0))
208                 help("set");
209             break;
210         case 'l':
211             mrd.mr_len = strtouq(optarg, &ep, 0);
212             if ((ep == optarg) || (*ep != 0))
213                 help("set");
214             break;
215         case 'o':
216             if ((*optarg == 0) || (strlen(optarg) > 7))
217                 help("set");
218             strcpy(mrd.mr_owner, optarg);
219             break;
220             
221         case '?':
222         default:
223             help("set");
224         }
225
226     if (mrd.mr_len == 0)
227         help("set");
228
229     argc -= optind;
230     argv += optind;
231     
232     while(argc--) {
233         for (i = 0; attrnames[i].name != NULL; i++) {
234             if (!strcmp(attrnames[i].name, argv[0])) {
235                 if (!attrnames[i].kind & MDF_SETTABLE)
236                     help("flags");
237                 mrd.mr_flags |= attrnames[i].val;
238                 break;
239             }
240         }
241         if (attrnames[i].name == NULL)
242             help("flags");
243         argv++;
244     }
245
246     mro.mo_desc = &mrd;
247     mro.mo_arg[0] = 0;
248     if (ioctl(memfd, MEMRANGE_SET, &mro))
249         err(1, "can't set range");
250 }
251
252 static void
253 clearfunc(int memfd, int argc, char *argv[])
254 {
255     struct mem_range_desc       mrd, *mrdp;
256     struct mem_range_op         mro;
257     int                         i, nd;
258     int                         ch;
259     char                        *ep, *owner;
260
261     mrd.mr_base = 0;
262     mrd.mr_len = 0;
263     owner = NULL;
264     while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
265         switch(ch) {
266         case 'b':
267             mrd.mr_base = strtouq(optarg, &ep, 0);
268             if ((ep == optarg) || (*ep != 0))
269                 help("clear");
270             break;
271         case 'l':
272             mrd.mr_len = strtouq(optarg, &ep, 0);
273             if ((ep == optarg) || (*ep != 0))
274                 help("clear");
275             break;
276         case 'o':
277             if ((*optarg == 0) || (strlen(optarg) > 7))
278                 help("clear");
279             owner = strdup(optarg);
280             break;
281             
282         case '?':
283         default:
284             help("clear");
285         }
286
287     if (owner != NULL) {
288         /* clear-by-owner */
289         if ((mrd.mr_base != 0) || (mrd.mr_len != 0))
290             help("clear");
291
292         mrdp = mrgetall(memfd, &nd);
293         mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
294         for (i = 0; i < nd; i++) {
295             if (!strcmp(owner, mrdp[i].mr_owner) && 
296                 (mrdp[i].mr_flags & MDF_ACTIVE) &&
297                 !(mrdp[i].mr_flags & MDF_FIXACTIVE)) {
298                 
299                 mro.mo_desc = mrdp + i;
300                 if (ioctl(memfd, MEMRANGE_SET, &mro))
301                     warn("couldn't clear range owned by '%s'", owner);
302             }
303         }
304     } else if (mrd.mr_len != 0) {
305         /* clear-by-base/len */
306         mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
307         mro.mo_desc = &mrd;
308         if (ioctl(memfd, MEMRANGE_SET, &mro))
309             err(1, "couldn't clear range");
310     } else {
311         help("clear");
312     }
313 }
314
315 static void
316 helpfunc(int memfd, int argc, char *argv[])
317 {
318     help(argv[1]);
319 }
320
321 static void
322 help(char *what)
323 {
324     int         i;
325
326     if (what != NULL) {
327         /* find a function that matches */
328         for (i = 0; functions[i].cmd != NULL; i++)
329             if (!strcmp(what, functions[i].cmd)) {
330                 fprintf(stderr, "%s\n", functions[i].desc);
331                 return;
332             }
333         fprintf(stderr, "Unknown command '%s'\n", what);
334     }
335     
336     /* print general help */
337     fprintf(stderr, "Valid commands are :\n");
338     for (i = 0; functions[i].cmd != NULL; i++)
339         fprintf(stderr, "    %s\n", functions[i].cmd);
340     fprintf(stderr, "Use help <command> for command-specific help\n");
341 }