diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1830,6 +1830,56 @@ : "cc", "memory"); } +extern const char wrmsr_early_safe_gp_handler[]; +static uint64_t orig_gp_handler; + +static struct gate_descriptor * +wrmsr_early_get_gp_descr(void) +{ + struct region_descriptor efi_idt; + struct gate_descriptor *gpf_descr; + + lidt(&efi_idt); + return ((void *)(uintptr_t)(efi_idt.rd_base + + sizeof(*gpf_descr) * IDT_GP)); +} + +static void +wrmsr_early_set_gp_handler(uint64_t h) +{ + struct gate_descriptor *gpf_descr; + + gpf_descr = wrmsr_early_get_gp_descr(); + gpf_descr->gd_looffset = h; + gpf_descr->gd_hioffset = h >> 16; +} + +static uint64_t +wrmsr_early_get_gp_handler(void) +{ + struct gate_descriptor *gpf_descr; + uint64_t res; + + gpf_descr = wrmsr_early_get_gp_descr(); + res = gpf_descr->gd_hioffset; + res <<= 16; + res |= gpf_descr->gd_looffset; + return (res); +} + +void +wrmsr_early_safe_start(void) +{ + orig_gp_handler = wrmsr_early_get_gp_handler(); + wrmsr_early_set_gp_handler((uintptr_t)wrmsr_early_safe_gp_handler); +} + +void +wrmsr_early_safe_end(void) +{ + wrmsr_early_set_gp_handler(orig_gp_handler); +} + #ifdef KDB /* diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S --- a/sys/amd64/amd64/support.S +++ b/sys/amd64/amd64/support.S @@ -1565,6 +1565,25 @@ POP_FRAME_POINTER ret +ENTRY(wrmsr_early_safe) + movl %edi,%ecx + movl %esi,%eax + sarq $32,%rsi + movl %esi,%edx +wrmsrF: wrmsr + xorl %eax,%eax + POP_FRAME_POINTER + ret + +ENTRY(wrmsr_early_faulted) + movl $EFAULT,%eax + POP_FRAME_POINTER + ret + +ENTRY(wrmsr_early_safe_gp_handler) + movq $wrmsr_early_faulted,8(%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 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -100,6 +100,10 @@ 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__ */