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}, 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[]); 6753f17f08SMike Smith static void help(char *what); 6853f17f08SMike Smith 6953f17f08SMike Smith struct 7053f17f08SMike Smith { 7153f17f08SMike Smith char *cmd; 7253f17f08SMike Smith char *desc; 7353f17f08SMike Smith void (*func)(int memfd, int argc, char *argv[]); 7453f17f08SMike Smith } functions[] = { 7553f17f08SMike Smith {"list", 7653f17f08SMike Smith "List current memory range attributes\n" 7753f17f08SMike Smith " list [-a]\n" 7853f17f08SMike Smith " -a list all range slots, even those that are inactive", 7953f17f08SMike Smith listfunc}, 8053f17f08SMike Smith {"set", 8153f17f08SMike Smith "Set memory range attributes\n" 8253f17f08SMike Smith " set -b <base> -l <length> -o <owner> <attribute>\n" 8353f17f08SMike Smith " <base> memory range base address\n" 8453f17f08SMike Smith " <length> length of memory range in bytes, power of 2\n" 8553f17f08SMike Smith " <owner> text identifier for this setting (7 char max)\n" 8653f17f08SMike Smith " <attribute> attribute(s) to be applied to this range:\n" 8753f17f08SMike Smith " uncacheable\n" 8853f17f08SMike Smith " write-combine\n" 8953f17f08SMike Smith " write-through\n" 9053f17f08SMike Smith " write-back\n" 9153f17f08SMike Smith " write-protect", 9253f17f08SMike Smith setfunc}, 9353f17f08SMike Smith {"clear", 9453f17f08SMike Smith "Clear memory range attributes\n" 9553f17f08SMike Smith " clear -o <owner>\n" 9653f17f08SMike Smith " <owner> all ranges with this owner will be cleared\n" 9753f17f08SMike Smith " clear -b <base> -l <length>\n" 9853f17f08SMike Smith " <base> memory range base address\n" 9953f17f08SMike Smith " <length> length of memory range in bytes, power of 2\n" 10053f17f08SMike Smith " Base and length must exactly match an existing range", 10153f17f08SMike Smith clearfunc}, 10253f17f08SMike Smith {NULL, NULL, helpfunc} 10353f17f08SMike Smith }; 10453f17f08SMike Smith 10553f17f08SMike Smith int 10653f17f08SMike Smith main(int argc, char *argv[]) 10753f17f08SMike Smith { 10853f17f08SMike Smith int i, memfd; 10953f17f08SMike Smith 11053f17f08SMike Smith if (argc < 2) { 11153f17f08SMike Smith help(NULL); 11253f17f08SMike Smith } else { 1131a37aa56SDavid E. O'Brien if ((memfd = open(_PATH_MEM, O_RDONLY)) == -1) 1141a37aa56SDavid E. O'Brien err(1, "can't open %s", _PATH_MEM); 11553f17f08SMike Smith 11653f17f08SMike Smith for (i = 0; functions[i].cmd != NULL; i++) 11753f17f08SMike Smith if (!strcmp(argv[1], functions[i].cmd)) 11853f17f08SMike Smith break; 11953f17f08SMike Smith functions[i].func(memfd, argc - 1, argv + 1); 12053f17f08SMike Smith close(memfd); 12153f17f08SMike Smith } 12253f17f08SMike Smith return(0); 12353f17f08SMike Smith } 12453f17f08SMike Smith 12553f17f08SMike Smith static struct mem_range_desc * 12653f17f08SMike Smith mrgetall(int memfd, int *nmr) 12753f17f08SMike Smith { 12853f17f08SMike Smith struct mem_range_desc *mrd; 12953f17f08SMike Smith struct mem_range_op mro; 13053f17f08SMike Smith 13153f17f08SMike Smith mro.mo_arg[0] = 0; 13253f17f08SMike Smith if (ioctl(memfd, MEMRANGE_GET, &mro)) 13353f17f08SMike Smith err(1, "can't size range descriptor array"); 13453f17f08SMike Smith 13553f17f08SMike Smith *nmr = mro.mo_arg[0]; 13653f17f08SMike Smith mrd = malloc(*nmr * sizeof(struct mem_range_desc)); 13753f17f08SMike Smith if (mrd == NULL) 13853f17f08SMike Smith errx(1, "can't allocate %d bytes for %d range descriptors", 13953f17f08SMike Smith *nmr * sizeof(struct mem_range_desc), *nmr); 14053f17f08SMike Smith 14153f17f08SMike Smith mro.mo_arg[0] = *nmr; 14253f17f08SMike Smith mro.mo_desc = mrd; 14353f17f08SMike Smith if (ioctl(memfd, MEMRANGE_GET, &mro)) 14453f17f08SMike Smith err(1, "can't fetch range descriptor array"); 14553f17f08SMike Smith 14653f17f08SMike Smith return(mrd); 14753f17f08SMike Smith } 14853f17f08SMike Smith 14953f17f08SMike Smith 15053f17f08SMike Smith static void 15153f17f08SMike Smith listfunc(int memfd, int argc, char *argv[]) 15253f17f08SMike Smith { 15353f17f08SMike Smith struct mem_range_desc *mrd; 15453f17f08SMike Smith int nd, i, j; 15553f17f08SMike Smith int ch; 15653f17f08SMike Smith int showall = 0; 15753f17f08SMike Smith char *owner; 15853f17f08SMike Smith 15953f17f08SMike Smith owner = NULL; 16053f17f08SMike Smith while ((ch = getopt(argc, argv, "ao:")) != -1) 16153f17f08SMike Smith switch(ch) { 16253f17f08SMike Smith case 'a': 16353f17f08SMike Smith showall = 1; 16453f17f08SMike Smith break; 16553f17f08SMike Smith case 'o': 16653f17f08SMike Smith owner = strdup(optarg); 16753f17f08SMike Smith break; 16853f17f08SMike Smith case '?': 16953f17f08SMike Smith default: 17053f17f08SMike Smith help("list"); 17153f17f08SMike Smith } 17253f17f08SMike Smith 17353f17f08SMike Smith mrd = mrgetall(memfd, &nd); 17453f17f08SMike Smith 17553f17f08SMike Smith for (i = 0; i < nd; i++) { 17653f17f08SMike Smith if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE)) 17753f17f08SMike Smith continue; 17853f17f08SMike Smith if (owner && strcmp(mrd[i].mr_owner, owner)) 17953f17f08SMike Smith continue; 18053f17f08SMike Smith printf("%qx/%qx %.8s ", mrd[i].mr_base, mrd[i].mr_len, 18153f17f08SMike Smith mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-"); 18253f17f08SMike Smith for (j = 0; attrnames[j].name != NULL; j++) 18353f17f08SMike Smith if (mrd[i].mr_flags & attrnames[j].val) 18453f17f08SMike Smith printf("%s ", attrnames[j].name); 18553f17f08SMike Smith printf("\n"); 18653f17f08SMike Smith } 18753f17f08SMike Smith free(mrd); 18853f17f08SMike Smith if (owner) 18953f17f08SMike Smith free(owner); 19053f17f08SMike Smith } 19153f17f08SMike Smith 19253f17f08SMike Smith static void 19353f17f08SMike Smith setfunc(int memfd, int argc, char *argv[]) 19453f17f08SMike Smith { 19553f17f08SMike Smith struct mem_range_desc mrd; 19653f17f08SMike Smith struct mem_range_op mro; 19753f17f08SMike Smith int i; 19853f17f08SMike Smith int ch; 19953f17f08SMike Smith char *ep; 20053f17f08SMike Smith 20153f17f08SMike Smith mrd.mr_base = 0; 20253f17f08SMike Smith mrd.mr_len = 0; 20353f17f08SMike Smith mrd.mr_flags = 0; 20453f17f08SMike Smith strcpy(mrd.mr_owner, "user"); 20553f17f08SMike Smith while ((ch = getopt(argc, argv, "b:l:o:")) != -1) 20653f17f08SMike Smith switch(ch) { 20753f17f08SMike Smith case 'b': 20853f17f08SMike Smith mrd.mr_base = strtouq(optarg, &ep, 0); 20953f17f08SMike Smith if ((ep == optarg) || (*ep != 0)) 21053f17f08SMike Smith help("set"); 21153f17f08SMike Smith break; 21253f17f08SMike Smith case 'l': 21353f17f08SMike Smith mrd.mr_len = strtouq(optarg, &ep, 0); 21453f17f08SMike Smith if ((ep == optarg) || (*ep != 0)) 21553f17f08SMike Smith help("set"); 21653f17f08SMike Smith break; 21753f17f08SMike Smith case 'o': 21853f17f08SMike Smith if ((*optarg == 0) || (strlen(optarg) > 7)) 21953f17f08SMike Smith help("set"); 22053f17f08SMike Smith strcpy(mrd.mr_owner, optarg); 22153f17f08SMike Smith break; 22253f17f08SMike Smith 22353f17f08SMike Smith case '?': 22453f17f08SMike Smith default: 22553f17f08SMike Smith help("set"); 22653f17f08SMike Smith } 22753f17f08SMike Smith 22853f17f08SMike Smith if (mrd.mr_len == 0) 22953f17f08SMike Smith help("set"); 23053f17f08SMike Smith 23153f17f08SMike Smith argc -= optind; 23253f17f08SMike Smith argv += optind; 23353f17f08SMike Smith 23453f17f08SMike Smith while(argc--) { 23553f17f08SMike Smith for (i = 0; attrnames[i].name != NULL; i++) { 23653f17f08SMike Smith if (!strcmp(attrnames[i].name, argv[0])) { 23753f17f08SMike Smith if (!attrnames[i].kind & MDF_SETTABLE) 23853f17f08SMike Smith help("flags"); 23953f17f08SMike Smith mrd.mr_flags |= attrnames[i].val; 24053f17f08SMike Smith break; 24153f17f08SMike Smith } 24253f17f08SMike Smith } 24353f17f08SMike Smith if (attrnames[i].name == NULL) 24453f17f08SMike Smith help("flags"); 24553f17f08SMike Smith argv++; 24653f17f08SMike Smith } 24753f17f08SMike Smith 24853f17f08SMike Smith mro.mo_desc = &mrd; 24953f17f08SMike Smith mro.mo_arg[0] = 0; 25053f17f08SMike Smith if (ioctl(memfd, MEMRANGE_SET, &mro)) 25153f17f08SMike Smith err(1, "can't set range"); 25253f17f08SMike Smith } 25353f17f08SMike Smith 25453f17f08SMike Smith static void 25553f17f08SMike Smith clearfunc(int memfd, int argc, char *argv[]) 25653f17f08SMike Smith { 25753f17f08SMike Smith struct mem_range_desc mrd, *mrdp; 25853f17f08SMike Smith struct mem_range_op mro; 25953f17f08SMike Smith int i, nd; 26053f17f08SMike Smith int ch; 26153f17f08SMike Smith char *ep, *owner; 26253f17f08SMike Smith 26353f17f08SMike Smith mrd.mr_base = 0; 26453f17f08SMike Smith mrd.mr_len = 0; 26553f17f08SMike Smith owner = NULL; 26653f17f08SMike Smith while ((ch = getopt(argc, argv, "b:l:o:")) != -1) 26753f17f08SMike Smith switch(ch) { 26853f17f08SMike Smith case 'b': 26953f17f08SMike Smith mrd.mr_base = strtouq(optarg, &ep, 0); 27053f17f08SMike Smith if ((ep == optarg) || (*ep != 0)) 27153f17f08SMike Smith help("clear"); 27253f17f08SMike Smith break; 27353f17f08SMike Smith case 'l': 27453f17f08SMike Smith mrd.mr_len = strtouq(optarg, &ep, 0); 27553f17f08SMike Smith if ((ep == optarg) || (*ep != 0)) 27653f17f08SMike Smith help("clear"); 27753f17f08SMike Smith break; 27853f17f08SMike Smith case 'o': 27953f17f08SMike Smith if ((*optarg == 0) || (strlen(optarg) > 7)) 28053f17f08SMike Smith help("clear"); 28153f17f08SMike Smith owner = strdup(optarg); 28253f17f08SMike Smith break; 28353f17f08SMike Smith 28453f17f08SMike Smith case '?': 28553f17f08SMike Smith default: 28653f17f08SMike Smith help("clear"); 28753f17f08SMike Smith } 28853f17f08SMike Smith 28953f17f08SMike Smith if (owner != NULL) { 29053f17f08SMike Smith /* clear-by-owner */ 29153f17f08SMike Smith if ((mrd.mr_base != 0) || (mrd.mr_len != 0)) 29253f17f08SMike Smith help("clear"); 29353f17f08SMike Smith 29453f17f08SMike Smith mrdp = mrgetall(memfd, &nd); 29553f17f08SMike Smith mro.mo_arg[0] = MEMRANGE_SET_REMOVE; 29653f17f08SMike Smith for (i = 0; i < nd; i++) { 29753f17f08SMike Smith if (!strcmp(owner, mrdp[i].mr_owner) && 29853f17f08SMike Smith (mrdp[i].mr_flags & MDF_ACTIVE) && 29953f17f08SMike Smith !(mrdp[i].mr_flags & MDF_FIXACTIVE)) { 30053f17f08SMike Smith 30153f17f08SMike Smith mro.mo_desc = mrdp + i; 30253f17f08SMike Smith if (ioctl(memfd, MEMRANGE_SET, &mro)) 30353f17f08SMike Smith warn("couldn't clear range owned by '%s'", owner); 30453f17f08SMike Smith } 30553f17f08SMike Smith } 3062e61f987SBrian Feldman } else if (mrd.mr_len != 0) { 30753f17f08SMike Smith /* clear-by-base/len */ 30853f17f08SMike Smith mro.mo_arg[0] = MEMRANGE_SET_REMOVE; 30953f17f08SMike Smith mro.mo_desc = &mrd; 31053f17f08SMike Smith if (ioctl(memfd, MEMRANGE_SET, &mro)) 31153f17f08SMike Smith err(1, "couldn't clear range"); 31253f17f08SMike Smith } else { 31353f17f08SMike Smith help("clear"); 31453f17f08SMike Smith } 31553f17f08SMike Smith } 31653f17f08SMike Smith 31753f17f08SMike Smith static void 31853f17f08SMike Smith helpfunc(int memfd, int argc, char *argv[]) 31953f17f08SMike Smith { 3205fd6b620SMike Smith help(argv[1]); 32153f17f08SMike Smith } 32253f17f08SMike Smith 32353f17f08SMike Smith static void 32453f17f08SMike Smith help(char *what) 32553f17f08SMike Smith { 3265fd6b620SMike Smith int i; 3275fd6b620SMike Smith 3285fd6b620SMike Smith if (what != NULL) { 3295fd6b620SMike Smith /* find a function that matches */ 3305fd6b620SMike Smith for (i = 0; functions[i].cmd != NULL; i++) 3315fd6b620SMike Smith if (!strcmp(what, functions[i].cmd)) { 3325fd6b620SMike Smith fprintf(stderr, "%s\n", functions[i].desc); 3335fd6b620SMike Smith return; 3345fd6b620SMike Smith } 3355fd6b620SMike Smith fprintf(stderr, "Unknown command '%s'\n", what); 3365fd6b620SMike Smith } 3375fd6b620SMike Smith 3385fd6b620SMike Smith /* print general help */ 3395fd6b620SMike Smith fprintf(stderr, "Valid commands are :\n"); 3405fd6b620SMike Smith for (i = 0; functions[i].cmd != NULL; i++) 3415fd6b620SMike Smith fprintf(stderr, " %s\n", functions[i].cmd); 3425fd6b620SMike Smith fprintf(stderr, "Use help <command> for command-specific help\n"); 34353f17f08SMike Smith } 344