summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/cpuctl.47
-rw-r--r--sys/dev/cpuctl/cpuctl.c20
-rw-r--r--sys/sys/cpuctl.h2
-rw-r--r--usr.sbin/cpucontrol/cpucontrol.860
-rw-r--r--usr.sbin/cpucontrol/cpucontrol.c101
5 files changed, 162 insertions, 28 deletions
diff --git a/share/man/man4/cpuctl.4 b/share/man/man4/cpuctl.4
index 9dd149a..09b2d4e 100644
--- a/share/man/man4/cpuctl.4
+++ b/share/man/man4/cpuctl.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 31, 2008
+.Dd June 30, 2009
.Dt CPUCTL 4
.Os
.Sh NAME
@@ -81,6 +81,11 @@ typedef struct {
uint64_t data;
} cpuctl_msr_args_t;
.Ed
+.It Dv CPUCTL_MSRSBIT Fa cpuctl_msr_args_t *args
+.It Dv CPUCTL_MSRCBIT Fa cpuctl_msr_args_t *args
+Set/clear MSR bits according to the mask given in the
+.Va data
+field.
.It Dv CPUCTL_CPUID Fa cpuctl_cpuid_args_t *args
Retrieve CPUID information.
Arguments are supplied in
diff --git a/sys/dev/cpuctl/cpuctl.c b/sys/dev/cpuctl/cpuctl.c
index f325797..c3a2434 100644
--- a/sys/dev/cpuctl/cpuctl.c
+++ b/sys/dev/cpuctl/cpuctl.c
@@ -158,6 +158,8 @@ cpuctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
case CPUCTL_RDMSR:
ret = cpuctl_do_msr(cpu, (cpuctl_msr_args_t *)data, cmd, td);
break;
+ case CPUCTL_MSRSBIT:
+ case CPUCTL_MSRCBIT:
case CPUCTL_WRMSR:
ret = priv_check(td, PRIV_CPUCTL_WRMSR);
if (ret != 0)
@@ -211,6 +213,7 @@ cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td)
static int
cpuctl_do_msr(int cpu, cpuctl_msr_args_t *data, u_long cmd, struct thread *td)
{
+ uint64_t reg;
int is_bound = 0;
int oldcpu;
int ret;
@@ -230,9 +233,22 @@ cpuctl_do_msr(int cpu, cpuctl_msr_args_t *data, u_long cmd, struct thread *td)
if (cmd == CPUCTL_RDMSR) {
data->data = 0;
ret = rdmsr_safe(data->msr, &data->data);
- } else {
+ } else if (cmd == CPUCTL_WRMSR) {
ret = wrmsr_safe(data->msr, data->data);
- }
+ } else if (cmd == CPUCTL_MSRSBIT) {
+ critical_enter();
+ ret = rdmsr_safe(data->msr, &reg);
+ if (ret == 0)
+ ret = wrmsr_safe(data->msr, reg | data->data);
+ critical_exit();
+ } else if (cmd == CPUCTL_MSRCBIT) {
+ critical_enter();
+ ret = rdmsr_safe(data->msr, &reg);
+ if (ret == 0)
+ ret = wrmsr_safe(data->msr, reg & ~data->data);
+ critical_exit();
+ } else
+ panic("[cpuctl,%d]: unknown operation requested: %lu", __LINE__, cmd);
restore_cpu(oldcpu, is_bound, td);
return (ret);
}
diff --git a/sys/sys/cpuctl.h b/sys/sys/cpuctl.h
index 57b5acf..4bddb34 100644
--- a/sys/sys/cpuctl.h
+++ b/sys/sys/cpuctl.h
@@ -48,5 +48,7 @@ typedef struct {
#define CPUCTL_WRMSR _IOWR('c', 2, cpuctl_msr_args_t)
#define CPUCTL_CPUID _IOWR('c', 3, cpuctl_cpuid_args_t)
#define CPUCTL_UPDATE _IOWR('c', 4, cpuctl_update_args_t)
+#define CPUCTL_MSRSBIT _IOWR('c', 5, cpuctl_msr_args_t)
+#define CPUCTL_MSRCBIT _IOWR('c', 6, cpuctl_msr_args_t)
#endif /* _CPUCTL_H_ */
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