145410Smsmith/*-
245410Smsmith * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
345410Smsmith * All rights reserved.
445410Smsmith *
545410Smsmith * Redistribution and use in source and binary forms, with or without
645410Smsmith * modification, are permitted provided that the following conditions
745410Smsmith * are met:
845410Smsmith * 1. Redistributions of source code must retain the above copyright
945410Smsmith *    notice, this list of conditions and the following disclaimer.
1045410Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1145410Smsmith *    notice, this list of conditions and the following disclaimer in the
1245410Smsmith *    documentation and/or other materials provided with the distribution.
1345410Smsmith *
1445410Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1545410Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1645410Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1745410Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1845410Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1945410Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2045410Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2145410Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2245410Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2345410Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2445410Smsmith * SUCH DAMAGE.
2545410Smsmith *
2650479Speter * $FreeBSD$
2745410Smsmith */
2845410Smsmith
2945410Smsmith#include <sys/types.h>
3045410Smsmith#include <sys/ioctl.h>
3145410Smsmith#include <sys/memrange.h>
3245410Smsmith
3345410Smsmith#include <err.h>
3445410Smsmith#include <fcntl.h>
35139854Sdelphij#include <inttypes.h>
3669793Sobrien#include <paths.h>
3745410Smsmith#include <stdio.h>
3845410Smsmith#include <stdlib.h>
3945410Smsmith#include <string.h>
4045410Smsmith#include <unistd.h>
4145410Smsmith
42227254Sedstatic struct {
43139854Sdelphij    const char	*name;
4445410Smsmith    int		val;
4545410Smsmith    int		kind;
4645410Smsmith#define MDF_SETTABLE	(1<<0)
4745410Smsmith} attrnames[] = {
4845410Smsmith    {"uncacheable",	MDF_UNCACHEABLE,	MDF_SETTABLE},
4945410Smsmith    {"write-combine",	MDF_WRITECOMBINE,	MDF_SETTABLE},
5045410Smsmith    {"write-through",	MDF_WRITETHROUGH,	MDF_SETTABLE},
5145410Smsmith    {"write-back",	MDF_WRITEBACK,		MDF_SETTABLE},
5245410Smsmith    {"write-protect",	MDF_WRITEPROTECT,	MDF_SETTABLE},
53103346Sdwmalone    {"force",		MDF_FORCE,		MDF_SETTABLE},
5494684Sdwmalone    {"unknown",		MDF_UNKNOWN,		0},
5545410Smsmith    {"fixed-base",	MDF_FIXBASE,		0},
5645410Smsmith    {"fixed-length",	MDF_FIXLEN,		0},
5745410Smsmith    {"set-by-firmware",	MDF_FIRMWARE,		0},
5845410Smsmith    {"active",		MDF_ACTIVE,		MDF_SETTABLE},
5945410Smsmith    {"bogus",		MDF_BOGUS,		0},
6045410Smsmith    {NULL,		0,			0}
6145410Smsmith};
6245410Smsmith
6345410Smsmithstatic void	listfunc(int memfd, int argc, char *argv[]);
6445410Smsmithstatic void	setfunc(int memfd, int argc, char *argv[]);
6545410Smsmithstatic void	clearfunc(int memfd, int argc, char *argv[]);
6645410Smsmithstatic void	helpfunc(int memfd, int argc, char *argv[]);
67139854Sdelphijstatic void	help(const char *what);
6845410Smsmith
69227254Sedstatic struct {
70139854Sdelphij    const char	*cmd;
71139854Sdelphij    const char	*desc;
7245410Smsmith    void	(*func)(int memfd, int argc, char *argv[]);
7345410Smsmith} functions[] = {
7445410Smsmith    {"list",
7545410Smsmith     "List current memory range attributes\n"
7645410Smsmith     "    list [-a]\n"
7745410Smsmith     "        -a    list all range slots, even those that are inactive",
7845410Smsmith     listfunc},
7945410Smsmith    {"set",
8045410Smsmith     "Set memory range attributes\n"
8145410Smsmith     "    set -b <base> -l <length> -o <owner> <attribute>\n"
8245410Smsmith     "        <base>      memory range base address\n"
8345410Smsmith     "        <length>    length of memory range in bytes, power of 2\n"
8445410Smsmith     "        <owner>     text identifier for this setting (7 char max)\n"
8545410Smsmith     "        <attribute> attribute(s) to be applied to this range:\n"
8645410Smsmith     "                        uncacheable\n"
8745410Smsmith     "                        write-combine\n"
8845410Smsmith     "                        write-through\n"
8945410Smsmith     "                        write-back\n"
9045410Smsmith     "                        write-protect",
9145410Smsmith     setfunc},
9245410Smsmith    {"clear",
9345410Smsmith     "Clear memory range attributes\n"
9445410Smsmith     "    clear -o <owner>\n"
9545410Smsmith     "        <owner>     all ranges with this owner will be cleared\n"
9645410Smsmith     "    clear -b <base> -l <length>\n"
9745410Smsmith     "        <base>      memory range base address\n"
9845410Smsmith     "        <length>    length of memory range in bytes, power of 2\n"
9945410Smsmith     "                    Base and length must exactly match an existing range",
10045410Smsmith     clearfunc},
10145410Smsmith    {NULL,	NULL,					helpfunc}
10245410Smsmith};
10345410Smsmith
10445410Smsmithint
10545410Smsmithmain(int argc, char *argv[])
10645410Smsmith{
10745410Smsmith    int		i, memfd;
10845410Smsmith
10945410Smsmith    if (argc < 2) {
11045410Smsmith	help(NULL);
11145410Smsmith    } else {
11269793Sobrien	if ((memfd = open(_PATH_MEM, O_RDONLY)) == -1)
11369793Sobrien	    err(1, "can't open %s", _PATH_MEM);
11445410Smsmith
11545410Smsmith	for (i = 0; functions[i].cmd != NULL; i++)
11645410Smsmith	    if (!strcmp(argv[1], functions[i].cmd))
11745410Smsmith		break;
11845410Smsmith	functions[i].func(memfd, argc - 1, argv + 1);
11945410Smsmith	close(memfd);
12045410Smsmith    }
12145410Smsmith    return(0);
12245410Smsmith}
12345410Smsmith
12445410Smsmithstatic struct mem_range_desc *
12545410Smsmithmrgetall(int memfd, int *nmr)
12645410Smsmith{
12745410Smsmith    struct mem_range_desc	*mrd;
12845410Smsmith    struct mem_range_op		mro;
12945410Smsmith
13045410Smsmith    mro.mo_arg[0] = 0;
13145410Smsmith    if (ioctl(memfd, MEMRANGE_GET, &mro))
13245410Smsmith	err(1, "can't size range descriptor array");
13345410Smsmith
13445410Smsmith    *nmr = mro.mo_arg[0];
13545410Smsmith    mrd = malloc(*nmr * sizeof(struct mem_range_desc));
13645410Smsmith    if (mrd == NULL)
137139854Sdelphij	errx(1, "can't allocate %zd bytes for %d range descriptors",
13845410Smsmith	     *nmr * sizeof(struct mem_range_desc), *nmr);
13945410Smsmith
14045410Smsmith    mro.mo_arg[0] = *nmr;
14145410Smsmith    mro.mo_desc = mrd;
14245410Smsmith    if (ioctl(memfd, MEMRANGE_GET, &mro))
14345410Smsmith	err(1, "can't fetch range descriptor array");
14445410Smsmith
14545410Smsmith    return(mrd);
14645410Smsmith}
14745410Smsmith
14845410Smsmith
14945410Smsmithstatic void
15045410Smsmithlistfunc(int memfd, int argc, char *argv[])
15145410Smsmith{
15245410Smsmith    struct mem_range_desc	*mrd;
15345410Smsmith    int				nd, i, j;
15445410Smsmith    int				ch;
15545410Smsmith    int				showall = 0;
15645410Smsmith    char			*owner;
15745410Smsmith
15845410Smsmith    owner = NULL;
15945410Smsmith    while ((ch = getopt(argc, argv, "ao:")) != -1)
16045410Smsmith	switch(ch) {
16145410Smsmith	case 'a':
16245410Smsmith	    showall = 1;
16345410Smsmith	    break;
16445410Smsmith	case 'o':
16545410Smsmith	    owner = strdup(optarg);
16645410Smsmith	    break;
16745410Smsmith	case '?':
16845410Smsmith	default:
16945410Smsmith	    help("list");
17045410Smsmith	}
17145410Smsmith
17245410Smsmith    mrd = mrgetall(memfd, &nd);
17345410Smsmith
17445410Smsmith    for (i = 0; i < nd; i++) {
17545410Smsmith	if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE))
17645410Smsmith	    continue;
17745410Smsmith	if (owner && strcmp(mrd[i].mr_owner, owner))
17845410Smsmith	    continue;
179144303Sanholt	printf("0x%" PRIx64 "/0x%" PRIx64 " %.8s ", mrd[i].mr_base, mrd[i].mr_len,
18045410Smsmith	       mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-");
18145410Smsmith	for (j = 0; attrnames[j].name != NULL; j++)
18245410Smsmith	    if (mrd[i].mr_flags & attrnames[j].val)
18345410Smsmith		printf("%s ", attrnames[j].name);
18445410Smsmith	printf("\n");
18545410Smsmith    }
18645410Smsmith    free(mrd);
18745410Smsmith    if (owner)
18845410Smsmith	free(owner);
18945410Smsmith}
19045410Smsmith
19145410Smsmithstatic void
19245410Smsmithsetfunc(int memfd, int argc, char *argv[])
19345410Smsmith{
19445410Smsmith    struct mem_range_desc	mrd;
19545410Smsmith    struct mem_range_op		mro;
19645410Smsmith    int				i;
19745410Smsmith    int				ch;
19845410Smsmith    char			*ep;
19945410Smsmith
20045410Smsmith    mrd.mr_base = 0;
20145410Smsmith    mrd.mr_len = 0;
20245410Smsmith    mrd.mr_flags = 0;
20345410Smsmith    strcpy(mrd.mr_owner, "user");
20445410Smsmith    while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
20545410Smsmith	switch(ch) {
20645410Smsmith	case 'b':
20745410Smsmith	    mrd.mr_base = strtouq(optarg, &ep, 0);
20845410Smsmith	    if ((ep == optarg) || (*ep != 0))
20945410Smsmith		help("set");
21045410Smsmith	    break;
21145410Smsmith	case 'l':
21245410Smsmith	    mrd.mr_len = strtouq(optarg, &ep, 0);
21345410Smsmith	    if ((ep == optarg) || (*ep != 0))
21445410Smsmith		help("set");
21545410Smsmith	    break;
21645410Smsmith	case 'o':
21745410Smsmith	    if ((*optarg == 0) || (strlen(optarg) > 7))
21845410Smsmith		help("set");
21945410Smsmith	    strcpy(mrd.mr_owner, optarg);
22045410Smsmith	    break;
22145410Smsmith
22245410Smsmith	case '?':
22345410Smsmith	default:
22445410Smsmith	    help("set");
22545410Smsmith	}
22645410Smsmith
22745410Smsmith    if (mrd.mr_len == 0)
22845410Smsmith	help("set");
22945410Smsmith
23045410Smsmith    argc -= optind;
23145410Smsmith    argv += optind;
23245410Smsmith
23345410Smsmith    while(argc--) {
23445410Smsmith	for (i = 0; attrnames[i].name != NULL; i++) {
23545410Smsmith	    if (!strcmp(attrnames[i].name, argv[0])) {
236241829Seadler		if (!(attrnames[i].kind & MDF_SETTABLE))
23745410Smsmith		    help("flags");
23845410Smsmith		mrd.mr_flags |= attrnames[i].val;
23945410Smsmith		break;
24045410Smsmith	    }
24145410Smsmith	}
24245410Smsmith	if (attrnames[i].name == NULL)
24345410Smsmith	    help("flags");
24445410Smsmith	argv++;
24545410Smsmith    }
24645410Smsmith
24745410Smsmith    mro.mo_desc = &mrd;
24845410Smsmith    mro.mo_arg[0] = 0;
24945410Smsmith    if (ioctl(memfd, MEMRANGE_SET, &mro))
25045410Smsmith	err(1, "can't set range");
25145410Smsmith}
25245410Smsmith
25345410Smsmithstatic void
25445410Smsmithclearfunc(int memfd, int argc, char *argv[])
25545410Smsmith{
25645410Smsmith    struct mem_range_desc	mrd, *mrdp;
25745410Smsmith    struct mem_range_op		mro;
25845410Smsmith    int				i, nd;
25945410Smsmith    int				ch;
26045410Smsmith    char			*ep, *owner;
26145410Smsmith
26245410Smsmith    mrd.mr_base = 0;
26345410Smsmith    mrd.mr_len = 0;
26445410Smsmith    owner = NULL;
26545410Smsmith    while ((ch = getopt(argc, argv, "b:l:o:")) != -1)
26645410Smsmith	switch(ch) {
26745410Smsmith	case 'b':
26845410Smsmith	    mrd.mr_base = strtouq(optarg, &ep, 0);
26945410Smsmith	    if ((ep == optarg) || (*ep != 0))
27045410Smsmith		help("clear");
27145410Smsmith	    break;
27245410Smsmith	case 'l':
27345410Smsmith	    mrd.mr_len = strtouq(optarg, &ep, 0);
27445410Smsmith	    if ((ep == optarg) || (*ep != 0))
27545410Smsmith		help("clear");
27645410Smsmith	    break;
27745410Smsmith	case 'o':
27845410Smsmith	    if ((*optarg == 0) || (strlen(optarg) > 7))
27945410Smsmith		help("clear");
28045410Smsmith	    owner = strdup(optarg);
28145410Smsmith	    break;
28245410Smsmith
28345410Smsmith	case '?':
28445410Smsmith	default:
28545410Smsmith	    help("clear");
28645410Smsmith	}
28745410Smsmith
28845410Smsmith    if (owner != NULL) {
28945410Smsmith	/* clear-by-owner */
29045410Smsmith	if ((mrd.mr_base != 0) || (mrd.mr_len != 0))
29145410Smsmith	    help("clear");
29245410Smsmith
29345410Smsmith	mrdp = mrgetall(memfd, &nd);
29445410Smsmith	mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
29545410Smsmith	for (i = 0; i < nd; i++) {
29645410Smsmith	    if (!strcmp(owner, mrdp[i].mr_owner) &&
29745410Smsmith		(mrdp[i].mr_flags & MDF_ACTIVE) &&
29845410Smsmith		!(mrdp[i].mr_flags & MDF_FIXACTIVE)) {
29945410Smsmith
30045410Smsmith		mro.mo_desc = mrdp + i;
30145410Smsmith		if (ioctl(memfd, MEMRANGE_SET, &mro))
30245410Smsmith		    warn("couldn't clear range owned by '%s'", owner);
30345410Smsmith	    }
30445410Smsmith	}
30558408Sgreen    } else if (mrd.mr_len != 0) {
30645410Smsmith	/* clear-by-base/len */
30745410Smsmith	mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
30845410Smsmith	mro.mo_desc = &mrd;
30945410Smsmith	if (ioctl(memfd, MEMRANGE_SET, &mro))
31045410Smsmith	    err(1, "couldn't clear range");
31145410Smsmith    } else {
31245410Smsmith	help("clear");
31345410Smsmith    }
31445410Smsmith}
31545410Smsmith
31645410Smsmithstatic void
317139854Sdelphijhelpfunc(__unused int memfd, __unused int argc, char *argv[])
31845410Smsmith{
31948920Smsmith    help(argv[1]);
32045410Smsmith}
32145410Smsmith
32245410Smsmithstatic void
323139854Sdelphijhelp(const char *what)
32445410Smsmith{
32548920Smsmith    int		i;
32648920Smsmith
32748920Smsmith    if (what != NULL) {
32848920Smsmith	/* find a function that matches */
32948920Smsmith	for (i = 0; functions[i].cmd != NULL; i++)
33048920Smsmith	    if (!strcmp(what, functions[i].cmd)) {
33148920Smsmith		fprintf(stderr, "%s\n", functions[i].desc);
33248920Smsmith		return;
33348920Smsmith	    }
33448920Smsmith	fprintf(stderr, "Unknown command '%s'\n", what);
33548920Smsmith    }
33648920Smsmith
33748920Smsmith    /* print general help */
33848920Smsmith    fprintf(stderr, "Valid commands are :\n");
33948920Smsmith    for (i = 0; functions[i].cmd != NULL; i++)
34048920Smsmith	fprintf(stderr, "    %s\n", functions[i].cmd);
34148920Smsmith    fprintf(stderr, "Use help <command> for command-specific help\n");
34245410Smsmith}
343