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> 351a37aa56SDavid E. O'Brien #include <paths.h> 3653f17f08SMike Smith #include <stdio.h> 3753f17f08SMike Smith #include <stdlib.h> 3853f17f08SMike Smith #include <string.h> 3953f17f08SMike Smith #include <unistd.h> 4053f17f08SMike Smith 4153f17f08SMike Smith struct 4253f17f08SMike Smith { 4353f17f08SMike Smith 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}, 5353f17f08SMike Smith {"fixed-base", MDF_FIXBASE, 0}, 5453f17f08SMike Smith {"fixed-length", MDF_FIXLEN, 0}, 5553f17f08SMike Smith {"set-by-firmware", MDF_FIRMWARE, 0}, 5653f17f08SMike Smith {"active", MDF_ACTIVE, MDF_SETTABLE}, 5753f17f08SMike Smith {"bogus", MDF_BOGUS, 0}, 5853f17f08SMike Smith {NULL, 0, 0} 5953f17f08SMike Smith }; 6053f17f08SMike Smith 6153f17f08SMike Smith static void listfunc(int memfd, int argc, char *argv[]); 6253f17f08SMike Smith static void setfunc(int memfd, int argc, char *argv[]); 6353f17f08SMike Smith static void clearfunc(int memfd, int argc, char *argv[]); 6453f17f08SMike Smith static void helpfunc(int memfd, int argc, char *argv[]); 6553f17f08SMike Smith static void help(char *what); 6653f17f08SMike Smith 6753f17f08SMike Smith struct 6853f17f08SMike Smith { 6953f17f08SMike Smith char *cmd; 7053f17f08SMike Smith char *desc; 7153f17f08SMike Smith void (*func)(int memfd, int argc, char *argv[]); 7253f17f08SMike Smith } functions[] = { 7353f17f08SMike Smith {"list", 7453f17f08SMike Smith "List current memory range attributes\n" 7553f17f08SMike Smith " list [-a]\n" 7653f17f08SMike Smith " -a list all range slots, even those that are inactive", 7753f17f08SMike Smith listfunc}, 7853f17f08SMike Smith {"set", 7953f17f08SMike Smith "Set memory range attributes\n" 8053f17f08SMike Smith " set -b <base> -l <length> -o <owner> <attribute>\n" 8153f17f08SMike Smith " <base> memory range base address\n" 8253f17f08SMike Smith " <length> length of memory range in bytes, power of 2\n" 8353f17f08SMike Smith " <owner> text identifier for this setting (7 char max)\n" 8453f17f08SMike Smith " <attribute> attribute(s) to be applied to this range:\n" 8553f17f08SMike Smith " uncacheable\n" 8653f17f08SMike Smith " write-combine\n" 8753f17f08SMike Smith " write-through\n" 8853f17f08SMike Smith " write-back\n" 8953f17f08SMike Smith " write-protect", 9053f17f08SMike Smith setfunc}, 9153f17f08SMike Smith {"clear", 9253f17f08SMike Smith "Clear memory range attributes\n" 9353f17f08SMike Smith " clear -o <owner>\n" 9453f17f08SMike Smith " <owner> all ranges with this owner will be cleared\n" 9553f17f08SMike Smith " clear -b <base> -l <length>\n" 9653f17f08SMike Smith " <base> memory range base address\n" 9753f17f08SMike Smith " <length> length of memory range in bytes, power of 2\n" 9853f17f08SMike Smith " Base and length must exactly match an existing range", 9953f17f08SMike Smith clearfunc}, 10053f17f08SMike Smith {NULL, NULL, helpfunc} 10153f17f08SMike Smith }; 10253f17f08SMike Smith 10353f17f08SMike Smith int 10453f17f08SMike Smith main(int argc, char *argv[]) 10553f17f08SMike Smith { 10653f17f08SMike Smith int i, memfd; 10753f17f08SMike Smith 10853f17f08SMike Smith if (argc < 2) { 10953f17f08SMike Smith help(NULL); 11053f17f08SMike Smith } else { 1111a37aa56SDavid E. O'Brien if ((memfd = open(_PATH_MEM, O_RDONLY)) == -1) 1121a37aa56SDavid E. O'Brien err(1, "can't open %s", _PATH_MEM); 11353f17f08SMike Smith 11453f17f08SMike Smith for (i = 0; functions[i].cmd != NULL; i++) 11553f17f08SMike Smith if (!strcmp(argv[1], functions[i].cmd)) 11653f17f08SMike Smith break; 11753f17f08SMike Smith functions[i].func(memfd, argc - 1, argv + 1); 11853f17f08SMike Smith close(memfd); 11953f17f08SMike Smith } 12053f17f08SMike Smith return(0); 12153f17f08SMike Smith } 12253f17f08SMike Smith 12353f17f08SMike Smith static struct mem_range_desc * 12453f17f08SMike Smith mrgetall(int memfd, int *nmr) 12553f17f08SMike Smith { 12653f17f08SMike Smith struct mem_range_desc *mrd; 12753f17f08SMike Smith struct mem_range_op mro; 12853f17f08SMike Smith 12953f17f08SMike Smith mro.mo_arg[0] = 0; 13053f17f08SMike Smith if (ioctl(memfd, MEMRANGE_GET, &mro)) 13153f17f08SMike Smith err(1, "can't size range descriptor array"); 13253f17f08SMike Smith 13353f17f08SMike Smith *nmr = mro.mo_arg[0]; 13453f17f08SMike Smith mrd = malloc(*nmr * sizeof(struct mem_range_desc)); 13553f17f08SMike Smith if (mrd == NULL) 13653f17f08SMike Smith errx(1, "can't allocate %d bytes for %d range descriptors", 13753f17f08SMike Smith *nmr * sizeof(struct mem_range_desc), *nmr); 13853f17f08SMike Smith 13953f17f08SMike Smith mro.mo_arg[0] = *nmr; 14053f17f08SMike Smith mro.mo_desc = mrd; 14153f17f08SMike Smith if (ioctl(memfd, MEMRANGE_GET, &mro)) 14253f17f08SMike Smith err(1, "can't fetch range descriptor array"); 14353f17f08SMike Smith 14453f17f08SMike Smith return(mrd); 14553f17f08SMike Smith } 14653f17f08SMike Smith 14753f17f08SMike Smith 14853f17f08SMike Smith static void 14953f17f08SMike Smith listfunc(int memfd, int argc, char *argv[]) 15053f17f08SMike Smith { 15153f17f08SMike Smith struct mem_range_desc *mrd; 15253f17f08SMike Smith int nd, i, j; 15353f17f08SMike Smith int error; 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; 17953f17f08SMike Smith printf("%qx/%qx %.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 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])) { 23653f17f08SMike Smith 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 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 31753f17f08SMike Smith helpfunc(int memfd, int argc, char *argv[]) 31853f17f08SMike Smith { 3195fd6b620SMike Smith help(argv[1]); 32053f17f08SMike Smith } 32153f17f08SMike Smith 32253f17f08SMike Smith static void 32353f17f08SMike Smith help(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