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