From 6369d0fbd5508ec3f4f0f72591d502ffb1f2fa61 Mon Sep 17 00:00:00 2001 From: Suleiman Souhlal Date: Sat, 7 Jul 2007 14:56:34 -0700 Subject: [PATCH] Introduce msr device. --- sys/amd64/amd64/support.S | 36 ++++++++++ sys/amd64/conf/NOTES | 1 + sys/amd64/include/cpufunc.h | 2 + sys/conf/files.amd64 | 1 + sys/conf/files.i386 | 1 + sys/dev/msr/msr.c | 159 +++++++++++++++++++++++++++++++++++++++++++ sys/i386/conf/NOTES | 1 + sys/i386/i386/support.s | 37 ++++++++++ sys/i386/include/cpufunc.h | 2 + sys/modules/Makefile | 3 + sys/modules/msr/Makefile | 10 +++ tools/tools/msr/Makefile | 6 ++ tools/tools/msr/msr.c | 134 ++++++++++++++++++++++++++++++++++++ 13 files changed, 393 insertions(+), 0 deletions(-) create mode 100644 sys/dev/msr/msr.c create mode 100644 sys/modules/msr/Makefile create mode 100644 tools/tools/msr/Makefile create mode 100644 tools/tools/msr/msr.c diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S index 782cde9..00150f6 100644 --- a/sys/amd64/amd64/support.S +++ b/sys/amd64/amd64/support.S @@ -689,3 +689,39 @@ NON_GPROF_ENTRY(__bb_init_func) movq %rax,32(%rdi) movq %rdi,bbhead NON_GPROF_RET + +ENTRY(wrmsr_safe) + movq PCPU(CURPCB),%r8 + movq $msrfault,PCB_ONFAULT(%r8) + + movl %edi,%ecx + movq %rsi,%rdx + shrq $32,%rdx + movl %esi,%eax + wrmsr + + xorl %eax,%eax + movq %rax,PCB_ONFAULT(%r8) + ret + +ENTRY(rdmsr_safe) + movq PCPU(CURPCB),%r8 + movq $msrfault,PCB_ONFAULT(%r8) + + movl %edi,%ecx + rdmsr + + shlq $32,%rdx + orq %rdx,%rax + movq %rax,(%rsi) + + xorl %eax,%eax + movq %rax,PCB_ONFAULT(%r8) + ret + + ALIGN_TEXT +msrfault: + movq $0,PCB_ONFAULT(%r8) + movq $EFAULT,%rax + ret + diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES index 5304bf9..d78f10b 100644 --- a/sys/amd64/conf/NOTES +++ b/sys/amd64/conf/NOTES @@ -429,6 +429,7 @@ device smbios device vpd # HOT1 Xilinx 6200 card (http://www.vcc.com/) device xrpu +device msr # # Laptop/Notebook options: diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h index 2c5fcb2..8366e7f 100644 --- a/sys/amd64/include/cpufunc.h +++ b/sys/amd64/include/cpufunc.h @@ -776,5 +776,7 @@ void wrmsr(u_int msr, u_int64_t newval); #endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */ void reset_dbregs(void); +int rdmsr_safe(u_int msr, u_int64_t *val); +int wrmsr_safe(u_int msr, u_int64_t newval); #endif /* !_MACHINE_CPUFUNC_H_ */ diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index a3c2daf..44310d8 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -182,6 +182,7 @@ dev/hwpmc/hwpmc_piv.c optional hwpmc dev/hwpmc/hwpmc_x86.c optional hwpmc dev/kbd/kbd.c optional atkbd | sc | ukbd dev/mem/memutil.c optional mem +dev/msr/msr.c optional msr dev/nfe/if_nfe.c optional nfe pci dev/nve/if_nve.c optional nve pci dev/rr232x/os_bsd.c optional rr232x diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 423b515..3b8dda0 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -208,6 +208,7 @@ dev/le/if_le_isa.c optional le isa dev/mem/memutil.c optional mem dev/mse/mse.c optional mse dev/mse/mse_isa.c optional mse isa +dev/msr/msr.c optional msr dev/nfe/if_nfe.c optional nfe pci dev/nve/if_nve.c optional nve pci dev/pcf/pcf_isa.c optional pcf diff --git a/sys/dev/msr/msr.c b/sys/dev/msr/msr.c new file mode 100644 index 0000000..7938401 --- /dev/null +++ b/sys/dev/msr/msr.c @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2006-2007 Suleiman Souhlal + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAXCPUCHARS 10 + +static d_read_t msr_read; +static d_write_t msr_write; + +static struct cdevsw msr_cdevsw = { + .d_version = D_VERSION, + .d_read = msr_read, + .d_write = msr_write, + .d_name = "msr", +}; + +/* For use with make_dev(9)/destroy_dev(9). */ +static struct cdev *msr_dev[MAXCPU]; + +/* ARGSUSED */ +static int +msr_read(struct cdev *dev, struct uio *uio, int flag) +{ + int cpu, error = 0; + u_int64_t msr; + + cpu = minor(dev); + + thread_lock(curthread); + sched_bind(curthread, cpu); + thread_unlock(curthread); + + while (uio->uio_resid > 0) { + if ((error = rdmsr_safe(uio->uio_offset, &msr)) != 0) + break; + if ((error = uiomove(&msr, sizeof(msr), uio)) != 0) + break; + + } + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); + + return (error); +} + +/* ARGSUSED */ +static int +msr_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) +{ + int cpu, error = 0; + long long value; + long msr; + + cpu = minor(dev); + + thread_lock(curthread); + sched_bind(curthread, cpu); + thread_unlock(curthread); + + while (uio->uio_resid > 0) { + msr = uio->uio_offset; + if ((error = uiomove(&value, sizeof(value), uio)) != 0) + break; + if ((error = wrmsr_safe(msr, value)) != 0) + break; + } + + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); + + return (error); +} + +/* ARGSUSED */ +static int +msr_modevent(module_t mod __unused, int type, void *data __unused) +{ + int i, error = 0; + char name[MAXCPUCHARS + 7]; + + switch (type) { + case MOD_LOAD: + for (i = 0; i < mp_ncpus; i++) { + snprintf(name, MAXCPUCHARS + 7, "cpu%dmsr", i); + msr_dev[i] = make_dev(&msr_cdevsw, i, + UID_ROOT, GID_WHEEL, 0600, name); + } + break; + + case MOD_UNLOAD: + for (i = 0; i < smp_cpus; i++) + destroy_dev(msr_dev[i]); + + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + + } + return (error); +} + +DEV_MODULE(msr, msr_modevent, NULL); +MODULE_VERSION(msr, 1); diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index bbbea1a..7cc5f51 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -315,6 +315,7 @@ hint.speaker.0.at="isa" hint.speaker.0.port="0x61" device gzip #Exec gzipped a.out's. REQUIRES COMPAT_AOUT! device apm_saver # Requires APM +device msr ##################################################################### diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s index 0f34525..25d57b9 100644 --- a/sys/i386/i386/support.s +++ b/sys/i386/i386/support.s @@ -1532,3 +1532,40 @@ NON_GPROF_ENTRY(__bb_init_func) movl %edx,16(%eax) movl %eax,bbhead NON_GPROF_RET + +ENTRY(wrmsr_safe) + movl PCPU(CURPCB),%ecx + movl $msrfault,PCB_ONFAULT(%ecx) + + movl 4(%esp),%ecx + movl 8(%esp),%eax + movl 12(%esp),%edx + wrmsr + + xorl %eax,%eax + movl PCPU(CURPCB),%ecx + movl %eax,PCB_ONFAULT(%ecx) + ret + +ENTRY(rdmsr_safe) + movl PCPU(CURPCB),%ecx + movl $msrfault,PCB_ONFAULT(%ecx) + + movl 4(%esp),%ecx + rdmsr + + movl 8(%esp),%ecx + movl %edx,4(%ecx) + movl %eax,(%ecx) + + xorl %eax,%eax + movl PCPU(CURPCB),%ecx + movl %eax,PCB_ONFAULT(%ecx) + ret + + ALIGN_TEXT +msrfault: + movl PCPU(CURPCB),%ecx + movl $0,PCB_ONFAULT(%ecx) + movl $EFAULT,%rax + ret diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h index 9a646f6..fc5889d 100644 --- a/sys/i386/include/cpufunc.h +++ b/sys/i386/include/cpufunc.h @@ -698,5 +698,7 @@ void wrmsr(u_int msr, u_int64_t newval); #endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */ void reset_dbregs(void); +int rdmsr_safe(u_int msr, u_int64_t *val); +int wrmsr_safe(u_int msr, u_int64_t newval); #endif /* !_MACHINE_CPUFUNC_H_ */ diff --git a/sys/modules/Makefile b/sys/modules/Makefile index babb1cb..a96eadc 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -170,6 +170,7 @@ SUBDIR= ${_3dfx} \ msdosfs_iconv \ ${_mse} \ msk \ + ${_msr} \ ${_mxge} \ my \ ${_ncp} \ @@ -447,6 +448,7 @@ _iwi= iwi _iwifw= iwifw _ixgb= ixgb _mly= mly +_msr= msr _mxge= mxge _nfe= nfe _nve= nve @@ -506,6 +508,7 @@ _linprocfs= linprocfs _linsysfs= linsysfs _linux= linux _mly= mly +_msr= msr _mxge= mxge _ndis= ndis _nfe= nfe diff --git a/sys/modules/msr/Makefile b/sys/modules/msr/Makefile new file mode 100644 index 0000000..87ef7e4 --- /dev/null +++ b/sys/modules/msr/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD: src/sys/modules/random/Makefile,v 1.15 2004/04/11 15:40:18 marcel Exp $ + +.PATH: ${.CURDIR}/../../dev/msr + +KMOD= msr +SRCS= msr.c + +CFLAGS+= -I${.CURDIR}/../.. + +.include diff --git a/tools/tools/msr/Makefile b/tools/tools/msr/Makefile new file mode 100644 index 0000000..d1d01db --- /dev/null +++ b/tools/tools/msr/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ +PROG= msr +NO_MAN= + +.include + diff --git a/tools/tools/msr/msr.c b/tools/tools/msr/msr.c new file mode 100644 index 0000000..303b17b --- /dev/null +++ b/tools/tools/msr/msr.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2007 Suleiman Souhlal + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void +usage(char *name) +{ + fprintf(stderr, "Usage: %s -r cpu msr\n %s -w cpu msr value\n", + name, name); + exit(1); +} + +void +rdmsr(char *path, int msr) +{ + u_int64_t val; + int fd; + int n; + + if ((fd = open(path, O_RDONLY)) < 0) + errx(1, "open: %s", strerror(errno)); + + if (lseek(fd, msr, SEEK_SET) < 0) + errx(1, "lseek: %s", strerror(errno)); + + if (read(fd, &val, sizeof(val)) != sizeof(val)) + errx(1, "read: %s", strerror(errno)); + printf("%jx\n", (intmax_t)val); +} + +void +wrmsr(char *path, int msr, uint64_t val) +{ + int fd; + + if ((fd = open(path, O_RDWR)) < 0) + errx(1, "open: %s", strerror(errno)); + + if (lseek(fd, msr, SEEK_SET) < 0) + errx(1, "lseek: %s", strerror(errno)); + + if (write(fd, &val, sizeof(val)) != sizeof(val)) + errx(1, "write: %s", strerror(errno)); +} + +int +main(int argc, char **argv) +{ + uint64_t val; + char c, path[PATH_MAX]; + int cpu, fd, msr, readmode, writemode; + + readmode = writemode = 0; + while ((c = getopt(argc, argv, "rwh")) != -1) { + switch (c) { + case 'r': + readmode = 1; + if (writemode || argc != 4) { + usage(argv[0]); + /* NOTREACHED */ + } + break; + case 'w': + writemode = 1; + if (readmode || argc != 5) { + usage(argv[0]); + /* NOTREACHED */ + } + break; + case 'h': + default: + usage(argv[0]); + /* NOTREACHED */ + } + } + + if (!readmode && !writemode) { + usage(argv[0]); + /* NOTREACHED */ + } + + cpu = strtoimax(argv[2], NULL, 10); + snprintf(path, PATH_MAX, "/dev/cpu%dmsr", cpu); + msr = strtol(argv[3], NULL, 0); + + if (readmode) + rdmsr(path, msr); + else { + val = strtol(argv[4], NULL, 0); + wrmsr(path, msr, val); + } + + return (0); +} -- 1.5.2