Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Sep 2025 13:02:47 GMT
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: a31969687545 - main - amd64: add wrmsr_early_safe(9)
Message-ID:  <202509241302.58OD2lKo034437@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kib:

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

commit a319696875451229f492b6c15e58a0ac54dbcda1
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-09-18 21:55:19 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-09-24 13:02:27 +0000

    amd64: add wrmsr_early_safe(9)
    
    The variant of wrmsr_safe(9) that might work before IDT and curpcb are
    initialized.  Assumes BSP, and that all APs are parked.
    
    Before calling wrmsr_early_safe(), the wrmsr_early_safe_start() should
    be called, afterward wrmsr_early_safe_end() restores the bootenv IDT.
    
    Reviewed by:    markj
    Tested by:      glebius
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D52607
---
 sys/amd64/amd64/machdep.c  | 33 +++++++++++++++++++++++++++++++++
 sys/amd64/amd64/support.S  | 16 ++++++++++++++++
 sys/amd64/include/md_var.h |  4 ++++
 3 files changed, 53 insertions(+)

diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 9ff60439d1ec..2fce1a7e64b6 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1822,6 +1822,39 @@ clear_pcb_flags(struct pcb *pcb, const u_int flags)
 	    : "cc", "memory");
 }
 
+extern const char wrmsr_early_safe_gp_handler[];
+static struct region_descriptor wrmsr_early_safe_orig_efi_idt;
+
+void
+wrmsr_early_safe_start(void)
+{
+	struct region_descriptor efi_idt;
+	struct gate_descriptor *gpf_descr;
+
+	sidt(&wrmsr_early_safe_orig_efi_idt);
+	efi_idt.rd_limit = 32 * sizeof(idt0[0]);
+	efi_idt.rd_base = (uintptr_t)idt0;
+	lidt(&efi_idt);
+
+	gpf_descr = &idt0[IDT_GP];
+	gpf_descr->gd_looffset = (uintptr_t)wrmsr_early_safe_gp_handler;
+	gpf_descr->gd_hioffset = (uintptr_t)wrmsr_early_safe_gp_handler >> 16;
+	gpf_descr->gd_selector = rcs();
+	gpf_descr->gd_type = SDT_SYSTGT;
+	gpf_descr->gd_p = 1;
+}
+
+void
+wrmsr_early_safe_end(void)
+{
+	struct gate_descriptor *gpf_descr;
+
+	lidt(&wrmsr_early_safe_orig_efi_idt);
+
+	gpf_descr = &idt0[IDT_GP];
+	memset(gpf_descr, 0, sizeof(*gpf_descr));
+}
+
 #ifdef KDB
 
 /*
diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S
index 870cd255abb7..27694a95653c 100644
--- a/sys/amd64/amd64/support.S
+++ b/sys/amd64/amd64/support.S
@@ -1565,6 +1565,22 @@ msr_onfault:
 	POP_FRAME_POINTER
 	ret
 
+ENTRY(wrmsr_early_safe)
+	movl	%edi,%ecx
+	movl	%esi,%eax
+	sarq	$32,%rsi
+	movl	%esi,%edx
+	wrmsr
+	xorl	%eax,%eax
+wrmsr_early_faulted:
+	ret
+
+ENTRY(wrmsr_early_safe_gp_handler)
+	addq	$8,%rsp
+	movl	$EFAULT,%eax
+	movq	$wrmsr_early_faulted,(%rsp)
+	iretq
+
 /*
  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
  * Invalidates address space addressed by ucr3, then returns to kcr3.
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index b6ddc6eaaebe..b6d8c469cdf6 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -99,6 +99,10 @@ void	get_fpcontext(struct thread *td, struct __mcontext *mcp,
 int	set_fpcontext(struct thread *td, struct __mcontext *mcp,
 	    char *xfpustate, size_t xfpustate_len);
 
+void	wrmsr_early_safe_start(void);
+void	wrmsr_early_safe_end(void);
+int	wrmsr_early_safe(u_int msr, uint64_t data);
+
 #endif /* !_MACHINE_MD_VAR_H_ */
 
 #endif /* __i386__ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509241302.58OD2lKo034437>