From adf731f0abaa675658ccf1c99ca1559e84334ca9 Mon Sep 17 00:00:00 2001 From: msmith Date: Wed, 7 Apr 1999 04:11:14 +0000 Subject: [PATCH] Commandline tool for manipulating memory range attributes. --- usr.sbin/memcontrol/Makefile | 4 + usr.sbin/memcontrol/memcontrol.c | 325 +++++++++++++++++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 usr.sbin/memcontrol/Makefile create mode 100644 usr.sbin/memcontrol/memcontrol.c diff --git a/usr.sbin/memcontrol/Makefile b/usr.sbin/memcontrol/Makefile new file mode 100644 index 000000000000..3d8ffd7cbb66 --- /dev/null +++ b/usr.sbin/memcontrol/Makefile @@ -0,0 +1,4 @@ +PROG= memcontrol +NOMAN= yes + +.include diff --git a/usr.sbin/memcontrol/memcontrol.c b/usr.sbin/memcontrol/memcontrol.c new file mode 100644 index 000000000000..d52e8afb840a --- /dev/null +++ b/usr.sbin/memcontrol/memcontrol.c @@ -0,0 +1,325 @@ +/*- + * Copyright (c) 1999 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct +{ + char *name; + int val; + int kind; +#define MDF_SETTABLE (1<<0) +} attrnames[] = { + {"uncacheable", MDF_UNCACHEABLE, MDF_SETTABLE}, + {"write-combine", MDF_WRITECOMBINE, MDF_SETTABLE}, + {"write-through", MDF_WRITETHROUGH, MDF_SETTABLE}, + {"write-back", MDF_WRITEBACK, MDF_SETTABLE}, + {"write-protect", MDF_WRITEPROTECT, MDF_SETTABLE}, + {"fixed-base", MDF_FIXBASE, 0}, + {"fixed-length", MDF_FIXLEN, 0}, + {"set-by-firmware", MDF_FIRMWARE, 0}, + {"active", MDF_ACTIVE, MDF_SETTABLE}, + {"bogus", MDF_BOGUS, 0}, + {NULL, 0, 0} +}; + +static void listfunc(int memfd, int argc, char *argv[]); +static void setfunc(int memfd, int argc, char *argv[]); +static void clearfunc(int memfd, int argc, char *argv[]); +static void helpfunc(int memfd, int argc, char *argv[]); +static void help(char *what); + +struct +{ + char *cmd; + char *desc; + void (*func)(int memfd, int argc, char *argv[]); +} functions[] = { + {"list", + "List current memory range attributes\n" + " list [-a]\n" + " -a list all range slots, even those that are inactive", + listfunc}, + {"set", + "Set memory range attributes\n" + " set -b -l -o \n" + " memory range base address\n" + " length of memory range in bytes, power of 2\n" + " text identifier for this setting (7 char max)\n" + " attribute(s) to be applied to this range:\n" + " uncacheable\n" + " write-combine\n" + " write-through\n" + " write-back\n" + " write-protect", + setfunc}, + {"clear", + "Clear memory range attributes\n" + " clear -o \n" + " all ranges with this owner will be cleared\n" + " clear -b -l \n" + " memory range base address\n" + " length of memory range in bytes, power of 2\n" + " Base and length must exactly match an existing range", + clearfunc}, + {NULL, NULL, helpfunc} +}; + +int +main(int argc, char *argv[]) +{ + int i, memfd; + + if (argc < 2) { + help(NULL); + } else { + if ((memfd = open("/dev/mem", O_RDONLY)) == -1) + err(1, "can't open /dev/mem"); + + for (i = 0; functions[i].cmd != NULL; i++) + if (!strcmp(argv[1], functions[i].cmd)) + break; + functions[i].func(memfd, argc - 1, argv + 1); + close(memfd); + } + return(0); +} + +static struct mem_range_desc * +mrgetall(int memfd, int *nmr) +{ + struct mem_range_desc *mrd; + struct mem_range_op mro; + + mro.mo_arg[0] = 0; + if (ioctl(memfd, MEMRANGE_GET, &mro)) + err(1, "can't size range descriptor array"); + + *nmr = mro.mo_arg[0]; + mrd = malloc(*nmr * sizeof(struct mem_range_desc)); + if (mrd == NULL) + errx(1, "can't allocate %d bytes for %d range descriptors", + *nmr * sizeof(struct mem_range_desc), *nmr); + + mro.mo_arg[0] = *nmr; + mro.mo_desc = mrd; + if (ioctl(memfd, MEMRANGE_GET, &mro)) + err(1, "can't fetch range descriptor array"); + + return(mrd); +} + + +static void +listfunc(int memfd, int argc, char *argv[]) +{ + struct mem_range_desc *mrd; + int nd, i, j; + int error; + int ch; + int showall = 0; + char *owner; + + owner = NULL; + while ((ch = getopt(argc, argv, "ao:")) != -1) + switch(ch) { + case 'a': + showall = 1; + break; + case 'o': + owner = strdup(optarg); + break; + case '?': + default: + help("list"); + } + + mrd = mrgetall(memfd, &nd); + + for (i = 0; i < nd; i++) { + if (!showall && !(mrd[i].mr_flags & MDF_ACTIVE)) + continue; + if (owner && strcmp(mrd[i].mr_owner, owner)) + continue; + printf("%qx/%qx %.8s ", mrd[i].mr_base, mrd[i].mr_len, + mrd[i].mr_owner[0] ? mrd[i].mr_owner : "-"); + for (j = 0; attrnames[j].name != NULL; j++) + if (mrd[i].mr_flags & attrnames[j].val) + printf("%s ", attrnames[j].name); + printf("\n"); + } + free(mrd); + if (owner) + free(owner); +} + +static void +setfunc(int memfd, int argc, char *argv[]) +{ + struct mem_range_desc mrd; + struct mem_range_op mro; + int i; + int ch; + char *ep; + + mrd.mr_base = 0; + mrd.mr_len = 0; + mrd.mr_flags = 0; + strcpy(mrd.mr_owner, "user"); + while ((ch = getopt(argc, argv, "b:l:o:")) != -1) + switch(ch) { + case 'b': + mrd.mr_base = strtouq(optarg, &ep, 0); + if ((ep == optarg) || (*ep != 0)) + help("set"); + break; + case 'l': + mrd.mr_len = strtouq(optarg, &ep, 0); + if ((ep == optarg) || (*ep != 0)) + help("set"); + break; + case 'o': + if ((*optarg == 0) || (strlen(optarg) > 7)) + help("set"); + strcpy(mrd.mr_owner, optarg); + break; + + case '?': + default: + help("set"); + } + + if (mrd.mr_len == 0) + help("set"); + + argc -= optind; + argv += optind; + + while(argc--) { + for (i = 0; attrnames[i].name != NULL; i++) { + if (!strcmp(attrnames[i].name, argv[0])) { + if (!attrnames[i].kind & MDF_SETTABLE) + help("flags"); + mrd.mr_flags |= attrnames[i].val; + break; + } + } + if (attrnames[i].name == NULL) + help("flags"); + argv++; + } + + mro.mo_desc = &mrd; + mro.mo_arg[0] = 0; + if (ioctl(memfd, MEMRANGE_SET, &mro)) + err(1, "can't set range"); +} + +static void +clearfunc(int memfd, int argc, char *argv[]) +{ + struct mem_range_desc mrd, *mrdp; + struct mem_range_op mro; + int i, nd; + int ch; + char *ep, *owner; + + mrd.mr_base = 0; + mrd.mr_len = 0; + owner = NULL; + while ((ch = getopt(argc, argv, "b:l:o:")) != -1) + switch(ch) { + case 'b': + mrd.mr_base = strtouq(optarg, &ep, 0); + if ((ep == optarg) || (*ep != 0)) + help("clear"); + break; + case 'l': + mrd.mr_len = strtouq(optarg, &ep, 0); + if ((ep == optarg) || (*ep != 0)) + help("clear"); + break; + case 'o': + if ((*optarg == 0) || (strlen(optarg) > 7)) + help("clear"); + owner = strdup(optarg); + break; + + case '?': + default: + help("clear"); + } + + if (owner != NULL) { + /* clear-by-owner */ + if ((mrd.mr_base != 0) || (mrd.mr_len != 0)) + help("clear"); + + mrdp = mrgetall(memfd, &nd); + mro.mo_arg[0] = MEMRANGE_SET_REMOVE; + for (i = 0; i < nd; i++) { + if (!strcmp(owner, mrdp[i].mr_owner) && + (mrdp[i].mr_flags & MDF_ACTIVE) && + !(mrdp[i].mr_flags & MDF_FIXACTIVE)) { + + mro.mo_desc = mrdp + i; + if (ioctl(memfd, MEMRANGE_SET, &mro)) + warn("couldn't clear range owned by '%s'", owner); + } + } + } else if ((mrd.mr_base != 0) && (mrd.mr_len != 0)) { + /* clear-by-base/len */ + mro.mo_arg[0] = MEMRANGE_SET_REMOVE; + mro.mo_desc = &mrd; + if (ioctl(memfd, MEMRANGE_SET, &mro)) + err(1, "couldn't clear range"); + } else { + help("clear"); + } +} + +static void +helpfunc(int memfd, int argc, char *argv[]) +{ + help(NULL); +} + +static void +help(char *what) +{ + errx(1, "help!"); +}