git: 797e92944d11 - stable/15 - cpuctl: run amd_ucode_wrmsr only on one CPU and report if it failed

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Mon, 22 Sep 2025 16:11:56 UTC
The branch stable/15 has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=797e92944d118c0fe7de20ae92a18066eaf9a194

commit 797e92944d118c0fe7de20ae92a18066eaf9a194
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-09-18 15:10:59 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-09-22 16:11:33 +0000

    cpuctl: run amd_ucode_wrmsr only on one CPU and report if it failed
    
    The CPUCTL_UPDATE is supposed to be applied only to the CPU the ioctl(2)
    was performed on.  This is true for Intel CPUs, but for AMD the SMP
    rendezvouz of amd_ucode_wrmsr() effectively executed it on all CPUs.
    Also, the update failure was not reported.
    
    Reviewed by:            markj
    Differential Revision:  https://reviews.freebsd.org/D52466
    
    (cherry picked from commit 6683dcf61b3d0dfa8639c9e501eefb7709922ddf)
---
 sys/dev/cpuctl/cpuctl.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/sys/dev/cpuctl/cpuctl.c b/sys/dev/cpuctl/cpuctl.c
index 9253b17a259d..b0ab3467df69 100644
--- a/sys/dev/cpuctl/cpuctl.c
+++ b/sys/dev/cpuctl/cpuctl.c
@@ -402,19 +402,20 @@ out:
  * its workings.
  */
 static void
-amd_ucode_wrmsr(void *ucode_ptr)
+amd_ucode_wrmsr(void *arg)
 {
+	struct ucode_update_data *d = arg;
 	uint32_t tmp[4];
 
-	wrmsr_safe(MSR_K8_UCODE_UPDATE, (uintptr_t)ucode_ptr);
+	if (PCPU_GET(cpuid) == d->cpu)
+		d->ret = wrmsr_safe(MSR_K8_UCODE_UPDATE, (uintptr_t)d->ptr);
 	do_cpuid(0, tmp);
 }
 
 static int
 update_amd(int cpu, cpuctl_update_args_t *args, struct thread *td)
 {
-	void *ptr;
-	int ret;
+	struct ucode_update_data d = { .cpu = cpu };
 
 	if (args->size == 0 || args->data == NULL) {
 		DPRINTF("[cpuctl,%d]: zero-sized firmware image", __LINE__);
@@ -430,18 +431,17 @@ update_amd(int cpu, cpuctl_update_args_t *args, struct thread *td)
 	 * malloc(9) always returns the pointer aligned at least on
 	 * the size of the allocation.
 	 */
-	ptr = malloc(args->size + 16, M_CPUCTL, M_ZERO | M_WAITOK);
-	if (copyin(args->data, ptr, args->size) != 0) {
+	d.ptr = malloc(args->size + 16, M_CPUCTL, M_ZERO | M_WAITOK);
+	if (copyin(args->data, d.ptr, args->size) != 0) {
 		DPRINTF("[cpuctl,%d]: copyin %p->%p of %zd bytes failed",
 		    __LINE__, args->data, ptr, args->size);
-		ret = EFAULT;
+		d.ret = EFAULT;
 		goto fail;
 	}
-	smp_rendezvous(NULL, amd_ucode_wrmsr, NULL, ptr);
-	ret = 0;
+	smp_rendezvous(NULL, amd_ucode_wrmsr, NULL, &d);
 fail:
-	free(ptr, M_CPUCTL);
-	return (ret);
+	free(d.ptr, M_CPUCTL);
+	return (d.ret);
 }
 
 static int