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