diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 1999-11-20 11:22:55 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 1999-11-20 11:22:55 +0000 |
commit | 5e1c1cf347b116df027434ae4540df720620ebe1 (patch) | |
tree | 332a1f9d1cecc59e02adcfbe14a06cabc1d50e02 /usr.sbin/memconfig | |
parent | 941375531642d071733eb1e0448b075182c301fa (diff) |
add memconfig, an utility to manipulate MTRRs, from FreeBSD
Diffstat (limited to 'usr.sbin/memconfig')
-rw-r--r-- | usr.sbin/memconfig/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/memconfig/memconfig.8 | 117 | ||||
-rw-r--r-- | usr.sbin/memconfig/memconfig.c | 359 |
3 files changed, 482 insertions, 0 deletions
diff --git a/usr.sbin/memconfig/Makefile b/usr.sbin/memconfig/Makefile new file mode 100644 index 00000000000..0e5e775a6a3 --- /dev/null +++ b/usr.sbin/memconfig/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD: src/usr.sbin/memcontrol/Makefile,v 1.2 1999/09/29 21:43:31 chris Exp $ + +PROG= memconfig +MAN= memconfig.8 + +.include <bsd.prog.mk> diff --git a/usr.sbin/memconfig/memconfig.8 b/usr.sbin/memconfig/memconfig.8 new file mode 100644 index 00000000000..2b991cba6db --- /dev/null +++ b/usr.sbin/memconfig/memconfig.8 @@ -0,0 +1,117 @@ +.\" $OpenBSD: memconfig.8,v 1.1 1999/11/20 11:22:54 matthieu Exp $ +.\" Copyright (c) 1999 Chris Costello +.\" 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. +.\" +.\" $FreeBSD: src/usr.sbin/memcontrol/memcontrol.8,v 1.2 1999/10/09 16:37:37 chris Exp $ +.\" +.Dd November 14, 1999 +.Dt MEMCONFIG 8 +.Os +.Sh NAME +.Nm memconfig +.Nd "Control system cache behaviour with respect to memory" +.Sh SYNOPSIS +.Nm +.Ar list +.Op Fl a +.Pp +.Nm +.Ar set +.Fl b Ar base +.Fl l Ar length +.Fl o Ar owner +.Ar attribute +.Pp +.Nm +.Ar clear +.Fl o Ar owner +.Pp +.Nm +.Ar clear +.Fl b Ar base +.Fl l Ar length +.Sh DESCRIPTION +A number of supported system architectures allow the behaviour of the CPU +cache to be programmed to behave differently depending on the region being +written. +.Pp +.Nm Memconfig +provides an interface to this facility, allowing CPU cache behavior to +be altered for ranges of system physical memory. +.Pp +These ranges are typically power-of-2 aligned and sized, however the specific +rules governing their layout vary between architectures. The +.Nm memconfig +program does not attempt to enforce these rules, however the system will +reject any attempt to set an illegal combination. +.Bl -tag -width clear +.It Ar list +List range slots. +.Bl -tag -width xxxxxx +.It Op Fl a +List all range slots, even those that are inactive +.El +.It Ar set +Set memory range attributes. +.Bl -tag -width xxxxxx +.It Fl b Ar base +Memory range base address +.It Fl l Ar length +Length of memory range in bytes, power of 2 +.It Fl o Ar owner +Text identifier for this setting (7 char max) +.It Ar attribute +Attributes applied to this range; one of +.Ar uncacheable , +.Ar write-combine , +.Ar write-through , +.Ar write-back , +.Ar write-protect +.El +.It Ar clear +Clear memory range attributes. Ranges may be cleared by owner or by +base/length combination. +.Pp +To clear based on ownership: +.Bl -tag -width xxxxxx +.It Fl o Ar owner +All ranges with this owner will be cleared +.El +.Pp +To clear based on the base/length combination: +.Bl -tag -width xxxxxx +.It Fl b Ar base +Memory range base address +.It Fl l Ar length +Length of memory range in bytes, power of 2 +.El +.Pp +Base and length must exactly match an existing range. +.El +.Sh SEE ALSO +.Xr mtrr 4 +.Sh HISTORY +.Nm memconfig +was originally introduced in FreeBSD 3.3 as +.Xr memcontrol 8 . diff --git a/usr.sbin/memconfig/memconfig.c b/usr.sbin/memconfig/memconfig.c new file mode 100644 index 00000000000..bad4d096f25 --- /dev/null +++ b/usr.sbin/memconfig/memconfig.c @@ -0,0 +1,359 @@ +/* $OpenBSD: memconfig.c,v 1.1 1999/11/20 11:22:54 matthieu Exp $ */ +/*- + * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> + * 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. + * + * $FreeBSD: src/usr.sbin/memcontrol/memcontrol.c,v 1.3 1999/08/28 01:17:00 peter Exp $ + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/memrange.h> + +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +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 __P((int, int, char *[])); +static void setfunc __P((int, int, char *[])); +static void clearfunc __P((int, int, char *[])); +static void helpfunc __P((int, int, char *[])); +static void help __P((char *)); + +struct +{ + char *cmd; + char *desc; + void (*func) __P((int, int, char *[])); +} 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 <base> -l <length> -o <owner> <attribute>\n" + " <base> memory range base address\n" + " <length> length of memory range in bytes, power of 2\n" + " <owner> text identifier for this setting (7 char max)\n" + " <attribute> 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 <owner>\n" + " <owner> all ranges with this owner will be cleared\n" + " clear -b <base> -l <length>\n" + " <base> memory range base address\n" + " <length> 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(argc, argv) + 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(memfd, nmr) + 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(memfd, argc, argv) + 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(memfd, argc, argv) + 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(memfd, argc, argv) + 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(memfd, argc, argv) + int memfd; + int argc; + char *argv[]; +{ + help(argv[1]); +} + +static void +help(what) + char *what; +{ + int i; + + if (what != NULL) { + /* find a function that matches */ + for (i = 0; functions[i].cmd != NULL; i++) + if (!strcmp(what, functions[i].cmd)) { + fprintf(stderr, "%s\n", functions[i].desc); + return; + } + fprintf(stderr, "Unknown command '%s'\n", what); + } + + /* print general help */ + fprintf(stderr, "Valid commands are :\n"); + for (i = 0; functions[i].cmd != NULL; i++) + fprintf(stderr, " %s\n", functions[i].cmd); + fprintf(stderr, "Use help <command> for command-specific help\n"); +} |