xref: /freebsd/usr.sbin/memcontrol/memcontrol.c (revision 50f39947dec886e964aedf712b237714c8c6e852)
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  *
2697d92980SPeter Wemm  * $FreeBSD$
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>
351a842e25SXin LI #include <inttypes.h>
361a37aa56SDavid E. O'Brien #include <paths.h>
3753f17f08SMike Smith #include <stdio.h>
3853f17f08SMike Smith #include <stdlib.h>
3953f17f08SMike Smith #include <string.h>
4053f17f08SMike Smith #include <unistd.h>
4153f17f08SMike Smith 
4253f17f08SMike Smith struct
4353f17f08SMike Smith {
441a842e25SXin LI     const char	*name;
4553f17f08SMike Smith     int		val;
4653f17f08SMike Smith     int		kind;
4753f17f08SMike Smith #define MDF_SETTABLE	(1<<0)
4853f17f08SMike Smith } attrnames[] = {
4953f17f08SMike Smith     {"uncacheable",	MDF_UNCACHEABLE,	MDF_SETTABLE},
5053f17f08SMike Smith     {"write-combine",	MDF_WRITECOMBINE,	MDF_SETTABLE},
5153f17f08SMike Smith     {"write-through",	MDF_WRITETHROUGH,	MDF_SETTABLE},
5253f17f08SMike Smith     {"write-back",	MDF_WRITEBACK,		MDF_SETTABLE},
5353f17f08SMike Smith     {"write-protect",	MDF_WRITEPROTECT,	MDF_SETTABLE},
5493f39ea8SDavid Malone     {"force",		MDF_FORCE,		MDF_SETTABLE},
55b0f4bb51SDavid Malone     {"unknown",		MDF_UNKNOWN,		0},
5653f17f08SMike Smith     {"fixed-base",	MDF_FIXBASE,		0},
5753f17f08SMike Smith     {"fixed-length",	MDF_FIXLEN,		0},
5853f17f08SMike Smith     {"set-by-firmware",	MDF_FIRMWARE,		0},
5953f17f08SMike Smith     {"active",		MDF_ACTIVE,		MDF_SETTABLE},
6053f17f08SMike Smith     {"bogus",		MDF_BOGUS,		0},
6153f17f08SMike Smith     {NULL,		0,			0}
6253f17f08SMike Smith };
6353f17f08SMike Smith 
6453f17f08SMike Smith static void	listfunc(int memfd, int argc, char *argv[]);
6553f17f08SMike Smith static void	setfunc(int memfd, int argc, char *argv[]);
6653f17f08SMike Smith static void	clearfunc(int memfd, int argc, char *argv[]);
6753f17f08SMike Smith static void	helpfunc(int memfd, int argc, char *argv[]);
681a842e25SXin LI static void	help(const char *what);
6953f17f08SMike Smith 
7053f17f08SMike Smith struct
7153f17f08SMike Smith {
721a842e25SXin LI     const char	*cmd;
731a842e25SXin LI     const char	*desc;
7453f17f08SMike Smith     void	(*func)(int memfd, int argc, char *argv[]);
7553f17f08SMike Smith } functions[] = {
7653f17f08SMike Smith     {"list",
7753f17f08SMike Smith      "List current memory range attributes\n"
7853f17f08SMike Smith      "    list [-a]\n"
7953f17f08SMike Smith      "        -a    list all range slots, even those that are inactive",
8053f17f08SMike Smith      listfunc},
8153f17f08SMike Smith     {"set",
8253f17f08SMike Smith      "Set memory range attributes\n"
8353f17f08SMike Smith      "    set -b <base> -l <length> -o <owner> <attribute>\n"
8453f17f08SMike Smith      "        <base>      memory range base address\n"
8553f17f08SMike Smith      "        <length>    length of memory range in bytes, power of 2\n"
8653f17f08SMike Smith      "        <owner>     text identifier for this setting (7 char max)\n"
8753f17f08SMike Smith      "        <attribute> attribute(s) to be applied to this range:\n"
8853f17f08SMike Smith      "                        uncacheable\n"
8953f17f08SMike Smith      "                        write-combine\n"
9053f17f08SMike Smith      "                        write-through\n"
9153f17f08SMike Smith      "                        write-back\n"
9253f17f08SMike Smith      "                        write-protect",
9353f17f08SMike Smith      setfunc},
9453f17f08SMike Smith     {"clear",
9553f17f08SMike Smith      "Clear memory range attributes\n"
9653f17f08SMike Smith      "    clear -o <owner>\n"
9753f17f08SMike Smith      "        <owner>     all ranges with this owner will be cleared\n"
9853f17f08SMike Smith      "    clear -b <base> -l <length>\n"
9953f17f08SMike Smith      "        <base>      memory range base address\n"
10053f17f08SMike Smith      "        <length>    length of memory range in bytes, power of 2\n"
10153f17f08SMike Smith      "                    Base and length must exactly match an existing range",
10253f17f08SMike Smith      clearfunc},
10353f17f08SMike Smith     {NULL,	NULL,					helpfunc}
10453f17f08SMike Smith };
10553f17f08SMike Smith 
10653f17f08SMike Smith int
10753f17f08SMike Smith main(int argc, char *argv[])
10853f17f08SMike Smith {
10953f17f08SMike Smith     int		i, memfd;
11053f17f08SMike Smith 
11153f17f08SMike Smith     if (argc < 2) {
11253f17f08SMike Smith 	help(NULL);
11353f17f08SMike Smith     } else {
1141a37aa56SDavid E. O'Brien 	if ((memfd = open(_PATH_MEM, O_RDONLY)) == -1)
1151a37aa56SDavid E. O'Brien 	    err(1, "can't open %s", _PATH_MEM);
11653f17f08SMike Smith 
11753f17f08SMike Smith 	for (i = 0; functions[i].cmd != NULL; i++)
11853f17f08SMike Smith 	    if (!strcmp(argv[1], functions[i].cmd))
11953f17f08SMike Smith 		break;
12053f17f08SMike Smith 	functions[i].func(memfd, argc - 1, argv + 1);
12153f17f08SMike Smith 	close(memfd);
12253f17f08SMike Smith     }
12353f17f08SMike Smith     return(0);
12453f17f08SMike Smith }
12553f17f08SMike Smith 
12653f17f08SMike Smith static struct mem_range_desc *
12753f17f08SMike Smith mrgetall(int memfd, int *nmr)
12853f17f08SMike Smith {
12953f17f08SMike Smith     struct mem_range_desc	*mrd;
13053f17f08SMike Smith     struct mem_range_op		mro;
13153f17f08SMike Smith 
13253f17f08SMike Smith     mro.mo_arg[0] = 0;
13353f17f08SMike Smith     if (ioctl(memfd, MEMRANGE_GET, &mro))
13453f17f08SMike Smith 	err(1, "can't size range descriptor array");
13553f17f08SMike Smith 
13653f17f08SMike Smith     *nmr = mro.mo_arg[0];
13753f17f08SMike Smith     mrd = malloc(*nmr * sizeof(struct mem_range_desc));
13853f17f08SMike Smith     if (mrd == NULL)
1391a842e25SXin LI 	errx(1, "can't allocate %zd bytes for %d range descriptors",
14053f17f08SMike Smith 	     *nmr * sizeof(struct mem_range_desc), *nmr);
14153f17f08SMike Smith 
14253f17f08SMike Smith     mro.mo_arg[0] = *nmr;
14353f17f08SMike Smith     mro.mo_desc = mrd;
14453f17f08SMike Smith     if (ioctl(memfd, MEMRANGE_GET, &mro))
14553f17f08SMike Smith 	err(1, "can't fetch range descriptor array");
14653f17f08SMike Smith 
14753f17f08SMike Smith     return(mrd);
14853f17f08SMike Smith }
14953f17f08SMike Smith 
15053f17f08SMike Smith 
15153f17f08SMike Smith static void
15253f17f08SMike Smith listfunc(int memfd, int argc, char *argv[])
15353f17f08SMike Smith {
15453f17f08SMike Smith     struct mem_range_desc	*mrd;
15553f17f08SMike Smith     int				nd, i, j;
15653f17f08SMike Smith     int				ch;
15753f17f08SMike Smith     int				showall = 0;
15853f17f08SMike Smith     char			*owner;
15953f17f08SMike Smith 
16053f17f08SMike Smith     owner = NULL;
16153f17f08SMike Smith     while ((ch = getopt(argc, argv, "ao:")) != -1)
16253f17f08SMike Smith 	switch(ch) {
16353f17f08SMike Smith 	case 'a':
16453f17f08SMike Smith 	    showall = 1;
16553f17f08SMike Smith 	    break;
16653f17f08SMike Smith 	case 'o':
16753f17f08SMike Smith 	    owner = strdup(optarg);
16853f17f08SMike Smith 	    break;
16953f17f08SMike Smith 	case '?':
17053f17f08SMike Smith 	default:
17153f17f08SMike Smith 	    help("list");
17253f17f08SMike Smith 	}
17353f17f08SMike Smith 
17453f17f08SMike Smith     mrd = mrgetall(memfd, &nd);
17553f17f08SMike Smith 
17653f17f08SMike Smith     for (i = 0; i < nd; i++) {
17753f17f08SMike Smith 	if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE))
17853f17f08SMike Smith 	    continue;
17953f17f08SMike Smith 	if (owner && strcmp(mrd[i].mr_owner, owner))
18053f17f08SMike Smith 	    continue;
18150f39947SEric Anholt 	printf("0x%" PRIx64 "/0x%" PRIx64 " %.8s ", mrd[i].mr_base, mrd[i].mr_len,
18253f17f08SMike Smith 	       mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-");
18353f17f08SMike Smith 	for (j = 0; attrnames[j].name != NULL; j++)
18453f17f08SMike Smith 	    if (mrd[i].mr_flags & attrnames[j].val)
18553f17f08SMike Smith 		printf("%s ", attrnames[j].name);
18653f17f08SMike Smith 	printf("\n");
18753f17f08SMike Smith     }
18853f17f08SMike Smith     free(mrd);
18953f17f08SMike Smith     if (owner)
19053f17f08SMike Smith 	free(owner);
19153f17f08SMike Smith }
19253f17f08SMike Smith 
19353f17f08SMike Smith static void
19453f17f08SMike Smith setfunc(int memfd, int argc, char *argv[])
19553f17f08SMike Smith {
19653f17f08SMike Smith     struct mem_range_desc	mrd;
19753f17f08SMike Smith     struct mem_range_op		mro;
19853f17f08SMike Smith     int				i;
19953f17f08SMike Smith     int				ch;
20053f17f08SMike Smith     char			*ep;
20153f17f08SMike Smith 
20253f17f08SMike Smith     mrd.mr_base = 0;
20353f17f08SMike Smith     mrd.mr_len = 0;
20453f17f08SMike Smith     mrd.mr_flags = 0;
20553f17f08SMike Smith     strcpy(mrd.mr_owner, "user");
20653f17f08SMike Smith     while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
20753f17f08SMike Smith 	switch(ch) {
20853f17f08SMike Smith 	case 'b':
20953f17f08SMike Smith 	    mrd.mr_base = strtouq(optarg, &ep, 0);
21053f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
21153f17f08SMike Smith 		help("set");
21253f17f08SMike Smith 	    break;
21353f17f08SMike Smith 	case 'l':
21453f17f08SMike Smith 	    mrd.mr_len = strtouq(optarg, &ep, 0);
21553f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
21653f17f08SMike Smith 		help("set");
21753f17f08SMike Smith 	    break;
21853f17f08SMike Smith 	case 'o':
21953f17f08SMike Smith 	    if ((*optarg == 0) || (strlen(optarg) > 7))
22053f17f08SMike Smith 		help("set");
22153f17f08SMike Smith 	    strcpy(mrd.mr_owner, optarg);
22253f17f08SMike Smith 	    break;
22353f17f08SMike Smith 
22453f17f08SMike Smith 	case '?':
22553f17f08SMike Smith 	default:
22653f17f08SMike Smith 	    help("set");
22753f17f08SMike Smith 	}
22853f17f08SMike Smith 
22953f17f08SMike Smith     if (mrd.mr_len == 0)
23053f17f08SMike Smith 	help("set");
23153f17f08SMike Smith 
23253f17f08SMike Smith     argc -= optind;
23353f17f08SMike Smith     argv += optind;
23453f17f08SMike Smith 
23553f17f08SMike Smith     while(argc--) {
23653f17f08SMike Smith 	for (i = 0; attrnames[i].name != NULL; i++) {
23753f17f08SMike Smith 	    if (!strcmp(attrnames[i].name, argv[0])) {
23853f17f08SMike Smith 		if (!attrnames[i].kind & MDF_SETTABLE)
23953f17f08SMike Smith 		    help("flags");
24053f17f08SMike Smith 		mrd.mr_flags |= attrnames[i].val;
24153f17f08SMike Smith 		break;
24253f17f08SMike Smith 	    }
24353f17f08SMike Smith 	}
24453f17f08SMike Smith 	if (attrnames[i].name == NULL)
24553f17f08SMike Smith 	    help("flags");
24653f17f08SMike Smith 	argv++;
24753f17f08SMike Smith     }
24853f17f08SMike Smith 
24953f17f08SMike Smith     mro.mo_desc = &mrd;
25053f17f08SMike Smith     mro.mo_arg[0] = 0;
25153f17f08SMike Smith     if (ioctl(memfd, MEMRANGE_SET, &mro))
25253f17f08SMike Smith 	err(1, "can't set range");
25353f17f08SMike Smith }
25453f17f08SMike Smith 
25553f17f08SMike Smith static void
25653f17f08SMike Smith clearfunc(int memfd, int argc, char *argv[])
25753f17f08SMike Smith {
25853f17f08SMike Smith     struct mem_range_desc	mrd, *mrdp;
25953f17f08SMike Smith     struct mem_range_op		mro;
26053f17f08SMike Smith     int				i, nd;
26153f17f08SMike Smith     int				ch;
26253f17f08SMike Smith     char			*ep, *owner;
26353f17f08SMike Smith 
26453f17f08SMike Smith     mrd.mr_base = 0;
26553f17f08SMike Smith     mrd.mr_len = 0;
26653f17f08SMike Smith     owner = NULL;
26753f17f08SMike Smith     while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
26853f17f08SMike Smith 	switch(ch) {
26953f17f08SMike Smith 	case 'b':
27053f17f08SMike Smith 	    mrd.mr_base = strtouq(optarg, &ep, 0);
27153f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
27253f17f08SMike Smith 		help("clear");
27353f17f08SMike Smith 	    break;
27453f17f08SMike Smith 	case 'l':
27553f17f08SMike Smith 	    mrd.mr_len = strtouq(optarg, &ep, 0);
27653f17f08SMike Smith 	    if ((ep == optarg) || (*ep != 0))
27753f17f08SMike Smith 		help("clear");
27853f17f08SMike Smith 	    break;
27953f17f08SMike Smith 	case 'o':
28053f17f08SMike Smith 	    if ((*optarg == 0) || (strlen(optarg) > 7))
28153f17f08SMike Smith 		help("clear");
28253f17f08SMike Smith 	    owner = strdup(optarg);
28353f17f08SMike Smith 	    break;
28453f17f08SMike Smith 
28553f17f08SMike Smith 	case '?':
28653f17f08SMike Smith 	default:
28753f17f08SMike Smith 	    help("clear");
28853f17f08SMike Smith 	}
28953f17f08SMike Smith 
29053f17f08SMike Smith     if (owner != NULL) {
29153f17f08SMike Smith 	/* clear-by-owner */
29253f17f08SMike Smith 	if ((mrd.mr_base != 0) || (mrd.mr_len != 0))
29353f17f08SMike Smith 	    help("clear");
29453f17f08SMike Smith 
29553f17f08SMike Smith 	mrdp = mrgetall(memfd, &nd);
29653f17f08SMike Smith 	mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
29753f17f08SMike Smith 	for (i = 0; i < nd; i++) {
29853f17f08SMike Smith 	    if (!strcmp(owner, mrdp[i].mr_owner) &&
29953f17f08SMike Smith 		(mrdp[i].mr_flags & MDF_ACTIVE) &&
30053f17f08SMike Smith 		!(mrdp[i].mr_flags & MDF_FIXACTIVE)) {
30153f17f08SMike Smith 
30253f17f08SMike Smith 		mro.mo_desc = mrdp + i;
30353f17f08SMike Smith 		if (ioctl(memfd, MEMRANGE_SET, &mro))
30453f17f08SMike Smith 		    warn("couldn't clear range owned by '%s'", owner);
30553f17f08SMike Smith 	    }
30653f17f08SMike Smith 	}
3072e61f987SBrian Feldman     } else if (mrd.mr_len != 0) {
30853f17f08SMike Smith 	/* clear-by-base/len */
30953f17f08SMike Smith 	mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
31053f17f08SMike Smith 	mro.mo_desc = &mrd;
31153f17f08SMike Smith 	if (ioctl(memfd, MEMRANGE_SET, &mro))
31253f17f08SMike Smith 	    err(1, "couldn't clear range");
31353f17f08SMike Smith     } else {
31453f17f08SMike Smith 	help("clear");
31553f17f08SMike Smith     }
31653f17f08SMike Smith }
31753f17f08SMike Smith 
31853f17f08SMike Smith static void
3191a842e25SXin LI helpfunc(__unused int memfd, __unused int argc, char *argv[])
32053f17f08SMike Smith {
3215fd6b620SMike Smith     help(argv[1]);
32253f17f08SMike Smith }
32353f17f08SMike Smith 
32453f17f08SMike Smith static void
3251a842e25SXin LI help(const char *what)
32653f17f08SMike Smith {
3275fd6b620SMike Smith     int		i;
3285fd6b620SMike Smith 
3295fd6b620SMike Smith     if (what != NULL) {
3305fd6b620SMike Smith 	/* find a function that matches */
3315fd6b620SMike Smith 	for (i = 0; functions[i].cmd != NULL; i++)
3325fd6b620SMike Smith 	    if (!strcmp(what, functions[i].cmd)) {
3335fd6b620SMike Smith 		fprintf(stderr, "%s\n", functions[i].desc);
3345fd6b620SMike Smith 		return;
3355fd6b620SMike Smith 	    }
3365fd6b620SMike Smith 	fprintf(stderr, "Unknown command '%s'\n", what);
3375fd6b620SMike Smith     }
3385fd6b620SMike Smith 
3395fd6b620SMike Smith     /* print general help */
3405fd6b620SMike Smith     fprintf(stderr, "Valid commands are :\n");
3415fd6b620SMike Smith     for (i = 0; functions[i].cmd != NULL; i++)
3425fd6b620SMike Smith 	fprintf(stderr, "    %s\n", functions[i].cmd);
3435fd6b620SMike Smith     fprintf(stderr, "Use help <command> for command-specific help\n");
34453f17f08SMike Smith }
345