summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/cpucontrol/cpucontrol.860
-rw-r--r--usr.sbin/cpucontrol/cpucontrol.c101
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);
OpenPOWER on IntegriCloud