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