Index: head/lib/libc/sys/ptrace.2 =================================================================== --- head/lib/libc/sys/ptrace.2 +++ head/lib/libc/sys/ptrace.2 @@ -2,7 +2,7 @@ .\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $ .\" .\" This file is in the public domain. -.Dd May 22, 2018 +.Dd June 2, 2018 .Dt PTRACE 2 .Os .Sh NAME @@ -934,6 +934,24 @@ Set the thread's .Dv ALTIVEC machine state from the buffer pointed to by +.Fa addr . +.Pp +The +.Fa data +argument is ignored. +.It Dv PT_GETVSRREGS +Return doubleword 1 of the thread's +.Dv VSX +registers VSR0-VSR31 in the buffer pointed to by +.Fa addr . +.Pp +The +.Fa data +argument is ignored. +.It Dv PT_SETVSRREGS +Set doubleword 1 of the thread's +.Dv VSX +registers VSR0-VSR31 from the buffer pointed to by .Fa addr . .Pp The Index: head/sys/powerpc/include/fpu.h =================================================================== --- head/sys/powerpc/include/fpu.h +++ head/sys/powerpc/include/fpu.h @@ -74,6 +74,7 @@ void enable_fpu(struct thread *); void save_fpu(struct thread *); +void save_fpu_nodrop(struct thread *); #endif /* _KERNEL */ Index: head/sys/powerpc/include/ptrace.h =================================================================== --- head/sys/powerpc/include/ptrace.h +++ head/sys/powerpc/include/ptrace.h @@ -39,5 +39,7 @@ #define PT_GETVRREGS (PT_FIRSTMACH + 0) #define PT_SETVRREGS (PT_FIRSTMACH + 1) +#define PT_GETVSRREGS (PT_FIRSTMACH + 2) +#define PT_SETVSRREGS (PT_FIRSTMACH + 3) #endif Index: head/sys/powerpc/powerpc/fpu.c =================================================================== --- head/sys/powerpc/powerpc/fpu.c +++ head/sys/powerpc/powerpc/fpu.c @@ -45,6 +45,60 @@ #include #include +static void +save_fpu_int(struct thread *td) +{ + int msr; + struct pcb *pcb; + + pcb = td->td_pcb; + + /* + * Temporarily re-enable floating-point during the save + */ + msr = mfmsr(); + if (pcb->pcb_flags & PCB_VSX) + mtmsr(msr | PSL_FP | PSL_VSX); + else + mtmsr(msr | PSL_FP); + + /* + * Save the floating-point registers and FPSCR to the PCB + */ + if (pcb->pcb_flags & PCB_VSX) { + #define SFP(n) __asm ("stxvw4x " #n ", 0,%0" \ + :: "b"(&pcb->pcb_fpu.fpr[n])); + SFP(0); SFP(1); SFP(2); SFP(3); + SFP(4); SFP(5); SFP(6); SFP(7); + SFP(8); SFP(9); SFP(10); SFP(11); + SFP(12); SFP(13); SFP(14); SFP(15); + SFP(16); SFP(17); SFP(18); SFP(19); + SFP(20); SFP(21); SFP(22); SFP(23); + SFP(24); SFP(25); SFP(26); SFP(27); + SFP(28); SFP(29); SFP(30); SFP(31); + #undef SFP + } else { + #define SFP(n) __asm ("stfd " #n ", 0(%0)" \ + :: "b"(&pcb->pcb_fpu.fpr[n])); + SFP(0); SFP(1); SFP(2); SFP(3); + SFP(4); SFP(5); SFP(6); SFP(7); + SFP(8); SFP(9); SFP(10); SFP(11); + SFP(12); SFP(13); SFP(14); SFP(15); + SFP(16); SFP(17); SFP(18); SFP(19); + SFP(20); SFP(21); SFP(22); SFP(23); + SFP(24); SFP(25); SFP(26); SFP(27); + SFP(28); SFP(29); SFP(30); SFP(31); + #undef SFP + } + __asm __volatile ("mffs 0; stfd 0,0(%0)" :: "b"(&pcb->pcb_fpu.fpscr)); + + /* + * Disable floating-point again + */ + isync(); + mtmsr(msr); +} + void enable_fpu(struct thread *td) { @@ -129,57 +183,13 @@ void save_fpu(struct thread *td) { - int msr; struct pcb *pcb; pcb = td->td_pcb; - /* - * Temporarily re-enable floating-point during the save - */ - msr = mfmsr(); - if (pcb->pcb_flags & PCB_VSX) - mtmsr(msr | PSL_FP | PSL_VSX); - else - mtmsr(msr | PSL_FP); + save_fpu_int(td); /* - * Save the floating-point registers and FPSCR to the PCB - */ - if (pcb->pcb_flags & PCB_VSX) { - #define SFP(n) __asm ("stxvw4x " #n ", 0,%0" \ - :: "b"(&pcb->pcb_fpu.fpr[n])); - SFP(0); SFP(1); SFP(2); SFP(3); - SFP(4); SFP(5); SFP(6); SFP(7); - SFP(8); SFP(9); SFP(10); SFP(11); - SFP(12); SFP(13); SFP(14); SFP(15); - SFP(16); SFP(17); SFP(18); SFP(19); - SFP(20); SFP(21); SFP(22); SFP(23); - SFP(24); SFP(25); SFP(26); SFP(27); - SFP(28); SFP(29); SFP(30); SFP(31); - #undef SFP - } else { - #define SFP(n) __asm ("stfd " #n ", 0(%0)" \ - :: "b"(&pcb->pcb_fpu.fpr[n])); - SFP(0); SFP(1); SFP(2); SFP(3); - SFP(4); SFP(5); SFP(6); SFP(7); - SFP(8); SFP(9); SFP(10); SFP(11); - SFP(12); SFP(13); SFP(14); SFP(15); - SFP(16); SFP(17); SFP(18); SFP(19); - SFP(20); SFP(21); SFP(22); SFP(23); - SFP(24); SFP(25); SFP(26); SFP(27); - SFP(28); SFP(29); SFP(30); SFP(31); - #undef SFP - } - __asm __volatile ("mffs 0; stfd 0,0(%0)" :: "b"(&pcb->pcb_fpu.fpscr)); - - /* - * Disable floating-point again - */ - isync(); - mtmsr(msr); - - /* * Clear the current fp thread and pcb's CPU id * XXX should this be left clear to allow lazy save/restore ? */ @@ -187,3 +197,19 @@ PCPU_SET(fputhread, NULL); } +/* + * Save fpu state without dropping ownership. This will only save state if + * the current fpu thread is `td'. + */ +void +save_fpu_nodrop(struct thread *td) +{ + struct thread *ftd; + + ftd = PCPU_GET(fputhread); + if (td != ftd) { + return; + } + + save_fpu_int(td); +} Index: head/sys/powerpc/powerpc/ptrace_machdep.c =================================================================== --- head/sys/powerpc/powerpc/ptrace_machdep.c +++ head/sys/powerpc/powerpc/ptrace_machdep.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -45,10 +46,14 @@ int error; struct pcb *pcb; struct vec vec; + uint64_t vsr[32]; + uint64_t *vsr_dw1; + int vsr_idx; pcb = td->td_pcb; bzero(&vec, sizeof(vec)); + bzero(vsr, sizeof(vsr)); error = EINVAL; switch (req) { @@ -69,6 +74,43 @@ if (error == 0) { pcb->pcb_flags |= PCB_VEC; memcpy(&pcb->pcb_vec, &vec, sizeof(vec)); + } + break; + case PT_GETVSRREGS: + if (!(cpu_features & PPC_FEATURE_HAS_VSX)) + break; + + if (pcb->pcb_flags & PCB_VSX) { + save_fpu_nodrop(td); + + /* + * Doubleword 0 of VSR0-VSR31 overlap with FPR0-FPR31 and + * VSR32-VSR63 overlap with VR0-VR31, so we only copy + * the non-overlapping data, which is doubleword 1 of VSR0-VSR31. + */ + for (vsr_idx = 0; vsr_idx < nitems(vsr); vsr_idx++) { + vsr_dw1 = (uint64_t *)&pcb->pcb_fpu.fpr[vsr_idx].vsr[2]; + vsr[vsr_idx] = *vsr_dw1; + } + } + error = copyout(&vsr, addr, sizeof(vsr)); + break; + case PT_SETVSRREGS: + if (!(cpu_features & PPC_FEATURE_HAS_VSX)) + break; + error = copyin(addr, &vsr, sizeof(vsr)); + if (error == 0) { + pcb->pcb_flags |= PCB_VSX; + + /* + * Doubleword 0 of VSR0-VSR31 overlap with FPR0-FPR31 and + * VSR32-VSR63 overlap with VR0-VR31, so we only copy + * the non-overlapping data, which is doubleword 1 of VSR0-VSR31. + */ + for (vsr_idx = 0; vsr_idx < nitems(vsr); vsr_idx++) { + vsr_dw1 = (uint64_t *)&pcb->pcb_fpu.fpr[vsr_idx].vsr[2]; + *vsr_dw1 = vsr[vsr_idx]; + } } break;