memcontrol.c revision 78737
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
31573Srgrimes * All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes *
141573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241573Srgrimes * SUCH DAMAGE.
251573Srgrimes *
261573Srgrimes * $FreeBSD: head/usr.sbin/memcontrol/memcontrol.c 78737 2001-06-24 23:41:57Z dd $
271573Srgrimes */
281573Srgrimes
291573Srgrimes#include <sys/types.h>
301573Srgrimes#include <sys/ioctl.h>
311573Srgrimes#include <sys/memrange.h>
321573Srgrimes
331573Srgrimes#include <err.h>
341573Srgrimes#include <fcntl.h>
351573Srgrimes#include <paths.h>
361573Srgrimes#include <stdio.h>
371573Srgrimes#include <stdlib.h>
381573Srgrimes#include <string.h>
391573Srgrimes#include <unistd.h>
401573Srgrimes
411573Srgrimesstruct
421573Srgrimes{
431573Srgrimes    char	*name;
441573Srgrimes    int		val;
451573Srgrimes    int		kind;
461573Srgrimes#define MDF_SETTABLE	(1<<0)
471573Srgrimes} attrnames[] = {
481573Srgrimes    {"uncacheable",	MDF_UNCACHEABLE,	MDF_SETTABLE},
491573Srgrimes    {"write-combine",	MDF_WRITECOMBINE,	MDF_SETTABLE},
501573Srgrimes    {"write-through",	MDF_WRITETHROUGH,	MDF_SETTABLE},
511573Srgrimes    {"write-back",	MDF_WRITEBACK,		MDF_SETTABLE},
521573Srgrimes    {"write-protect",	MDF_WRITEPROTECT,	MDF_SETTABLE},
531573Srgrimes    {"fixed-base",	MDF_FIXBASE,		0},
541573Srgrimes    {"fixed-length",	MDF_FIXLEN,		0},
551573Srgrimes    {"set-by-firmware",	MDF_FIRMWARE,		0},
561573Srgrimes    {"active",		MDF_ACTIVE,		MDF_SETTABLE},
571573Srgrimes    {"bogus",		MDF_BOGUS,		0},
581573Srgrimes    {NULL,		0,			0}
591573Srgrimes};
601573Srgrimes
611573Srgrimesstatic void	listfunc(int memfd, int argc, char *argv[]);
621573Srgrimesstatic void	setfunc(int memfd, int argc, char *argv[]);
631573Srgrimesstatic void	clearfunc(int memfd, int argc, char *argv[]);
641573Srgrimesstatic void	helpfunc(int memfd, int argc, char *argv[]);
651573Srgrimesstatic void	help(char *what);
661573Srgrimes
671573Srgrimesstruct
681573Srgrimes{
691573Srgrimes    char	*cmd;
701573Srgrimes    char	*desc;
711573Srgrimes    void	(*func)(int memfd, int argc, char *argv[]);
721573Srgrimes} functions[] = {
731573Srgrimes    {"list",
741573Srgrimes     "List current memory range attributes\n"
751573Srgrimes     "    list [-a]\n"
761573Srgrimes     "        -a    list all range slots, even those that are inactive",
771573Srgrimes     listfunc},
781573Srgrimes    {"set",
791573Srgrimes     "Set memory range attributes\n"
801573Srgrimes     "    set -b <base> -l <length> -o <owner> <attribute>\n"
811573Srgrimes     "        <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
103int
104main(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
123static struct mem_range_desc *
124mrgetall(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
148static void
149listfunc(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
190static void
191setfunc(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
252static void
253clearfunc(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
315static void
316helpfunc(int memfd, int argc, char *argv[])
317{
318    help(argv[1]);
319}
320
321static void
322help(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}
342