Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Jul 2026 10:00:24 +0000
From:      Olivier Certner <olce@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Cc:        Konstantin Belousov <kib@FreeBSD.org>
Subject:   git: 7ad1f88f6f5d - stable/14 - x86: add a safe variant of MSR_OP_SCHED* operations for x86_msr_op(9)
Message-ID:  <6a61e638.3d32f.1a0f2af8@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/14 has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=7ad1f88f6f5db6754d31f2018599c92efb11ab6f

commit 7ad1f88f6f5db6754d31f2018599c92efb11ab6f
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-02-01 23:43:50 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2026-07-23 09:58:59 +0000

    x86: add a safe variant of MSR_OP_SCHED* operations for x86_msr_op(9)
    
    The modifier executes the operation using msr{read,write}_safe()
    functions instead of plain msr reads and writes.  Returns EFAULT if any
    MSR access caused #GP.
    
    Reviewed by:    markj, olce
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D55045
    
    (cherry picked from commit af99e40af1dd4e8b39ca986240ee8b9aea722958)
---
 sys/x86/include/x86_var.h |  3 +-
 sys/x86/x86/cpu_machdep.c | 75 ++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 70 insertions(+), 8 deletions(-)

diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
index bd246623ec07..e12f88e0ae03 100644
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -172,6 +172,7 @@ uint64_t rdtsc_ordered(void);
  *
  * All modes cause execution on the target CPU(s) with interrupts disabled.
  */
+#define	MSR_OP_SAFE		0x08000000
 #define	MSR_OP_LOCAL		0x10000000
 #define	MSR_OP_SCHED_ALL	0x20000000
 #define	MSR_OP_SCHED_ONE	0x30000000
@@ -179,7 +180,7 @@ uint64_t rdtsc_ordered(void);
 #define	MSR_OP_RENDEZVOUS_ONE	0x50000000
 #define	MSR_OP_CPUID(id)	((id) << 8)
 
-void x86_msr_op(u_int msr, u_int op, uint64_t arg1, uint64_t *res);
+int x86_msr_op(u_int msr, u_int op, uint64_t arg1, uint64_t *res);
 
 #if defined(__i386__) && defined(INVARIANTS)
 void	trap_check_kstack(void);
diff --git a/sys/x86/x86/cpu_machdep.c b/sys/x86/x86/cpu_machdep.c
index 1c10af10e79d..6e49a25f8ece 100644
--- a/sys/x86/x86/cpu_machdep.c
+++ b/sys/x86/x86/cpu_machdep.c
@@ -119,15 +119,60 @@ struct msr_op_arg {
 	int op;
 	uint64_t arg1;
 	uint64_t *res;
+	bool safe;
+	int error;
 };
 
 static void
-x86_msr_op_one(void *argp)
+x86_msr_op_one_safe(struct msr_op_arg *a)
+{
+	uint64_t v;
+	int error;
+
+	error = 0;
+	switch (a->op) {
+	case MSR_OP_ANDNOT:
+		error = rdmsr_safe(a->msr, &v);
+		if (error != 0) {
+			atomic_cmpset_int(&a->error, 0, error);
+			break;
+		}
+		v &= ~a->arg1;
+		error = wrmsr_safe(a->msr, v);
+		if (error != 0)
+			atomic_cmpset_int(&a->error, 0, error);
+		break;
+	case MSR_OP_OR:
+		error = rdmsr_safe(a->msr, &v);
+		if (error != 0) {
+			atomic_cmpset_int(&a->error, 0, error);
+			break;
+		}
+		v |= a->arg1;
+		error = wrmsr_safe(a->msr, v);
+		if (error != 0)
+			atomic_cmpset_int(&a->error, 0, error);
+		break;
+	case MSR_OP_WRITE:
+		error = wrmsr_safe(a->msr, a->arg1);
+		if (error != 0)
+			atomic_cmpset_int(&a->error, 0, error);
+		break;
+	case MSR_OP_READ:
+		error = rdmsr_safe(a->msr, &v);
+		if (error == 0)
+			*a->res = v;
+		else
+			atomic_cmpset_int(&a->error, 0, error);
+		break;
+	}
+}
+
+static void
+x86_msr_op_one_unsafe(struct msr_op_arg *a)
 {
-	struct msr_op_arg *a;
 	uint64_t v;
 
-	a = argp;
 	switch (a->op) {
 	case MSR_OP_ANDNOT:
 		v = rdmsr(a->msr);
@@ -151,11 +196,24 @@ x86_msr_op_one(void *argp)
 	}
 }
 
+static void
+x86_msr_op_one(void *arg)
+{
+	struct msr_op_arg *a;
+
+	a = arg;
+	if (a->safe)
+		x86_msr_op_one_safe(a);
+	else
+		x86_msr_op_one_unsafe(a);
+}
+
 #define	MSR_OP_EXMODE_MASK	0xf0000000
 #define	MSR_OP_OP_MASK		0x000000ff
-#define	MSR_OP_GET_CPUID(x)	(((x) & ~MSR_OP_EXMODE_MASK) >> 8)
+#define	MSR_OP_GET_CPUID(x) \
+    (((x) & ~(MSR_OP_EXMODE_MASK | MSR_OP_SAFE)) >> 8)
 
-void
+int
 x86_msr_op(u_int msr, u_int op, uint64_t arg1, uint64_t *res)
 {
 	struct thread *td;
@@ -168,8 +226,10 @@ x86_msr_op(u_int msr, u_int op, uint64_t arg1, uint64_t *res)
 	exmode = op & MSR_OP_EXMODE_MASK;
 	a.op = op & MSR_OP_OP_MASK;
 	a.msr = msr;
+	a.safe = (op & MSR_OP_SAFE) != 0;
 	a.arg1 = arg1;
 	a.res = res;
+	a.error = 0;
 
 	switch (exmode) {
 	case MSR_OP_LOCAL:
@@ -210,8 +270,8 @@ x86_msr_op(u_int msr, u_int op, uint64_t arg1, uint64_t *res)
 		thread_unlock(td);
 		break;
 	case MSR_OP_RENDEZVOUS_ALL:
-		smp_rendezvous(smp_no_rendezvous_barrier, x86_msr_op_one,
-		    smp_no_rendezvous_barrier, &a);
+		smp_rendezvous(smp_no_rendezvous_barrier,
+		    x86_msr_op_one, smp_no_rendezvous_barrier, &a);
 		break;
 	case MSR_OP_RENDEZVOUS_ONE:
 		cpu = MSR_OP_GET_CPUID(op);
@@ -222,6 +282,7 @@ x86_msr_op(u_int msr, u_int op, uint64_t arg1, uint64_t *res)
 	default:
 		__assert_unreachable();
 	}
+	return (a.error);
 }
 
 /*


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a61e638.3d32f.1a0f2af8>