Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

userland access to MSRs



     For some time I've wanted to have userland access to MSRs.
One of the things that prompted my desire was a message on a Xen
console about memory errors along with instructions to read an MSR
to get details but not having any way to do so.  Several others
seem somewhat enthused by this as a number of other OSes already
have facilities.  I have started working on this.  I have modelled
it somewhat on how FreeBSD does it.  Here is my current kernel
patch:

Index: kern_cpu.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_cpu.c,v
retrieving revision 1.97
diff -p -u -r1.97 kern_cpu.c
--- kern_cpu.c	2 Sep 2023 17:44:59 -0000	1.97
+++ kern_cpu.c	14 Jul 2024 06:11:52 -0000
@@ -65,6 +65,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v
 #ifdef _KERNEL_OPT
 #include "opt_cpu_ucode.h"
 #include "opt_heartbeat.h"
+#include "opt_cpu_msr.h"
 #endif
 
 #include <sys/param.h>
@@ -92,6 +93,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v
 
 #include "ioconf.h"
 
+#ifdef CPU_MSR
+#include <x86/cpufunc.h>
+#endif
+
 /*
  * If the port has stated that cpu_data is the first thing in cpu_info,
  * verify that the claim is true. This will prevent them from getting out
@@ -197,6 +202,7 @@ cpuctl_ioctl(dev_t dev, u_long cmd, void
 	struct cpu_info *ci;
 	int error, i;
 	u_int id;
+	struct cpu_msr *cm;
 
 	error = 0;
 
@@ -274,6 +280,26 @@ cpuctl_ioctl(dev_t dev, u_long cmd, void
 		break;
 #endif
 
+#ifdef CPU_MSR
+	case IOC_CPU_RDMSR:
+		cm = data;
+		id = cm->id;
+		if (id >= maxcpus ||
+		    (ci = cpu_lookup(id)) == NULL) {
+			error = ESRCH;
+			break;
+		}
+		/* switch CPU or have userland do it? */
+		error = rdmsr_safe(cm->msr, &cm->data);
+		break;
+
+	case IOC_CPU_WRMSR:		/* fall through */
+	case IOC_CPU_MSRSBIT:		/* fall through */
+	case IOC_CPU_MSRCBIT:
+		/* insert call to kauth_authorize_machdep here */
+		break;
+#endif
+
 	default:
 		error = (*compat_cpuctl_ioctl)(l, cmd, data);
 		break;

     At the moment, this is only for x86, but should be easily
adaptable to other platforms.  Reading works, but obviously without
doing in-kernel cpu switching.  Userland is handled through cpuctl(8).
The first question is whether CPU switching should be handled in
userland (ala "cpuctl identify" which my patch to cpuctl(8) does)
or whether it should be handled in the kernel (switching CPUs,
xcalls, etc.).  Any thoughts on this and if in-kernel, how to do
it?

     The second question is about thoughts on authorization for
wrmsr.  Initailly I'm thinking along the lines of how updating
ucode does it (by code inspection, no ability above securelevel 1,
root otherwise).  Also, there is no wrmsr_safe() analog to rdmsr_safe()
(turns traps into EFAULT) which should be created.  Help with this
from somebody comfortable with x86 low-level assembly coding would
be appreciated.


Home | Main Index | Thread Index | Old Index