145410Smsmith/*- 245410Smsmith * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> 345410Smsmith * All rights reserved. 445410Smsmith * 545410Smsmith * Redistribution and use in source and binary forms, with or without 645410Smsmith * modification, are permitted provided that the following conditions 745410Smsmith * are met: 845410Smsmith * 1. Redistributions of source code must retain the above copyright 945410Smsmith * notice, this list of conditions and the following disclaimer. 1045410Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1145410Smsmith * notice, this list of conditions and the following disclaimer in the 1245410Smsmith * documentation and/or other materials provided with the distribution. 1345410Smsmith * 1445410Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1545410Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1645410Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1745410Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1845410Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1945410Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2045410Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2145410Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2245410Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2345410Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2445410Smsmith * SUCH DAMAGE. 2545410Smsmith * 2650479Speter * $FreeBSD$ 2745410Smsmith */ 2845410Smsmith 2945410Smsmith#include <sys/types.h> 3045410Smsmith#include <sys/ioctl.h> 3145410Smsmith#include <sys/memrange.h> 3245410Smsmith 3345410Smsmith#include <err.h> 3445410Smsmith#include <fcntl.h> 35139854Sdelphij#include <inttypes.h> 3669793Sobrien#include <paths.h> 3745410Smsmith#include <stdio.h> 3845410Smsmith#include <stdlib.h> 3945410Smsmith#include <string.h> 4045410Smsmith#include <unistd.h> 4145410Smsmith 42227254Sedstatic struct { 43139854Sdelphij const char *name; 4445410Smsmith int val; 4545410Smsmith int kind; 4645410Smsmith#define MDF_SETTABLE (1<<0) 4745410Smsmith} attrnames[] = { 4845410Smsmith {"uncacheable", MDF_UNCACHEABLE, MDF_SETTABLE}, 4945410Smsmith {"write-combine", MDF_WRITECOMBINE, MDF_SETTABLE}, 5045410Smsmith {"write-through", MDF_WRITETHROUGH, MDF_SETTABLE}, 5145410Smsmith {"write-back", MDF_WRITEBACK, MDF_SETTABLE}, 5245410Smsmith {"write-protect", MDF_WRITEPROTECT, MDF_SETTABLE}, 53103346Sdwmalone {"force", MDF_FORCE, MDF_SETTABLE}, 5494684Sdwmalone {"unknown", MDF_UNKNOWN, 0}, 5545410Smsmith {"fixed-base", MDF_FIXBASE, 0}, 5645410Smsmith {"fixed-length", MDF_FIXLEN, 0}, 5745410Smsmith {"set-by-firmware", MDF_FIRMWARE, 0}, 5845410Smsmith {"active", MDF_ACTIVE, MDF_SETTABLE}, 5945410Smsmith {"bogus", MDF_BOGUS, 0}, 6045410Smsmith {NULL, 0, 0} 6145410Smsmith}; 6245410Smsmith 6345410Smsmithstatic void listfunc(int memfd, int argc, char *argv[]); 6445410Smsmithstatic void setfunc(int memfd, int argc, char *argv[]); 6545410Smsmithstatic void clearfunc(int memfd, int argc, char *argv[]); 6645410Smsmithstatic void helpfunc(int memfd, int argc, char *argv[]); 67139854Sdelphijstatic void help(const char *what); 6845410Smsmith 69227254Sedstatic struct { 70139854Sdelphij const char *cmd; 71139854Sdelphij const char *desc; 7245410Smsmith void (*func)(int memfd, int argc, char *argv[]); 7345410Smsmith} functions[] = { 7445410Smsmith {"list", 7545410Smsmith "List current memory range attributes\n" 7645410Smsmith " list [-a]\n" 7745410Smsmith " -a list all range slots, even those that are inactive", 7845410Smsmith listfunc}, 7945410Smsmith {"set", 8045410Smsmith "Set memory range attributes\n" 8145410Smsmith " set -b <base> -l <length> -o <owner> <attribute>\n" 8245410Smsmith " <base> memory range base address\n" 8345410Smsmith " <length> length of memory range in bytes, power of 2\n" 8445410Smsmith " <owner> text identifier for this setting (7 char max)\n" 8545410Smsmith " <attribute> attribute(s) to be applied to this range:\n" 8645410Smsmith " uncacheable\n" 8745410Smsmith " write-combine\n" 8845410Smsmith " write-through\n" 8945410Smsmith " write-back\n" 9045410Smsmith " write-protect", 9145410Smsmith setfunc}, 9245410Smsmith {"clear", 9345410Smsmith "Clear memory range attributes\n" 9445410Smsmith " clear -o <owner>\n" 9545410Smsmith " <owner> all ranges with this owner will be cleared\n" 9645410Smsmith " clear -b <base> -l <length>\n" 9745410Smsmith " <base> memory range base address\n" 9845410Smsmith " <length> length of memory range in bytes, power of 2\n" 9945410Smsmith " Base and length must exactly match an existing range", 10045410Smsmith clearfunc}, 10145410Smsmith {NULL, NULL, helpfunc} 10245410Smsmith}; 10345410Smsmith 10445410Smsmithint 10545410Smsmithmain(int argc, char *argv[]) 10645410Smsmith{ 10745410Smsmith int i, memfd; 10845410Smsmith 10945410Smsmith if (argc < 2) { 11045410Smsmith help(NULL); 11145410Smsmith } else { 11269793Sobrien if ((memfd = open(_PATH_MEM, O_RDONLY)) == -1) 11369793Sobrien err(1, "can't open %s", _PATH_MEM); 11445410Smsmith 11545410Smsmith for (i = 0; functions[i].cmd != NULL; i++) 11645410Smsmith if (!strcmp(argv[1], functions[i].cmd)) 11745410Smsmith break; 11845410Smsmith functions[i].func(memfd, argc - 1, argv + 1); 11945410Smsmith close(memfd); 12045410Smsmith } 12145410Smsmith return(0); 12245410Smsmith} 12345410Smsmith 12445410Smsmithstatic struct mem_range_desc * 12545410Smsmithmrgetall(int memfd, int *nmr) 12645410Smsmith{ 12745410Smsmith struct mem_range_desc *mrd; 12845410Smsmith struct mem_range_op mro; 12945410Smsmith 13045410Smsmith mro.mo_arg[0] = 0; 13145410Smsmith if (ioctl(memfd, MEMRANGE_GET, &mro)) 13245410Smsmith err(1, "can't size range descriptor array"); 13345410Smsmith 13445410Smsmith *nmr = mro.mo_arg[0]; 13545410Smsmith mrd = malloc(*nmr * sizeof(struct mem_range_desc)); 13645410Smsmith if (mrd == NULL) 137139854Sdelphij errx(1, "can't allocate %zd bytes for %d range descriptors", 13845410Smsmith *nmr * sizeof(struct mem_range_desc), *nmr); 13945410Smsmith 14045410Smsmith mro.mo_arg[0] = *nmr; 14145410Smsmith mro.mo_desc = mrd; 14245410Smsmith if (ioctl(memfd, MEMRANGE_GET, &mro)) 14345410Smsmith err(1, "can't fetch range descriptor array"); 14445410Smsmith 14545410Smsmith return(mrd); 14645410Smsmith} 14745410Smsmith 14845410Smsmith 14945410Smsmithstatic void 15045410Smsmithlistfunc(int memfd, int argc, char *argv[]) 15145410Smsmith{ 15245410Smsmith struct mem_range_desc *mrd; 15345410Smsmith int nd, i, j; 15445410Smsmith int ch; 15545410Smsmith int showall = 0; 15645410Smsmith char *owner; 15745410Smsmith 15845410Smsmith owner = NULL; 15945410Smsmith while ((ch = getopt(argc, argv, "ao:")) != -1) 16045410Smsmith switch(ch) { 16145410Smsmith case 'a': 16245410Smsmith showall = 1; 16345410Smsmith break; 16445410Smsmith case 'o': 16545410Smsmith owner = strdup(optarg); 16645410Smsmith break; 16745410Smsmith case '?': 16845410Smsmith default: 16945410Smsmith help("list"); 17045410Smsmith } 17145410Smsmith 17245410Smsmith mrd = mrgetall(memfd, &nd); 17345410Smsmith 17445410Smsmith for (i = 0; i < nd; i++) { 17545410Smsmith if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE)) 17645410Smsmith continue; 17745410Smsmith if (owner && strcmp(mrd[i].mr_owner, owner)) 17845410Smsmith continue; 179144303Sanholt printf("0x%" PRIx64 "/0x%" PRIx64 " %.8s ", mrd[i].mr_base, mrd[i].mr_len, 18045410Smsmith mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-"); 18145410Smsmith for (j = 0; attrnames[j].name != NULL; j++) 18245410Smsmith if (mrd[i].mr_flags & attrnames[j].val) 18345410Smsmith printf("%s ", attrnames[j].name); 18445410Smsmith printf("\n"); 18545410Smsmith } 18645410Smsmith free(mrd); 18745410Smsmith if (owner) 18845410Smsmith free(owner); 18945410Smsmith} 19045410Smsmith 19145410Smsmithstatic void 19245410Smsmithsetfunc(int memfd, int argc, char *argv[]) 19345410Smsmith{ 19445410Smsmith struct mem_range_desc mrd; 19545410Smsmith struct mem_range_op mro; 19645410Smsmith int i; 19745410Smsmith int ch; 19845410Smsmith char *ep; 19945410Smsmith 20045410Smsmith mrd.mr_base = 0; 20145410Smsmith mrd.mr_len = 0; 20245410Smsmith mrd.mr_flags = 0; 20345410Smsmith strcpy(mrd.mr_owner, "user"); 20445410Smsmith while ((ch = getopt(argc, argv, "b:l:o:")) != -1) 20545410Smsmith switch(ch) { 20645410Smsmith case 'b': 20745410Smsmith mrd.mr_base = strtouq(optarg, &ep, 0); 20845410Smsmith if ((ep == optarg) || (*ep != 0)) 20945410Smsmith help("set"); 21045410Smsmith break; 21145410Smsmith case 'l': 21245410Smsmith mrd.mr_len = strtouq(optarg, &ep, 0); 21345410Smsmith if ((ep == optarg) || (*ep != 0)) 21445410Smsmith help("set"); 21545410Smsmith break; 21645410Smsmith case 'o': 21745410Smsmith if ((*optarg == 0) || (strlen(optarg) > 7)) 21845410Smsmith help("set"); 21945410Smsmith strcpy(mrd.mr_owner, optarg); 22045410Smsmith break; 22145410Smsmith 22245410Smsmith case '?': 22345410Smsmith default: 22445410Smsmith help("set"); 22545410Smsmith } 22645410Smsmith 22745410Smsmith if (mrd.mr_len == 0) 22845410Smsmith help("set"); 22945410Smsmith 23045410Smsmith argc -= optind; 23145410Smsmith argv += optind; 23245410Smsmith 23345410Smsmith while(argc--) { 23445410Smsmith for (i = 0; attrnames[i].name != NULL; i++) { 23545410Smsmith if (!strcmp(attrnames[i].name, argv[0])) { 236241829Seadler if (!(attrnames[i].kind & MDF_SETTABLE)) 23745410Smsmith help("flags"); 23845410Smsmith mrd.mr_flags |= attrnames[i].val; 23945410Smsmith break; 24045410Smsmith } 24145410Smsmith } 24245410Smsmith if (attrnames[i].name == NULL) 24345410Smsmith help("flags"); 24445410Smsmith argv++; 24545410Smsmith } 24645410Smsmith 24745410Smsmith mro.mo_desc = &mrd; 24845410Smsmith mro.mo_arg[0] = 0; 24945410Smsmith if (ioctl(memfd, MEMRANGE_SET, &mro)) 25045410Smsmith err(1, "can't set range"); 25145410Smsmith} 25245410Smsmith 25345410Smsmithstatic void 25445410Smsmithclearfunc(int memfd, int argc, char *argv[]) 25545410Smsmith{ 25645410Smsmith struct mem_range_desc mrd, *mrdp; 25745410Smsmith struct mem_range_op mro; 25845410Smsmith int i, nd; 25945410Smsmith int ch; 26045410Smsmith char *ep, *owner; 26145410Smsmith 26245410Smsmith mrd.mr_base = 0; 26345410Smsmith mrd.mr_len = 0; 26445410Smsmith owner = NULL; 26545410Smsmith while ((ch = getopt(argc, argv, "b:l:o:")) != -1) 26645410Smsmith switch(ch) { 26745410Smsmith case 'b': 26845410Smsmith mrd.mr_base = strtouq(optarg, &ep, 0); 26945410Smsmith if ((ep == optarg) || (*ep != 0)) 27045410Smsmith help("clear"); 27145410Smsmith break; 27245410Smsmith case 'l': 27345410Smsmith mrd.mr_len = strtouq(optarg, &ep, 0); 27445410Smsmith if ((ep == optarg) || (*ep != 0)) 27545410Smsmith help("clear"); 27645410Smsmith break; 27745410Smsmith case 'o': 27845410Smsmith if ((*optarg == 0) || (strlen(optarg) > 7)) 27945410Smsmith help("clear"); 28045410Smsmith owner = strdup(optarg); 28145410Smsmith break; 28245410Smsmith 28345410Smsmith case '?': 28445410Smsmith default: 28545410Smsmith help("clear"); 28645410Smsmith } 28745410Smsmith 28845410Smsmith if (owner != NULL) { 28945410Smsmith /* clear-by-owner */ 29045410Smsmith if ((mrd.mr_base != 0) || (mrd.mr_len != 0)) 29145410Smsmith help("clear"); 29245410Smsmith 29345410Smsmith mrdp = mrgetall(memfd, &nd); 29445410Smsmith mro.mo_arg[0] = MEMRANGE_SET_REMOVE; 29545410Smsmith for (i = 0; i < nd; i++) { 29645410Smsmith if (!strcmp(owner, mrdp[i].mr_owner) && 29745410Smsmith (mrdp[i].mr_flags & MDF_ACTIVE) && 29845410Smsmith !(mrdp[i].mr_flags & MDF_FIXACTIVE)) { 29945410Smsmith 30045410Smsmith mro.mo_desc = mrdp + i; 30145410Smsmith if (ioctl(memfd, MEMRANGE_SET, &mro)) 30245410Smsmith warn("couldn't clear range owned by '%s'", owner); 30345410Smsmith } 30445410Smsmith } 30558408Sgreen } else if (mrd.mr_len != 0) { 30645410Smsmith /* clear-by-base/len */ 30745410Smsmith mro.mo_arg[0] = MEMRANGE_SET_REMOVE; 30845410Smsmith mro.mo_desc = &mrd; 30945410Smsmith if (ioctl(memfd, MEMRANGE_SET, &mro)) 31045410Smsmith err(1, "couldn't clear range"); 31145410Smsmith } else { 31245410Smsmith help("clear"); 31345410Smsmith } 31445410Smsmith} 31545410Smsmith 31645410Smsmithstatic void 317139854Sdelphijhelpfunc(__unused int memfd, __unused int argc, char *argv[]) 31845410Smsmith{ 31948920Smsmith help(argv[1]); 32045410Smsmith} 32145410Smsmith 32245410Smsmithstatic void 323139854Sdelphijhelp(const char *what) 32445410Smsmith{ 32548920Smsmith int i; 32648920Smsmith 32748920Smsmith if (what != NULL) { 32848920Smsmith /* find a function that matches */ 32948920Smsmith for (i = 0; functions[i].cmd != NULL; i++) 33048920Smsmith if (!strcmp(what, functions[i].cmd)) { 33148920Smsmith fprintf(stderr, "%s\n", functions[i].desc); 33248920Smsmith return; 33348920Smsmith } 33448920Smsmith fprintf(stderr, "Unknown command '%s'\n", what); 33548920Smsmith } 33648920Smsmith 33748920Smsmith /* print general help */ 33848920Smsmith fprintf(stderr, "Valid commands are :\n"); 33948920Smsmith for (i = 0; functions[i].cmd != NULL; i++) 34048920Smsmith fprintf(stderr, " %s\n", functions[i].cmd); 34148920Smsmith fprintf(stderr, "Use help <command> for command-specific help\n"); 34245410Smsmith} 343