MSR support for x86

Stephan Meyer (sensei@wiesel.de)
Thu, 27 Feb 1997 23:42:46 +0100 (MET)


Hia! [you will probably receive this 4-5 times :-( ]

Well, I implemented support for the Machine Specific Registers supported
by most recent processors that are compatible with the x86 line.
These registers provide access to options and statistics deeply buried
inside the CPU.

Some Examples: - application interface to the cycle counter
(user level program to determine clock speed)
- counting of internal events:
- cache hits/misses
- [MMX] instructions executed in U/V pipe
- bad alignments

Intel claims that with each generation of processors, the meaning of the
registers might change. I only have information on the Pentium and I will
go find and post some URLs to listings of these features.

Access to the registers is made available through the character device
/dev/msr major 10 / minor 8. (Could the responsible person please make
this assignment official?). To read/write, you open the device and seek to
the index of the needed register. E.g. for register Nr.10, this becomes
"lseek(f,10,0);". Regardless of the specified size, always 8 bytes (two
long ints, 64 bits) are copied (actual size of a register). The high dword
(edx) is followed by the low dword (eax).

The code is very simple and should be easy to understand. However, it took
me quite some time to dig around in other sources to learn how to
implement a character device. And I don't understand, why an "open"
function is needed for a character device with major 10 (misc device).
It's just the body in my code.

The patch is against 2.0.29, but should probably work with 2.1.x, too. To
enable this, you need to check "Prompt for development and/or incomplete
code/drivers" and then enable "Enable /dev/msr to access Machine Specific
Registers" in section "General setup". Recompile and enjoy!

IMHO, this could be the way to many answers to performance related
questions. Especially debugger programmers might be interested in this.

Have fun and send me feedback!

Many thanks go to Ingo Molnar for encouraging me!

Cheers, Stephan

-----------------------------------------------
Stephan Meyer
+49-89-4301114
Stephan.Meyer@munich.netsurf.de
http://fatman.mathematik.tu-muenchen.de/~meyer/
-----------------------------------------------

-------------- cut here -----------------
diff -u -N -r linux-old/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-old/Documentation/Configure.help Wed Feb 26 15:48:18 1997
+++ linux/Documentation/Configure.help Thu Feb 27 23:05:05 1997
@@ -3893,6 +3893,17 @@
machine see http://cap.anu.edu.au/cap/projects/linux or mail to
hackers@cafe.anu.edu.au

+Support for Model Specific Registers
+CONFIG_CHR_DEV_MSR
+ This enables support for the Model Specific Registers implemented
+ by most recent x86 family processors. Access is done by doing a seek
+ with the number of the needed register and subsequent read/write
+ operations on /dev/msr. The read/write routines always copy two 32-bit
+ values (8 bytes). A read/write operation does *not* advance the
+ position pointer.
+ To check if your processor supports MSR, look for
+ "msr" in the "flags" section of "/proc/cpuinfo".
+
# need an empty line after last entry, for sed script in Configure.

#
diff -u -N -r linux-old/Documentation/devices.tex linux/Documentation/devices.tex
--- linux-old/Documentation/devices.tex Wed Feb 26 15:48:16 1997
+++ linux/Documentation/devices.tex Thu Feb 27 15:54:00 1997
@@ -453,6 +453,7 @@
\minor{5}{/dev/atarimouse}{Atari mouse}
\minor{6}{/dev/sunmouse}{Sun mouse}
\minor{7}{/dev/amigamouse1}{Second Amiga mouse}
+ \minor{8}{/dev/msr}{Machine Specific Registers}
\minor{128}{/dev/beep}{Fancy beep device}
\minor{129}{/dev/modreq}{Kernel module load request}
\minor{130}{/dev/watchdog}{Watchdog timer port}
diff -u -N -r linux-old/Documentation/devices.txt linux/Documentation/devices.txt
--- linux-old/Documentation/devices.txt Wed Feb 26 15:48:16 1997
+++ linux/Documentation/devices.txt Thu Feb 27 15:53:22 1997
@@ -269,6 +269,7 @@
5 = /dev/atarimouse Atari mouse
6 = /dev/sunmouse Sun mouse
7 = /dev/amigamouse1 Second Amiga mouse
+ 8 = /dev/msr Machine Specific Registers
128 = /dev/beep Fancy beep device
129 = /dev/modreq Kernel module load request
130 = /dev/watchdog Watchdog timer port
diff -u -N -r linux-old/MAINTAINERS linux/MAINTAINERS
--- linux-old/MAINTAINERS Wed Feb 26 15:48:21 1997
+++ linux/MAINTAINERS Wed Feb 26 16:12:02 1997
@@ -353,6 +353,12 @@
L: linux-kernel@vger.rutgers.edu
S: Maintained

+X86 MSR DRIVER
+P: Stephan Meyer
+M: Stephan.Meyer@munich.netsurf.de
+W: http://fatman.mathematik.tu-muenchen.de/~meyer/
+S: Maintained
+
CREDITS FILE
P: John A. Martin
M: jam@acm.org
diff -u -N -r linux-old/arch/i386/config.in linux/arch/i386/config.in
--- linux-old/arch/i386/config.in Wed Feb 26 15:48:22 1997
+++ linux/arch/i386/config.in Wed Feb 26 15:58:05 1997
@@ -47,6 +47,7 @@
if [ "$CONFIG_M586" = "y" ]; then
bool 'Use Pentium-optimized copy routine' CONFIG_M586_COPY y
fi
+ bool 'Enable /dev/msr to access Machine Specific Registers' CONFIG_CHR_DEV_MSR y
fi
endmenu

diff -u -N -r linux-old/drivers/char/Makefile linux/drivers/char/Makefile
--- linux-old/drivers/char/Makefile Wed Feb 26 15:48:52 1997
+++ linux/drivers/char/Makefile Thu Feb 27 06:50:42 1997
@@ -188,6 +188,11 @@
M = y
endif

+ifdef CONFIG_CHR_DEV_MSR
+LX_OBJS += msr.o
+M = y
+endif
+
ifdef M
LX_OBJS += misc.o
else
diff -u -N -r linux-old/drivers/char/misc.c linux/drivers/char/misc.c
--- linux-old/drivers/char/misc.c Wed Feb 26 15:48:53 1997
+++ linux/drivers/char/misc.c Wed Feb 26 16:05:32 1997
@@ -61,6 +61,7 @@
static unsigned char misc_minors[DYNAMIC_MINORS / 8];

#ifndef MODULE
+extern int msr_init(void);
extern int bus_mouse_init(void);
extern int psaux_init(void);
extern int ms_bus_mouse_init(void);
@@ -188,6 +189,9 @@
int misc_init(void)
{
#ifndef MODULE
+#ifdef CONFIG_CHR_DEV_MSR
+ msr_init();
+#endif
#ifdef CONFIG_PROC_FS
proc_register_dynamic(&proc_root, &(struct proc_dir_entry) {
0, 4, "misc",
diff -u -N -r linux-old/drivers/char/msr.c linux/drivers/char/msr.c
--- linux-old/drivers/char/msr.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/char/msr.c Thu Feb 27 23:03:35 1997
@@ -0,0 +1,92 @@
+/*
+ * Machine Specific Register Driver for Linux
+ * by Stephan Meyer
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/linkage.h>
+#include <linux/miscdevice.h>
+
+#define MSR_MINOR 8
+
+static int msr_open(struct inode * inode, struct file * file) {
+ return 0;
+}
+
+static void msr_close(struct inode * inode, struct file * file) {
+}
+
+static int msr_read(struct inode *inode, struct file *file, char *buf, int count) {
+ unsigned long int p=file->f_pos,hi,lo;
+ __asm__ __volatile__ (
+ "rdmsr"
+ :"=a" (lo), "=d" (hi)
+ :"c" (p)
+ :"eax","ecx","edx");
+ memcpy_tofs(buf,&hi,4);
+ memcpy_tofs(buf+4,&lo,4);
+ return 8;
+}
+
+static int msr_write(struct inode *inode, struct file *file, const char *buf, int count) {
+ unsigned long p=file->f_pos,hi,lo;
+ memcpy_fromfs(&hi,buf,4);
+ memcpy_fromfs(&lo,buf+4,4);
+ __asm__ __volatile__ (
+ "wrmsr"
+ :
+ :"c" (p), "a" (lo), "d" (hi)
+ :"eax","ecx","edx");
+ return 8;
+}
+
+static int msr_seek(struct inode *inode, struct file *file, off_t offset, int orig) {
+ switch (orig) {
+ case 0:
+ file->f_pos=offset;
+ return file->f_pos;
+ case 1:
+ file->f_pos+=offset;
+ return file->f_pos;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct file_operations msr_fops = {
+ msr_seek,
+ msr_read,
+ msr_write,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ msr_open,
+ msr_close,
+ NULL,
+ NULL
+};
+
+static struct miscdevice msr_device = {
+ MSR_MINOR,
+ "msr",
+ &msr_fops
+};
+
+void msr_init(void) {
+ int i;
+ if ((!have_cpuid) && (!(x86_capability & 32))) {
+ printk("MSR not supported!\n");
+ return;
+ }
+ misc_register(&msr_device);
+}
+
\ No newline at end of file