diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/cpucontrol/cpucontrol.8 | 60 | ||||
-rw-r--r-- | usr.sbin/cpucontrol/cpucontrol.c | 101 |
2 files changed, 136 insertions, 25 deletions
diff --git a/usr.sbin/cpucontrol/cpucontrol.8 b/usr.sbin/cpucontrol/cpucontrol.8 index 01bc9d3..165e67b 100644 --- a/usr.sbin/cpucontrol/cpucontrol.8 +++ b/usr.sbin/cpucontrol/cpucontrol.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 4, 2008 +.Dd June 30, 2009 .Dt CPUCONTROL 8 .Os .Sh NAME @@ -35,7 +35,25 @@ device. .Sh SYNOPSIS .Nm .Op Fl vh -.Fl m Ar msr Ns Op = Ns Ar value +.Fl m Ar msr +.Bk +.Ar device +.Ek +.Nm +.Op Fl vh +.Fl m Ar msr Ns = Ns Ar value +.Bk +.Ar device +.Ek +.Nm +.Op Fl vh +.Fl m Ar msr Ns &= Ns Ar mask +.Bk +.Ar device +.Ek +.Nm +.Op Fl vh +.Fl m Ar msr Ns |= Ns Ar mask .Bk .Ar device .Ek @@ -67,8 +85,32 @@ The following options are available: Where to look for microcode images. The option can be specified multiple times. .It Fl m Ar msr Ns Op = Ns Ar value -Read/write the specified MSR. -Both the MSR and the value should be given as a hex number. +Show value of the specified MSR. +MSR register number should be given as a hexadecimal number. +.It Fl m Ar msr Ns = Ns Ar value +Store the +.Ar value +in the specified MSR register. +The +.Ar value +argument can be prefixed with ~ operator. +In this case the inverted value of argument will be stored in the register. +.It Fl m Ar msr Ns &= Ns Ar mask +Store the result of bitwise AND operation between +.Ar mask +and the current MSR value in the MSR register. +The +.Ar mask +argument can be prefixed with ~ operator. +In this case the inverted value of mask will be used. +.It Fl m Ar msr Ns |= Ns Ar mask +Store the result of bitwise OR operation between +.Ar mask +and the current MSR value in the MSR register. +The +.Ar mask +argument can be prefixed with ~ operator. +In this case the inverted value of mask will be used. .It Fl i Ar level Retrieve CPUID info. Level should be given as a hex number. @@ -94,7 +136,15 @@ will read the contents of TSC MSR from CPU 0. .Pp To set the CPU 0 TSC MSR register value to 0x1 issue .Pp -.Dq Li "cpucontrol -m 0x10=0x1 /dev/cpuctl0" +.Dq Li "cpucontrol -m 0x10=0x1 /dev/cpuctl0" . +.Pp +The following command will clear the second bit of TSC register: +.Pp +.Dq Li "cpucontrol -m 0x10&=~0x02 /dev/cpuctl0" . +.Pp +The following command will set the forth and second bit of TSC register: +.Pp +.Dq Li "cpucontrol -m 0x10|=0x0a /dev/cpuctl0" . .Pp The command .Pp diff --git a/usr.sbin/cpucontrol/cpucontrol.c b/usr.sbin/cpucontrol/cpucontrol.c index 5469ee2..8b3ca1d 100644 --- a/usr.sbin/cpucontrol/cpucontrol.c +++ b/usr.sbin/cpucontrol/cpucontrol.c @@ -60,6 +60,12 @@ int verbosity_level = 0; #define FLAG_M 0x02 #define FLAG_U 0x04 +#define OP_INVAL 0x00 +#define OP_READ 0x01 +#define OP_WRITE 0x02 +#define OP_OR 0x04 +#define OP_AND 0x08 + #define HIGH(val) (uint32_t)(((val) >> 32) & 0xffffffff) #define LOW(val) (uint32_t)((val) & 0xffffffff) @@ -166,28 +172,64 @@ do_msr(const char *cmdarg, const char *dev) { unsigned int msr; cpuctl_msr_args_t args; + size_t len; + uint64_t data = 0; + unsigned long command; + int do_invert = 0, op; int fd, error; - int wr = 0; - char *p; char *endptr; + char *p; assert(cmdarg != NULL); assert(dev != NULL); + len = strlen(cmdarg); + if (len == 0) { + WARNX(0, "MSR register expected"); + usage(); + /* NOTREACHED */ + } - p = strchr(cmdarg, '='); - if (p != NULL) { - wr = 1; - *p++ = '\0'; - args.data = strtoull(p, &endptr, 16); - if (*p == '\0' || *endptr != '\0') { - WARNX(0, "incorrect MSR value: %s", p); - usage(); - /* NOTREACHED */ + /* + * Parse command string. + */ + msr = strtoul(cmdarg, &endptr, 16); + switch (*endptr) { + case '\0': + op = OP_READ; + break; + case '=': + op = OP_WRITE; + break; + case '&': + op = OP_AND; + endptr++; + break; + case '|': + op = OP_OR; + endptr++; + break; + default: + op = OP_INVAL; + } + if (op != OP_READ) { /* Complex operation. */ + if (*endptr != '=') + op = OP_INVAL; + else { + p = ++endptr; + if (*p == '~') { + do_invert = 1; + p++; + } + data = strtoull(p, &endptr, 16); + if (*p == '\0' || *endptr != '\0') { + WARNX(0, "argument required: %s", cmdarg); + usage(); + /* NOTREACHED */ + } } } - msr = strtoul(cmdarg, &endptr, 16); - if (*cmdarg == '\0' || *endptr != '\0') { - WARNX(0, "incorrect MSR register: %s", cmdarg); + if (op == OP_INVAL) { + WARNX(0, "invalid operator: %s", cmdarg); usage(); /* NOTREACHED */ } @@ -196,20 +238,39 @@ do_msr(const char *cmdarg, const char *dev) * Fill ioctl argument structure. */ args.msr = msr; - fd = open(dev, wr == 0 ? O_RDONLY : O_WRONLY); + if ((do_invert != 0) ^ (op == OP_AND)) + args.data = ~data; + else + args.data = data; + switch (op) { + case OP_READ: + command = CPUCTL_RDMSR; + break; + case OP_WRITE: + command = CPUCTL_WRMSR; + break; + case OP_OR: + command = CPUCTL_MSRSBIT; + break; + case OP_AND: + command = CPUCTL_MSRCBIT; + break; + default: + abort(); + } + fd = open(dev, op == OP_READ ? O_RDONLY : O_WRONLY); if (fd < 0) { WARN(0, "error opening %s for %s", dev, - wr == 0 ? "reading" : "writing"); + op == OP_READ ? "reading" : "writing"); return (1); } - error = ioctl(fd, wr == 0 ? CPUCTL_RDMSR : CPUCTL_WRMSR, &args); + error = ioctl(fd, command, &args); if (error < 0) { - WARN(0, "ioctl(%s, %s)", dev, - wr == 0 ? "CPUCTL_RDMSR" : "CPUCTL_WRMSR"); + WARN(0, "ioctl(%s, %lu)", dev, command); close(fd); return (1); } - if (wr == 0) + if (op == OP_READ) fprintf(stdout, "MSR 0x%x: 0x%.8x 0x%.8x\n", msr, HIGH(args.data), LOW(args.data)); close(fd); |