| /* |
| * 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 && 0 == 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 (0 == 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); |
| } |
| 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%01x", val.lo & 0xf); |
| else if (bits <= 8) |
| fprintf(f, "0x%02x", val.lo & 0xff); |
| else if (bits <= 12) |
| fprintf(f, "0x%03x", val.lo & 0xfff); |
| else if (bits <= 16) |
| fprintf(f, "0x%04x", val.lo & 0xffff); |
| else if (bits <= 20) |
| fprintf(f, "0x%05x", val.lo & 0xfffff); |
| else if (bits <= 24) |
| fprintf(f, "0x%06x", val.lo & 0xffffff); |
| else if (bits <= 28) |
| fprintf(f, "0x%07x", val.lo & 0xfffffff); |
| else if (bits <= 32) |
| fprintf(f, "0x%08x", val.lo); |
| else if (bits <= 36) |
| fprintf(f, "0x%01x%08x", val.hi & 0xf, val.lo); |
| else if (bits <= 40) |
| fprintf(f, "0x%02x%08x", val.hi & 0xff, val.lo); |
| else if (bits <= 44) |
| fprintf(f, "0x%03x%08x", val.hi & 0xfff, val.lo); |
| else if (bits <= 48) |
| fprintf(f, "0x%04x%08x", val.hi & 0xffff, val.lo); |
| else if (bits <= 52) |
| fprintf(f, "0x%05x%08x", val.hi & 0xfffff, val.lo); |
| else if (bits <= 56) |
| fprintf(f, "0x%06x%08x", val.hi & 0xffffff, val.lo); |
| else if (bits <= 60) |
| fprintf(f, "0x%07x%08x", val.hi & 0xfffffff, 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; |
| } |
| |
| uint32_t msraddrbyname(const char *name) { |
| uint8_t t; |
| const uint32_t addr = strtoul(name, NULL, 16); |
| const struct msrdef *m; |
| if (!targets) |
| return addr; |
| for (t = 0; t < targets_found; t++) |
| for (m = targets[t]->msrs; !MSR_ISEOT(*m); m++) { |
| if (addr == m->addr) |
| return m->addr; |
| if (!strcasecmp(name, m->symbol)) |
| return m->addr; |
| } |
| return addr; |
| } |
| |
| void dumpmsrdefs(const struct targetdef *t) { |
| const struct msrdef *m; |
| const struct msrbits *mb; |
| if (NULL == 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 (NULL == 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 except ' ' can 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. |
| * @param endptr If endptr is not NULL, *endptr will point to after the MSR. |
| * @return 1 on success, 0 on parse failure. msr is unchanged on failure. |
| */ |
| uint8_t str2msr(char *str, struct msr *msr, char **endptr) { |
| 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] || ' ' == 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, endptr, 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 (NULL != m) |
| printf("# %s ", m->symbol); |
| printf("0x%08x = 0x%08x%08x\n", addr, val.hi, val.lo); |
| if (NULL == 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 (NULL == 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; |
| } |