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