From dad1e3091f2d9a3fc03b9ca83c2990e23b4ea32c Mon Sep 17 00:00:00 2001 From: Peter Stuge Date: Sat, 22 Nov 2008 17:13:36 +0000 Subject: msrtool: Release Candidate 1 msrtool can decode MSRs and print the value of every field in human readable form. It can also be used to save a set of MSRs to a file, and at a later time compare the saved values with current values in hardware. Signed-off-by: Peter Stuge Acked-by: Stefan Reinauer git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3766 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- util/msrtool/msrtool.c | 399 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 util/msrtool/msrtool.c (limited to 'util/msrtool/msrtool.c') diff --git a/util/msrtool/msrtool.c b/util/msrtool/msrtool.c new file mode 100644 index 0000000000..6f0b3a0109 --- /dev/null +++ b/util/msrtool/msrtool.c @@ -0,0 +1,399 @@ +/* + * This file is part of msrtool. + * + * Copyright (c) 2008 Peter Stuge + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msrtool.h" + +#define DEFAULT_CPU 0 +static uint8_t cpu = DEFAULT_CPU; + +uint8_t targets_found = 0; +const struct targetdef **targets = NULL; +const struct sysdef *sys = NULL; +uint8_t reserved = 0, verbose = 0, quiet = 0; + +static struct targetdef alltargets[] = { + { "geodelx", "AMD Geode(tm) LX", geodelx_probe, geodelx_msrs }, + { "cs5536", "AMD Geode(tm) CS5536", cs5536_probe, cs5536_msrs }, + { TARGET_EOT } +}; + +static struct sysdef allsystems[] = { + { "linux", "Linux with /dev/cpu/*/msr", linux_probe, linux_open, linux_close, linux_rdmsr }, + { SYSTEM_EOT } +}; + +static void syntax(char *argv[]) { + printf("syntax: %s [-hvqrkl] [-c cpu] [-m system] [-t target ...]\n", argv[0]); + printf("\t [-i addr=hi[:]lo] | [-s file] | [-d [:]file] | addr...\n"); + printf(" -h\t show this help text\n"); + printf(" -v\t be verbose\n"); + printf(" -q\t be quiet (overrides -v)\n"); + printf(" -r\t include [Reserved] values\n"); + printf(" -k\t list all known systems and targets\n"); + printf(" -l\t list MSRs and bit fields for current target(s) (-kl for ALL targets!)\n"); + printf(" -c\t access MSRs on the specified CPU, default=%d\n", DEFAULT_CPU); + printf(" -m\t force a system, e.g: -m linux\n"); + printf(" -t\t force a target, can be used multiple times, e.g: -t geodelx -t cs5536\n"); + printf(" -i\t immediate mode\n"); + printf("\t decode hex addr=hi:lo for the target without reading hw value\n"); + printf("\t e.g: -i 4c00000f=f2f100ff56960004\n"); + printf(" -s\t stream mode\n"); + printf("\t read one MSR address per line and append current hw value to the line\n"); + printf("\t use the filename - for stdin/stdout\n"); + printf("\t using -l -s ignores input and will output all MSRs with values\n"); + printf(" -d\t diff mode\n"); + printf("\t read one address and value per line and compare with current hw value,\n"); + printf("\t printing differences to stdout. use the filename - to read from stdin\n"); + printf("\t use :file or :- to reverse diff, normally hw values are considered new\n"); + printf(" addr.. direct mode, read and decode values for the given MSR address(es)\n"); +} + +static void *add_target(const struct targetdef *t) { + void *tmp; + tmp = realloc(targets, (targets_found + 2) * sizeof(struct targetdef *)); + if (NULL == tmp) { + perror("realloc"); + return tmp; + } + targets = tmp; + targets[targets_found++] = t; + targets[targets_found] = NULL; + return targets; +} + +int do_stream(const char *streamfn, uint8_t ignoreinput) { + char tmpfn[20], line[256]; + uint8_t tn; + size_t start, len; + int ret = 1; + int fdout = -1; + FILE *fin = NULL, *fout = NULL; + uint32_t addr, linenum; + struct msr m = MSR1(0); + + if (0 == strcmp(streamfn, "-")) { + fin = stdin; + fout = stdout; + } else { + if (!ignoreinput) { + if (NULL == (fin = fopen(streamfn, "r"))) { + perror("fopen()"); + return 1; + } + if (snprintf(tmpfn, sizeof(tmpfn), "msrtoolXXXXXX") >= sizeof(tmpfn)) { + perror("snprintf"); + return 1; + } + if (-1 == (fdout = mkstemp(tmpfn))) { + perror("mkstemp"); + return 1; + } + if (NULL == (fout = fdopen(fdout, "w"))) { + perror("fdopen"); + return 1; + } + } else { + if (NULL == (fout = fopen(streamfn, "w"))) { + perror("fopen"); + return 1; + } + } + } + + if (!sys->open(cpu, SYS_RDONLY)) + goto done; + if (ignoreinput) { + for (tn = 0; tn < targets_found; tn++) + if (dumpmsrdefsvals(fout, targets[tn], cpu)) { + ret = 1; + break; + } + } else { + for (linenum = 1; NULL != fgets(line, sizeof(line), fin); ++linenum) { + start = (0 == strncmp("0x", line, 2)) ? 2 : 0; + if (1 == sscanf(line + start, "%8x", &addr)) { + if (!sys->rdmsr(cpu, addr, &m)) + goto done; + fprintf(fout, "0x%08x 0x%08x%08x\n", addr, m.hi, m.lo); + continue; + } + while (1) { + fprintf(fout, "%s", line); + len = strlen(line); + if (NULL != strchr("\r\n", line[len - 1])) + break; + if (NULL == fgets(line, sizeof(line), fin)) + goto read_done; + } + } +read_done: + if (!feof(fin)) { + fprintf(stderr, "%s:%d: fgets: %s\n", streamfn, linenum, strerror(errno)); + goto done; + } + } + ret = 0; +done: + sys->close(cpu); + if (strcmp(streamfn, "-")) { + if (ret) + unlink(tmpfn); + else if (!ignoreinput) + rename(tmpfn, streamfn); + } + if (!ignoreinput) + fclose(fin); + fclose(fout); + return ret; +} + +int do_diff(const char *difffn) { + char tmpfn[20], line[512]; + size_t start, len; + int ret = 1, tmp; + FILE *fin = NULL, *fout = stdout; + uint8_t rev = 0; + uint32_t addr, linenum; + struct msr mf = MSR1(0), mhw = MSR1(0); + + if (':' == difffn[0]) { + rev = 1; + ++difffn; + } + if (0 == strcmp(difffn, "-")) + fin = stdin; + else if (NULL == (fin = fopen(difffn, "r"))) { + perror("fopen()"); + return 1; + } + + if (!sys->open(cpu, SYS_RDONLY)) + goto done; + for (linenum = 1; NULL != fgets(line, sizeof(line), fin); ++linenum) { + start = (0 == strncmp("0x", line, 2)) ? 2 : 0; + if (sscanf(line + start, "%8x %n%*x", &addr, &tmp) >= 1) { + start += tmp; + for (len = strlen(line) - 1; NULL != strchr("\r\n", line[len]); --len) + line[len] = 0; + if (!str2msr(line + start, &mf)) { + fprintf(stderr, "%s:%d: invalid MSR value '%s'\n", difffn, linenum, line + start); + continue; + } + if (!sys->rdmsr(cpu, addr, &mhw)) + goto done; + if (diff_msr(fout, addr, rev ? mhw : mf, rev ? mf : mhw)) + fprintf(fout, "\n"); + } + } + if (!feof(fin)) + fprintf(stderr, "%s:%d: fgets: %s\n", difffn, linenum, strerror(errno)); + else + ret = 0; +done: + sys->close(cpu); + if (strcmp(difffn, "-")) { + if (ret) + unlink(tmpfn); + else + rename(tmpfn, difffn); + fclose(fin); + fclose(fout); + } + return ret; +} + +int main(int argc, char *argv[]) { + char c; + int ret = 1; + const struct sysdef *s; + const struct targetdef *t; + uint8_t tn, listmsrs = 0, listknown = 0, input = 0; + uint32_t addr = 0; + const char *streamfn = NULL, *difffn = NULL; + struct msr msrval = MSR2(-1, -1); + while ((c = getopt(argc, argv, "hqvrklc:m:t:a:i:s:d:")) != -1) + switch (c) { + case 'h': + syntax(argv); + return 0; + case 'q': + quiet = 1; + break; + case 'v': + ++verbose; + break; + case 'r': + reserved = 1; + break; + case 'k': + listknown = 1; + break; + case 'l': + listmsrs = 1; + break; + case 'c': + cpu = atoi(optarg); + break; + case 'm': + for (s = allsystems; !SYSTEM_ISEOT(*s); s++) + if (!strcmp(s->name, optarg)) { + sys = s; + break; + } + break; + case 't': + for (t = alltargets; !TARGET_ISEOT(*t); t++) + if (!strcmp(t->name, optarg)) { + add_target(t); + break; + } + break; + case 'i': + input = 1; + addr = strtoul(optarg, NULL, 16); + optarg = strchr(optarg, '='); + if (NULL == optarg) { + fprintf(stderr, "missing value in -i argument!\n"); + break; + } + if (!str2msr(++optarg, &msrval)) + fprintf(stderr, "invalid value in -i argument!\n"); + break; + case 's': + streamfn = optarg; + break; + case 'd': + difffn = optarg; + break; + default: + break; + } + + printf_quiet("msrtool %s\n", VERSION); + + if (!sys && !input && !listknown) + for (sys = allsystems; !SYSTEM_ISEOT(*sys); sys++) { + printf_verbose("Probing for system %s: %s\n", sys->name, sys->prettyname); + if (!sys->probe(sys)) + continue; + printf_quiet("Detected system %s: %s\n", sys->name, sys->prettyname); + break; + } + + if (targets) + for (tn = 0; tn < targets_found; tn++) + printf_quiet("Forced target %s: %s\n", targets[tn]->name, targets[tn]->prettyname); + else + for (t = alltargets; !TARGET_ISEOT(*t); t++) { + printf_verbose("Probing for target %s: %s\n", t->name, t->prettyname); + if (!t->probe(t)) + continue; + printf_quiet("Detected target %s: %s\n", t->name, t->prettyname); + add_target(t); + } + + printf_quiet("\n"); + fflush(stdout); + + if (listknown) { + printf("Known systems:\n"); + for (s = allsystems; s->name; s++) + printf("%s: %s\n", s->name, s->prettyname); + printf("\nKnown targets:\n"); + for (t = alltargets; t->name; t++) { + if (listmsrs && alltargets != t) + printf("\n"); + printf("%s: %s\n", t->name, t->prettyname); + if (listmsrs) + dumpmsrdefs(t); + } + printf("\n"); + return 0; + } + + if (sys && !sys->name) { + fprintf(stderr, "Unable to detect the current operating system!\n"); + fprintf(stderr, "Please send a report or patch to coreboot@coreboot.org. Thanks for your help!\n"); + fprintf(stderr, "\n"); + } + + if (!targets_found || !targets) { + fprintf(stderr, "Unable to detect a known target; can not decode any MSRs! (Use -t to force)\n"); + fprintf(stderr, "Please send a report or patch to coreboot@coreboot.org. Thanks for your help!\n"); + fprintf(stderr, "\n"); + return 1; + } + + if (input) { + decodemsr(cpu, addr, msrval); + return 0; + } + + if (sys && !sys->name) + return 1; + + if (listmsrs) { + if (streamfn) + return do_stream(streamfn, 1); + for (tn = 0; tn < targets_found; tn++) { + if (tn) + printf("\n"); + dumpmsrdefs(targets[tn]); + } + printf("\n"); + return 0; + } + + if (streamfn) + return do_stream(streamfn, 0); + + if (!sys->open(cpu, SYS_RDONLY)) + return 1; + + if (difffn) { + ret = do_diff(difffn); + goto done; + } + + if (optind == argc) { + syntax(argv); + printf("\nNo mode or address(es) specified!\n"); + goto done; + } + + for (; optind < argc; optind++) { + addr = strtoul(argv[optind], NULL, 16); + if (!sys->rdmsr(cpu, addr, &msrval)) + break; + decodemsr(cpu, addr, msrval); + } + ret = 0; +done: + sys->close(cpu); + return ret; +} -- cgit v1.2.3