| /* ----------------------------------------------------------------------- * |
| * |
| * Copyright 2000 Transmeta Corporation - All Rights Reserved |
| * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston MA 02110-1301, USA; either version 2 of the License, or |
| * (at your option) any later version; incorporated herein by reference. |
| * |
| * ----------------------------------------------------------------------- */ |
| |
| /* |
| * wrmsr.c |
| * |
| * Utility to write to an MSR. |
| */ |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <getopt.h> |
| #include <inttypes.h> |
| #include <sys/types.h> |
| |
| #include "version.h" |
| |
| static const struct option long_options[] = { |
| {"help", 0, 0, 'h'}, |
| {"version", 0, 0, 'V'}, |
| {"all", 0, 0, 'a'}, |
| {"processor", 1, 0, 'p'}, |
| {"cpu", 1, 0, 'p'}, |
| {0, 0, 0, 0} |
| }; |
| static const char short_options[] = "hVap:"; |
| |
| static const char *proc_stat = "/proc/stat"; |
| const char *program; |
| |
| void usage(void) |
| { |
| fprintf(stderr, "Usage: %s [options] regno value...\n" |
| " --help -h Print this help\n" |
| " --version -V Print current version\n" |
| " --all -a all processors\n" |
| " --processor # -p Select processor number (default 0)\n", |
| program); |
| } |
| |
| void wrmsr_on_cpu(uint32_t reg, uint64_t data, int cpu) |
| { |
| int fd; |
| char msr_file_name[64]; |
| |
| sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); |
| fd = open(msr_file_name, O_WRONLY); |
| if (fd < 0) { |
| if (errno == ENXIO) { |
| fprintf(stderr, "wrmsr: No CPU %d\n", cpu); |
| exit(2); |
| } else if (errno == EIO) { |
| fprintf(stderr, "wrmsr: CPU %d doesn't support MSRs\n", |
| cpu); |
| exit(3); |
| } else { |
| perror("wrmsr: open"); |
| exit(127); |
| } |
| } |
| if (pwrite(fd, &data, sizeof data, reg) != sizeof data) { |
| if (errno == EIO) { |
| fprintf(stderr, |
| "wrmsr: CPU %d cannot set MSR " |
| "0x%08"PRIx32" to 0x%016"PRIx64"\n", |
| cpu, reg, data); |
| exit(4); |
| } else { |
| perror("wrmsr: pwrite"); |
| exit(127); |
| } |
| } |
| close(fd); |
| } |
| |
| |
| void wrmsr_on_all_cpus(uint32_t reg, uint64_t data) |
| { |
| FILE *fp; |
| int retval; |
| |
| fp = fopen(proc_stat, "r"); |
| if (fp == NULL) { |
| perror(proc_stat); |
| exit(-1); |
| } |
| |
| retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); |
| if (retval != 0) { |
| perror("/proc/stat format"); |
| exit(-1); |
| } |
| |
| for (;;) { |
| int cpu; |
| |
| retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d " |
| "%*d %*d\n", &cpu); |
| if (retval != 1) |
| return; |
| |
| wrmsr_on_cpu(reg, data, cpu); |
| } |
| fclose(fp); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| uint32_t reg; |
| uint64_t data; |
| int c; |
| int cpu = 0; |
| unsigned long arg; |
| char *endarg; |
| |
| program = argv[0]; |
| |
| while ((c = getopt_long(argc, argv, short_options, |
| long_options, NULL)) != -1) { |
| switch (c) { |
| case 'h': |
| usage(); |
| exit(0); |
| case 'V': |
| fprintf(stderr, "%s: version %s\n", program, |
| VERSION_STRING); |
| exit(0); |
| case 'a': |
| cpu = -1; |
| break; |
| case 'p': |
| arg = strtoul(optarg, &endarg, 0); |
| if (*endarg || arg > 255) { |
| usage(); |
| exit(127); |
| } |
| cpu = (int)arg; |
| break; |
| default: |
| usage(); |
| exit(127); |
| } |
| } |
| |
| if (optind > argc - 2) { |
| /* Should have at least two arguments */ |
| usage(); |
| exit(127); |
| } |
| |
| reg = strtoul(argv[optind++], NULL, 0); |
| |
| while (optind < argc) { |
| data = strtoull(argv[optind++], NULL, 0); |
| if (cpu == -1) |
| wrmsr_on_all_cpus(reg, data); |
| else |
| wrmsr_on_cpu(reg, data, cpu); |
| } |
| exit(0); |
| } |