The branch main has been updated by kib:

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

commit a319696875451229f492b6c15e58a0ac54dbcda1
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2025-09-18 21:55:19 +0000
Commit:     Konstantin Belousov <k...@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__ */

Reply via email to