diff options
-rw-r--r-- | share/man/man4/cpuctl.4 | 7 | ||||
-rw-r--r-- | sys/dev/cpuctl/cpuctl.c | 20 | ||||
-rw-r--r-- | sys/sys/cpuctl.h | 2 | ||||
-rw-r--r-- | usr.sbin/cpucontrol/cpucontrol.8 | 60 | ||||
-rw-r--r-- | usr.sbin/cpucontrol/cpucontrol.c | 101 |
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, ®); + 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, ®); + 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); |