xref: /freebsd/usr.sbin/memcontrol/memcontrol.c (revision 53f17f08ba7772e40ae259094d3122a163eb84fa)
153f17f08SMike Smith /*-
253f17f08SMike Smith  * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
353f17f08SMike Smith  * All rights reserved.
453f17f08SMike Smith  *
553f17f08SMike Smith  * Redistribution and use in source and binary forms, with or without
653f17f08SMike Smith  * modification, are permitted provided that the following conditions
753f17f08SMike Smith  * are met:
853f17f08SMike Smith  * 1. Redistributions of source code must retain the above copyright
953f17f08SMike Smith  *    notice, this list of conditions and the following disclaimer.
1053f17f08SMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1153f17f08SMike Smith  *    notice, this list of conditions and the following disclaimer in the
1253f17f08SMike Smith  *    documentation and/or other materials provided with the distribution.
1353f17f08SMike Smith  *
1453f17f08SMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1553f17f08SMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1653f17f08SMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1753f17f08SMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1853f17f08SMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1953f17f08SMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2053f17f08SMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2153f17f08SMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2253f17f08SMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2353f17f08SMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2453f17f08SMike Smith  * SUCH DAMAGE.
2553f17f08SMike Smith  *
2653f17f08SMike Smith  *	$Id$
2753f17f08SMike Smith  */
2853f17f08SMike Smith 
2953f17f08SMike Smith #include <sys/types.h>
3053f17f08SMike Smith #include <sys/ioctl.h>
3153f17f08SMike Smith #include <sys/memrange.h>
3253f17f08SMike Smith 
3353f17f08SMike Smith #include <err.h>
3453f17f08SMike Smith #include <fcntl.h>
3553f17f08SMike Smith #include <stdio.h>
3653f17f08SMike Smith #include <stdlib.h>
3753f17f08SMike Smith #include <string.h>
3853f17f08SMike Smith #include <unistd.h>
3953f17f08SMike Smith 
4053f17f08SMike Smith struct
4153f17f08SMike Smith {
4253f17f08SMike Smith     char	*name;
4353f17f08SMike Smith     int		val;
4453f17f08SMike Smith     int		kind;
4553f17f08SMike Smith #define MDF_SETTABLE	(1<<0)
4653f17f08SMike Smith } attrnames[] = {
4753f17f08SMike Smith     {"uncacheable",	MDF_UNCACHEABLE,	MDF_SETTABLE},
4853f17f08SMike Smith     {"write-combine",	MDF_WRITECOMBINE,	MDF_SETTABLE},
4953f17f08SMike Smith     {"write-through",	MDF_WRITETHROUGH,	MDF_SETTABLE},
5053f17f08SMike Smith     {"write-back",	MDF_WRITEBACK,		MDF_SETTABLE},
5153f17f08SMike Smith     {"write-protect",	MDF_WRITEPROTECT,	MDF_SETTABLE},
5253f17f08SMike Smith     {"fixed-base",	MDF_FIXBASE,		0},
5353f17f08SMike Smith     {"fixed-length",	MDF_FIXLEN,		0},
5453f17f08SMike Smith     {"set-by-firmware",	MDF_FIRMWARE,		0},
5553f17f08SMike Smith     {"active",		MDF_ACTIVE,		MDF_SETTABLE},
5653f17f08SMike Smith     {"bogus",		MDF_BOGUS,		0},
5753f17f08SMike Smith     {NULL,		0,			0}
5853f17f08SMike Smith };
5953f17f08SMike Smith 
6053f17f08SMike Smith static void	listfunc(int memfd, int argc, char *argv[]);
6153f17f08SMike Smith static void	setfunc(int memfd, int argc, char *argv[]);
6253f17f08SMike Smith static void	clearfunc(int memfd, int argc, char *argv[]);
6353f17f08SMike Smith static void	helpfunc(int memfd, int argc, char *argv[]);
6453f17f08SMike Smith static void	help(char *what);
6553f17f08SMike Smith 
6653f17f08SMike Smith struct
6753f17f08SMike Smith {
6853f17f08SMike Smith     char	*cmd;
6953f17f08SMike Smith     char	*desc;
7053f17f08SMike Smith     void	(*func)(int memfd, int argc, char *argv[]);
7153f17f08SMike Smith } functions[] = {
7253f17f08SMike Smith     {"list",
7353f17f08SMike Smith      "List current memory range attributes\n"
7453f17f08SMike Smith      "    list [-a]\n"
7553f17f08SMike Smith      "        -a    list all range slots, even those that are inactive",
7653f17f08SMike Smith      listfunc},
7753f17f08SMike Smith     {"set",
7853f17f08SMike Smith      "Set memory range attributes\n"
7953f17f08SMike Smith      "    set -b <base> -l <length> -o <owner> <attribute>\n"
8053f17f08SMike Smith      "        <base>      memory range base address\n"
8153f17f08SMike Smith      "        <length>    length of memory range in bytes, power of 2\n"
8253f17f08SMike Smith      "        <owner>     text identifier for this setting (7 char max)\n"
8353f17f08SMike Smith      "        <attribute> attribute(s) to be applied to this range:\n"
8453f17f08SMike Smith      "                        uncacheable\n"
8553f17f08SMike Smith      "                        write-combine\n"
8653f17f08SMike Smith      "                        write-through\n"
8753f17f08SMike Smith      "                        write-back\n"
8853f17f08SMike Smith      "                        write-protect",
8953f17f08SMike Smith      setfunc},
9053f17f08SMike Smith     {"clear",
9153f17f08SMike Smith      "Clear memory range attributes\n"
9253f17f08SMike Smith      "    clear -o <owner>\n"
9353f17f08SMike Smith      "        <owner>     all ranges with this owner will be cleared\n"
9453f17f08SMike Smith      "    clear -b <base> -l <length>\n"
9553f17f08SMike Smith      "        <base>      memory range base address\n"
9653f17f08SMike Smith      "        <length>    length of memory range in bytes, power of 2\n"
9753f17f08SMike Smith      "                    Base and length must exactly match an existing range",
9853f17f08SMike Smith      clearfunc},
9953f17f08SMike Smith     {NULL,	NULL,					helpfunc}
10053f17f08SMike Smith };
10153f17f08SMike Smith 
10253f17f08SMike Smith int
10353f17f08SMike Smith main(int argc, char *argv[])
10453f17f08SMike Smith {
10553f17f08SMike Smith     int		i, memfd;
10653f17f08SMike Smith 
10753f17f08SMike Smith     if (argc < 2) {
10853f17f08SMike Smith 	help(NULL);
10953f17f08SMike Smith     } else {
11053f17f08SMike Smith 	if ((memfd = open("/dev/mem", O_RDONLY)) == -1)
11153f17f08SMike Smith 	    err(1, "can't open /dev/mem");
11253f17f08SMike Smith 
11353f17f08SMike Smith 	for (i = 0; functions[i].cmd != NULL; i++)
11453f17f08SMike Smith 	    if (!strcmp(argv[1], functions[i].cmd))
11553f17f08SMike Smith 		break;
11653f17f08SMike Smith 	functions[i].func(memfd, argc - 1, argv + 1);
11753f17f08SMike Smith 	close(memfd);
11853f17f08SMike Smith     }
11953f17f08SMike Smith     return(0);
12053f17f08SMike Smith }
12153f17f08SMike Smith 
12253f17f08SMike Smith static struct mem_range_desc *
12353f17f08SMike Smith mrgetall(int memfd, int *nmr)
12453f17f08SMike Smith {
12553f17f08SMike Smith     struct mem_range_desc	*mrd;
12653f17f08SMike Smith     struct mem_range_op		mro;
12753f17f08SMike Smith 
12853f17f08SMike Smith     mro.mo_arg[0] = 0;
12953f17f08SMike Smith     if (ioctl(memfd, MEMRANGE_GET, &mro))
13053f17f08SMike Smith 	err(1, "can't size range descriptor array");
13153f17f08SMike Smith 
13253f17f08SMike Smith     *nmr = mro.mo_arg[0];
13353f17f08SMike Smith     mrd = malloc(*nmr * sizeof(struct mem_range_desc));
13453f17f08SMike Smith     if (mrd == NULL)
13553f17f08SMike Smith 	errx(1, "can't allocate %d bytes for %d range descriptors",
13653f17f08SMike Smith 	     *nmr * sizeof(struct mem_range_desc), *nmr);
13753f17f08SMike Smith 
13853f17f08SMike Smith     mro.mo_arg[0] = *nmr;
13953f17f08SMike Smith     mro.mo_desc = mrd;
14053f17f08SMike Smith     if (ioctl(memfd, MEMRANGE_GET, &mro))
14153f17f08SMike Smith 	err(1, "can't fetch range descriptor array");
14253f17f08SMike Smith 
14353f17f08SMike Smith     return(mrd);
14453f17f08SMike Smith }
14553f17f08SMike Smith 
14653f17f08SMike Smith 
14753f17f08SMike Smith static void
14853f17f08SMike Smith listfunc(int memfd, int argc, char *argv[])
14953f17f08SMike Smith {
15053f17f08SMike Smith     struct mem_range_desc	*mrd;
15153f17f08SMike Smith     int				nd, i, j;
15253f17f08SMike Smith     int				error;
15353f17f08SMike Smith     int				ch;
15453f17f08SMike Smith     int				showall = 0;
15553f17f08SMike Smith     char			*owner;
15653f17f08SMike Smith 
15753f17f08SMike Smith     owner = NULL;
15853f17f08SMike Smith     while ((ch = getopt(argc, argv, "ao:")) != -1)
15953f17f08SMike Smith 	switch(ch) {
16053f17f08SMike Smith 	case 'a':
16153f17f08SMike Smith 	    showall = 1;
16253f17f08SMike Smith 	    break;
16353f17f08SMike Smith 	case 'o':
16453f17f08SMike Smith 	    owner = strdup(optarg);
16553f17f08SMike Smith 	    break;
16653f17f08SMike Smith 	case '?':
16753f17f08SMike Smith 	default:
16853f17f08SMike Smith 	    help("list");
16953f17f08SMike Smith 	}
17053f17f08SMike Smith 
17153f17f08SMike Smith     mrd = mrgetall(memfd, &nd);
17253f17f08SMike Smith 
17353f17f08SMike Smith     for (i = 0; i < nd; i++) {
17453f17f08SMike Smith 	if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE))
17553f17f08SMike Smith 	    continue;
17653f17f08SMike Smith 	if (owner && strcmp(mrd[i].mr_owner, owner))
17753f17f08SMike Smith 	    continue;
17853f17f08SMike Smith 	printf("%qx/%qx %.8s ", mrd[i].mr_base, mrd[i].mr_len,
17953f17f08SMike Smith 	       mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-");
18053f17f08SMike Smith 	for (j = 0; attrnames[j].name != NULL; j++)
18153f17f08SMike Smith 	    if (mrd[i].mr_flags & attrnames[j].val)
18253f17f08SMike Smith 		printf("%s ", attrnames[j].name);
18353f17f08SMike Smith 	printf("\n");
18453f17f08SMike Smith     }
18553f17f08SMike Smith     free(mrd);
18653f17f08SMike Smith     if (owner)
18753f17f08SMike Smith 	free(owner);
18853f17f08SMike Smith }
18953f17f08SMike Smith 
19053f17f08SMike Smith static void
19153f17f08SMike Smith setfunc(int memfd, int argc, char *argv[])
19253f17f08SMike Smith {
19353f17f08SMike Smith     struct mem_range_desc	mrd;
19453f17f08SMike Smith     struct mem_range_op		mro;
19553f17f08SMike Smith     int				i;
19653f17f08SMike Smith     int				ch;
19753f17f08SMike Smith     char			*ep;
19853f17f08SMike Smith 
19953f17f08SMike Smith     mrd.mr_base = 0;
20053f17f08SMike Smith     mrd.mr_len = 0;
20153f17f08SMike Smith     mrd.mr_flags = 0;
20253f17f08SMike Smith     strcpy(mrd.mr_owner, "user");
20353f17f08SMike Smith     while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
20453f17f08SMike Smith 	switch(ch) {
20553f17f08SMike Smith 	case 'b':
20653f17f08SMike Smith 	    mrd.mr_base = strtouq(optarg, &ep, 0);
20753f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
20853f17f08SMike Smith 		help("set");
20953f17f08SMike Smith 	    break;
21053f17f08SMike Smith 	case 'l':
21153f17f08SMike Smith 	    mrd.mr_len = strtouq(optarg, &ep, 0);
21253f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
21353f17f08SMike Smith 		help("set");
21453f17f08SMike Smith 	    break;
21553f17f08SMike Smith 	case 'o':
21653f17f08SMike Smith 	    if ((*optarg == 0) || (strlen(optarg) > 7))
21753f17f08SMike Smith 		help("set");
21853f17f08SMike Smith 	    strcpy(mrd.mr_owner, optarg);
21953f17f08SMike Smith 	    break;
22053f17f08SMike Smith 
22153f17f08SMike Smith 	case '?':
22253f17f08SMike Smith 	default:
22353f17f08SMike Smith 	    help("set");
22453f17f08SMike Smith 	}
22553f17f08SMike Smith 
22653f17f08SMike Smith     if (mrd.mr_len == 0)
22753f17f08SMike Smith 	help("set");
22853f17f08SMike Smith 
22953f17f08SMike Smith     argc -= optind;
23053f17f08SMike Smith     argv += optind;
23153f17f08SMike Smith 
23253f17f08SMike Smith     while(argc--) {
23353f17f08SMike Smith 	for (i = 0; attrnames[i].name != NULL; i++) {
23453f17f08SMike Smith 	    if (!strcmp(attrnames[i].name, argv[0])) {
23553f17f08SMike Smith 		if (!attrnames[i].kind & MDF_SETTABLE)
23653f17f08SMike Smith 		    help("flags");
23753f17f08SMike Smith 		mrd.mr_flags |= attrnames[i].val;
23853f17f08SMike Smith 		break;
23953f17f08SMike Smith 	    }
24053f17f08SMike Smith 	}
24153f17f08SMike Smith 	if (attrnames[i].name == NULL)
24253f17f08SMike Smith 	    help("flags");
24353f17f08SMike Smith 	argv++;
24453f17f08SMike Smith     }
24553f17f08SMike Smith 
24653f17f08SMike Smith     mro.mo_desc = &mrd;
24753f17f08SMike Smith     mro.mo_arg[0] = 0;
24853f17f08SMike Smith     if (ioctl(memfd, MEMRANGE_SET, &mro))
24953f17f08SMike Smith 	err(1, "can't set range");
25053f17f08SMike Smith }
25153f17f08SMike Smith 
25253f17f08SMike Smith static void
25353f17f08SMike Smith clearfunc(int memfd, int argc, char *argv[])
25453f17f08SMike Smith {
25553f17f08SMike Smith     struct mem_range_desc	mrd, *mrdp;
25653f17f08SMike Smith     struct mem_range_op		mro;
25753f17f08SMike Smith     int				i, nd;
25853f17f08SMike Smith     int				ch;
25953f17f08SMike Smith     char			*ep, *owner;
26053f17f08SMike Smith 
26153f17f08SMike Smith     mrd.mr_base = 0;
26253f17f08SMike Smith     mrd.mr_len = 0;
26353f17f08SMike Smith     owner = NULL;
26453f17f08SMike Smith     while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
26553f17f08SMike Smith 	switch(ch) {
26653f17f08SMike Smith 	case 'b':
26753f17f08SMike Smith 	    mrd.mr_base = strtouq(optarg, &ep, 0);
26853f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
26953f17f08SMike Smith 		help("clear");
27053f17f08SMike Smith 	    break;
27153f17f08SMike Smith 	case 'l':
27253f17f08SMike Smith 	    mrd.mr_len = strtouq(optarg, &ep, 0);
27353f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
27453f17f08SMike Smith 		help("clear");
27553f17f08SMike Smith 	    break;
27653f17f08SMike Smith 	case 'o':
27753f17f08SMike Smith 	    if ((*optarg == 0) || (strlen(optarg) > 7))
27853f17f08SMike Smith 		help("clear");
27953f17f08SMike Smith 	    owner = strdup(optarg);
28053f17f08SMike Smith 	    break;
28153f17f08SMike Smith 
28253f17f08SMike Smith 	case '?':
28353f17f08SMike Smith 	default:
28453f17f08SMike Smith 	    help("clear");
28553f17f08SMike Smith 	}
28653f17f08SMike Smith 
28753f17f08SMike Smith     if (owner != NULL) {
28853f17f08SMike Smith 	/* clear-by-owner */
28953f17f08SMike Smith 	if ((mrd.mr_base != 0) || (mrd.mr_len != 0))
29053f17f08SMike Smith 	    help("clear");
29153f17f08SMike Smith 
29253f17f08SMike Smith 	mrdp = mrgetall(memfd, &nd);
29353f17f08SMike Smith 	mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
29453f17f08SMike Smith 	for (i = 0; i < nd; i++) {
29553f17f08SMike Smith 	    if (!strcmp(owner, mrdp[i].mr_owner) &&
29653f17f08SMike Smith 		(mrdp[i].mr_flags & MDF_ACTIVE) &&
29753f17f08SMike Smith 		!(mrdp[i].mr_flags & MDF_FIXACTIVE)) {
29853f17f08SMike Smith 
29953f17f08SMike Smith 		mro.mo_desc = mrdp + i;
30053f17f08SMike Smith 		if (ioctl(memfd, MEMRANGE_SET, &mro))
30153f17f08SMike Smith 		    warn("couldn't clear range owned by '%s'", owner);
30253f17f08SMike Smith 	    }
30353f17f08SMike Smith 	}
30453f17f08SMike Smith     } else if ((mrd.mr_base != 0) && (mrd.mr_len != 0)) {
30553f17f08SMike Smith 	/* clear-by-base/len */
30653f17f08SMike Smith 	mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
30753f17f08SMike Smith 	mro.mo_desc = &mrd;
30853f17f08SMike Smith 	if (ioctl(memfd, MEMRANGE_SET, &mro))
30953f17f08SMike Smith 	    err(1, "couldn't clear range");
31053f17f08SMike Smith     } else {
31153f17f08SMike Smith 	help("clear");
31253f17f08SMike Smith     }
31353f17f08SMike Smith }
31453f17f08SMike Smith 
31553f17f08SMike Smith static void
31653f17f08SMike Smith helpfunc(int memfd, int argc, char *argv[])
31753f17f08SMike Smith {
31853f17f08SMike Smith     help(NULL);
31953f17f08SMike Smith }
32053f17f08SMike Smith 
32153f17f08SMike Smith static void
32253f17f08SMike Smith help(char *what)
32353f17f08SMike Smith {
32453f17f08SMike Smith     errx(1, "help!");
32553f17f08SMike Smith }
326