diff --git a/sys/arch/amd64/amd64/cpufunc.S b/sys/arch/amd64/amd64/cpufunc.S index 9aa328a9df6a..1d78c4cf710e 100644 --- a/sys/arch/amd64/amd64/cpufunc.S +++ b/sys/arch/amd64/amd64/cpufunc.S @@ -398,11 +398,16 @@ ENTRY(x86_mwait) ret END(x86_mwait) +ENTRY(clts) + clts + jmp _C_LABEL(stts_clts_record) +END(clts) + ENTRY(stts) movq %cr0, %rax orq $CR0_TS, %rax movq %rax, %cr0 - ret + jmp _C_LABEL(stts_clts_record) END(stts) ENTRY(fldummy) diff --git a/sys/arch/i386/i386/cpufunc.S b/sys/arch/i386/i386/cpufunc.S index 931f0962aa27..dc341c5ca622 100644 --- a/sys/arch/i386/i386/cpufunc.S +++ b/sys/arch/i386/i386/cpufunc.S @@ -297,6 +297,11 @@ ENTRY(x86_mwait) ret END(x86_mwait) +ENTRY(clts) + clts + jmp _C_LABEL(stts_clts_record) +END(clts) + ENTRY(stts) movl %cr0, %eax testl $CR0_TS, %eax @@ -304,7 +309,7 @@ ENTRY(stts) orl $CR0_TS, %eax movl %eax, %cr0 1: - ret + jmp _C_LABEL(stts_clts_record) END(stts) ENTRY(fldummy) diff --git a/sys/arch/x86/include/cpufunc.h b/sys/arch/x86/include/cpufunc.h index 524b8db6d867..3d701fd86c2d 100644 --- a/sys/arch/x86/include/cpufunc.h +++ b/sys/arch/x86/include/cpufunc.h @@ -327,12 +327,7 @@ fnstsw(uint16_t *val) ); } -static inline void -clts(void) -{ - __asm volatile ("clts" ::: "memory"); -} - +void clts(void); void stts(void); static inline void diff --git a/sys/arch/x86/x86/fpu.c b/sys/arch/x86/x86/fpu.c index 6730a1febce7..5f0ae59f5e34 100644 --- a/sys/arch/x86/x86/fpu.c +++ b/sys/arch/x86/x86/fpu.c @@ -576,12 +576,49 @@ fputrap(struct trapframe *frame) (*curlwp->l_proc->p_emul->e_trapsignal)(curlwp, &ksi); } +static vaddr_t last_stts_clts[MAXCPUS]; + +void stts_clts_record(void); +void +stts_clts_record(void) +{ + + last_stts_clts[cpu_number()] = (vaddr_t)__builtin_return_address(0); +} + +#include +#include + void fpudna(struct trapframe *frame) { - panic("fpudna from %s, ip %p, trapframe %p", + vaddr_t addr = last_stts_clts[cpu_number()]; + const char *mod, *sym; + char buf[128]; + int s; + + s = pserialize_read_enter(); + if (ksyms_getname(&mod, &sym, addr, KSYMS_PROC|KSYMS_CLOSEST) == 0) { + unsigned long naddr; + char offset[32]; + + if (ksyms_getval(mod, sym, &naddr, KSYMS_ANY) == 0 && + (addr - naddr) != 0) { + snprintf(offset, sizeof(offset), "+%p", + (void *)(addr - naddr)); + } else { + offset[0] = '\0'; + } + snprintf(buf, sizeof(buf), "%s:%s%s", mod, sym, offset); + } else { + snprintf(buf, sizeof(buf), "%"PRIxVADDR, addr); + } + pserialize_read_exit(s); + + panic("fpudna from %s, ip %p, trapframe %p, cr0 0x%"PRIxREGISTER"," + " last stts/clts %s", USERMODE(frame->tf_cs) ? "userland" : "kernel", - (void *)X86_TF_RIP(frame), frame); + (void *)X86_TF_RIP(frame), frame, rcr0(), buf); } /* -------------------------------------------------------------------------- */