summaryrefslogtreecommitdiff
path: root/util/msrtool/msrutils.c
diff options
context:
space:
mode:
authorPeter Stuge <peter@stuge.se>2008-11-22 17:13:36 +0000
committerStefan Reinauer <stepan@openbios.org>2008-11-22 17:13:36 +0000
commitdad1e3091f2d9a3fc03b9ca83c2990e23b4ea32c (patch)
tree4ca71d53ba7405b720fa977614fd68a96bf3d3bd /util/msrtool/msrutils.c
parentd24fe7e80ede60847afaa2ae30692b072ea06eda (diff)
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 <peter@stuge.se> Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3766 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/msrtool/msrutils.c')
-rw-r--r--util/msrtool/msrutils.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/util/msrtool/msrutils.c b/util/msrtool/msrutils.c
new file mode 100644
index 0000000000..3c64242a87
--- /dev/null
+++ b/util/msrtool/msrutils.c
@@ -0,0 +1,299 @@
+/*
+ * This file is part of msrtool.
+ *
+ * Copyright (c) 2008 Peter Stuge <peter@stuge.se>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "msrtool.h"
+
+static void print_bitdef(FILE *f, const struct msrbits *mb, const char *tail) {
+ uint8_t endbit;
+ if (!reserved && !strcmp(mb->name, "RSVD"))
+ return;
+ if (1 == mb->size)
+ fprintf(f, "# %5d", mb->start);
+ else {
+ endbit = mb->start - mb->size + 1;
+ fprintf(f, "# %*d:%d", endbit < 10 ? 3 : 2, mb->start, endbit);
+ }
+ if (!strcmp(mb->name, "RSVD"))
+ fprintf(f, " [%s]", mb->desc);
+ else
+ fprintf(f, " %s %s", mb->name, mb->desc);
+ fprintf(f, "%s", tail);
+}
+
+static void print_bitval(FILE *f, const struct msrbits *mb, const struct msr val) {
+ uint8_t i;
+ struct msr tmp, mask = MSR1(1);
+ const struct msrbitvalues *mbv = mb->bitval;
+ while (mbv->text && !msr_eq(mbv->value, val))
+ mbv++;
+ switch (mb->present) {
+ case PRESENT_BIN:
+ mask = msr_shl(mask, mb->size - 1);
+ for (i = 0; i < mb->size; i++) {
+ memcpy(&tmp, &val, sizeof(val));
+ msr_and(&tmp, mask);
+ fprintf(f, "%d", (tmp.hi || tmp.lo) ? 1 : 0);
+ mask = msr_shr(mask, 1);
+ }
+ /* TODO */
+ break;
+ case PRESENT_DEC:
+ fprintf(f, "%d", val.lo);
+ break;
+ case PRESENT_OCT:
+ fprintf(f, "0%o", val.lo);
+ break;
+ case PRESENT_HEX:
+ hexprint(f, val, mb->size);
+ break;
+ case PRESENT_HEXDEC:
+ hexprint(f, val, mb->size);
+ fprintf(f, " %d", val.lo);
+ break;
+ }
+ if (mbv->text)
+ fprintf(f, ": %s", mbv->text);
+ fprintf(f, "\n");
+}
+
+void hexprint(FILE *f, const struct msr val, const uint8_t bits) {
+ if (bits <= 4)
+ fprintf(f, "0x%x", (uint8_t)(val.lo & 0x0f));
+ else if (bits <= 8)
+ fprintf(f, "0x%02x", (uint8_t)(val.lo & 0xff));
+ else if (bits <= 16)
+ fprintf(f, "0x%04x", (uint16_t)(val.lo & 0xffff));
+ else if (bits <= 32)
+ fprintf(f, "0x%08x", val.lo);
+ else
+ fprintf(f, "0x%08x%08x", val.hi, val.lo);
+}
+
+int msr_eq(const struct msr a, const struct msr b) {
+ return a.hi == b.hi && a.lo == b.lo;
+}
+
+struct msr msr_shl(const struct msr a, const uint8_t bits) {
+ struct msr ret;
+
+ ret.hi = bits < 32 ? a.hi << bits : 0;
+ ret.lo = bits < 32 ? a.lo << bits : 0;
+
+ if (bits < 32)
+ ret.hi |= bits ? a.lo >> (32 - bits) : 0;
+ else
+ ret.hi |= a.lo << (bits - 32);
+
+ return ret;
+}
+
+struct msr msr_shr(const struct msr a, const uint8_t bits) {
+ struct msr ret;
+
+ ret.hi = bits < 32 ? a.hi >> bits : 0;
+ ret.lo = bits < 32 ? a.lo >> bits : 0;
+
+ if (bits < 32)
+ ret.lo |= bits ? a.hi << (32 - bits) : 0;
+ else
+ ret.lo |= a.hi >> (bits - 32);
+
+ return ret;
+}
+
+void msr_and(struct msr *a, const struct msr b) {
+ a->hi &= b.hi;
+ a->lo &= b.lo;
+}
+
+const struct msrdef *findmsrdef(const uint32_t addr) {
+ uint8_t t;
+ const struct msrdef *m;
+ if (!targets)
+ return NULL;
+ for (t = 0; t < targets_found; t++)
+ for (m = targets[t]->msrs; !MSR_ISEOT(*m); m++)
+ if (addr == m->addr)
+ return m;
+ return NULL;
+}
+
+void dumpmsrdefs(const struct targetdef *t) {
+ const struct msrdef *m;
+ const struct msrbits *mb;
+ if (!t)
+ return;
+ printf("# %s MSRs:\n", t->name);
+ for (m = t->msrs; !MSR_ISEOT(*m); m++) {
+ if (t->msrs != m)
+ printf("\n");
+ printf("# %s\n", m->symbol);
+ for (mb = m->bits; mb->size; mb++)
+ print_bitdef(stdout, mb, "\n");
+ printf("0x%08x\n", m->addr);
+ }
+}
+
+int dumpmsrdefsvals(FILE *f, const struct targetdef *t, const uint8_t cpu) {
+ struct msr val = MSR1(0);
+ const struct msrdef *m;
+ const struct msrbits *mb;
+ if (!t)
+ return 1;
+ fprintf(f, "# %s MSRs:\n", t->name);
+ for (m = t->msrs; !MSR_ISEOT(*m); m++) {
+ if (t->msrs != m)
+ fprintf(f, "\n");
+ if (!sys->rdmsr(cpu, m->addr, &val))
+ return 1;
+ fprintf(f, "# %s\n", m->symbol);
+ for (mb = m->bits; mb->size; mb++)
+ print_bitdef(f, mb, "\n");
+ fprintf(f, "0x%08x 0x%08x%08x\n", m->addr, val.hi, val.lo);
+ }
+ return 0;
+}
+
+/**
+ * Parse a hexadecimal string into an MSR value.
+ *
+ * Leading 0x or 0X is optional, the string is always parsed as hexadecimal.
+ * Any non-hexadecimal character can be used to separate the high 32 bits and
+ * the low 32 bits. If there is such a separator, high and low values do not
+ * need to be zero padded. If there is no separator, the last <=8 digits are
+ * the low 32 bits and any characters before them are the high 32 bits.
+ * When there is no separator and less than eight digits, the high 32 bits
+ * are set to 0.
+ * Parsing fails when there is a separator and it is followed by another
+ * non-hexadecimal character.
+ *
+ * @param str The string to parse. The string must be writable but will be
+ * restored before return.
+ * @param msr Pointer to the struct msr where the value will be stored.
+ * @return 1 on success, 0 on parse failure. msr is unchanged on failure.
+ */
+uint8_t str2msr(char *str, struct msr *msr) {
+ char c;
+ size_t len, lo;
+ if (0 == strncmp(str, "0x", 2) || 0 == strncmp(str, "0X", 2))
+ str += 2;
+ len = strspn(str, HEXCHARS);
+ if (len <= 8 && 0 == str[len]) {
+ msr->hi = 0;
+ lo = 0;
+ } else if (len <= 8) {
+ lo = len + strcspn(str + len, HEXCHARS);
+ if (0 == len && 0 == strspn(str + lo, HEXCHARS))
+ return 0;
+ c = str[len];
+ str[len] = 0;
+ msr->hi = strtoul(str, NULL, 16);
+ str[len] = c;
+ } else {
+ lo = len - 8;
+ c = str[lo];
+ str[lo] = 0;
+ msr->hi = strtoul(str, NULL, 16);
+ str[lo] = c;
+ }
+ msr->lo = strtoul(str + lo, NULL, 16);
+ return 1;
+}
+
+void decodemsr(const uint8_t cpu, const uint32_t addr, const struct msr val) {
+ struct msr bitval, mask;
+ const struct msrdef *m = findmsrdef(addr);
+ const struct msrbits *mb;
+
+ if (m)
+ printf("# %s ", m->symbol);
+ printf("0x%08x = 0x%08x%08x\n", addr, val.hi, val.lo);
+ if (!m) {
+ fprintf(stderr, "Sorry - no definition exists for this MSR! Please add it and send a signed-off\n");
+ fprintf(stderr, "patch to coreboot@coreboot.org. Thanks for your help!\n");
+ return;
+ }
+
+ for (mb = m->bits; mb->size; mb++) {
+ if (!reserved && 0 == strcmp(mb->name, "RSVD"))
+ continue;
+ print_bitdef(stdout, mb, " = ");
+ mask.hi = mask.lo = 0xffffffff;
+ mask = msr_shr(mask, 64 - mb->size);
+ bitval = msr_shr(val, mb->start - mb->size + 1);
+ msr_and(&bitval, mask);
+ print_bitval(stdout, mb, bitval);
+ }
+}
+
+/**
+ * Compare two MSR values and print any differences with field definitions and
+ * both old and new values decoded.
+ *
+ * @param f Output stream.
+ * @param addr MSR address.
+ * @param a Left value.
+ * @param b Right value.
+ * @return 1 when a and b differ, 0 when they are equal or only reserved bits
+ * differ and processing of reserved bits was not requested (with -r).
+ */
+uint8_t diff_msr(FILE *f, const uint32_t addr, const struct msr a, const struct msr b) {
+ uint8_t ret = 0, first = 1;
+ struct msr aval, bval, mask;
+ const struct msrdef *m = findmsrdef(addr);
+ const struct msrbits *mb;
+
+ if (a.hi == b.hi && a.lo == b.lo)
+ return 0;
+
+ if (!m) {
+ fprintf(stderr, "MSR 0x%08x has no definition! Please add it and send a Signed-off-by patch\n", addr);
+ fprintf(stderr, "to coreboot@coreboot.org. Thank you for your help!\n");
+ return 1;
+ }
+
+ for (mb = m->bits; mb->size; mb++) {
+ if (!reserved && 0 == strcmp(mb->name, "RSVD"))
+ continue;
+ mask.hi = mask.lo = 0xffffffff;
+ mask = msr_shr(mask, 64 - mb->size);
+ aval = msr_shr(a, mb->start - mb->size + 1);
+ bval = msr_shr(b, mb->start - mb->size + 1);
+ msr_and(&aval, mask);
+ msr_and(&bval, mask);
+ if (msr_eq(aval, bval))
+ continue;
+ if (first) {
+ fprintf(f, "# %s\n", m->symbol);
+ fprintf(f, "-0x%08x 0x%08x%08x\n", addr, a.hi, a.lo);
+ fprintf(f, "+0x%08x 0x%08x%08x\n", addr, b.hi, b.lo);
+ first = 0;
+ ret = 1;
+ }
+ print_bitdef(f, mb, "\n-");
+ print_bitval(f, mb, aval);
+ fprintf(f, "+");
+ print_bitval(f, mb, bval);
+ }
+ return ret;
+}