powerpc/64: Interrupts save PPR on stack rather than thread_struct
PPR is the odd register out when it comes to interrupt handling, it is saved in current->thread.ppr while all others are saved on the stack. The difficulty with this is that accessing thread.ppr can cause a SLB fault, but the SLB fault handler implementation in C change had assumed the normal exception entry handlers would not cause an SLB fault. Fix this by allocating room in the interrupt stack to save PPR. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:

committed by
Michael Ellerman

parent
3eeacd9f4e
commit
4c2de74cc8
@@ -89,7 +89,6 @@ int main(void)
|
||||
#ifdef CONFIG_PPC64
|
||||
DEFINE(SIGSEGV, SIGSEGV);
|
||||
DEFINE(NMI_MASK, NMI_MASK);
|
||||
OFFSET(TASKTHREADPPR, task_struct, thread.ppr);
|
||||
#else
|
||||
OFFSET(THREAD_INFO, task_struct, stack);
|
||||
DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16));
|
||||
@@ -323,6 +322,7 @@ int main(void)
|
||||
STACK_PT_REGS_OFFSET(_ESR, dsisr);
|
||||
#else /* CONFIG_PPC64 */
|
||||
STACK_PT_REGS_OFFSET(SOFTE, softe);
|
||||
STACK_PT_REGS_OFFSET(_PPR, ppr);
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
#if defined(CONFIG_PPC32)
|
||||
|
@@ -386,10 +386,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
|
||||
4: /* Anything else left to do? */
|
||||
BEGIN_FTR_SECTION
|
||||
lis r3,INIT_PPR@highest /* Set thread.ppr = 3 */
|
||||
ld r10,PACACURRENT(r13)
|
||||
lis r3,DEFAULT_PPR@highest /* Set default PPR */
|
||||
sldi r3,r3,32 /* bits 11-13 are used for ppr */
|
||||
std r3,TASKTHREADPPR(r10)
|
||||
std r3,_PPR(r1)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
|
||||
andi. r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP)
|
||||
@@ -942,12 +941,6 @@ fast_exception_return:
|
||||
andi. r0,r3,MSR_RI
|
||||
beq- .Lunrecov_restore
|
||||
|
||||
/* Load PPR from thread struct before we clear MSR:RI */
|
||||
BEGIN_FTR_SECTION
|
||||
ld r2,PACACURRENT(r13)
|
||||
ld r2,TASKTHREADPPR(r2)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
|
||||
/*
|
||||
* Clear RI before restoring r13. If we are returning to
|
||||
* userspace and we take an exception after restoring r13,
|
||||
@@ -968,7 +961,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
andi. r0,r3,MSR_PR
|
||||
beq 1f
|
||||
BEGIN_FTR_SECTION
|
||||
mtspr SPRN_PPR,r2 /* Restore PPR */
|
||||
/* Restore PPR */
|
||||
ld r2,_PPR(r1)
|
||||
mtspr SPRN_PPR,r2
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
ACCOUNT_CPU_USER_EXIT(r13, r2, r4)
|
||||
REST_GPR(13, r1)
|
||||
|
@@ -1710,7 +1710,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||
p->thread.dscr = mfspr(SPRN_DSCR);
|
||||
}
|
||||
if (cpu_has_feature(CPU_FTR_HAS_PPR))
|
||||
p->thread.ppr = INIT_PPR;
|
||||
childregs->ppr = DEFAULT_PPR;
|
||||
|
||||
p->thread.tidr = 0;
|
||||
#endif
|
||||
|
@@ -1609,7 +1609,7 @@ static int ppr_get(struct task_struct *target,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.ppr, 0, sizeof(u64));
|
||||
&target->thread.regs->ppr, 0, sizeof(u64));
|
||||
}
|
||||
|
||||
static int ppr_set(struct task_struct *target,
|
||||
@@ -1618,7 +1618,7 @@ static int ppr_set(struct task_struct *target,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.ppr, 0, sizeof(u64));
|
||||
&target->thread.regs->ppr, 0, sizeof(u64));
|
||||
}
|
||||
|
||||
static int dscr_get(struct task_struct *target,
|
||||
|
Reference in New Issue
Block a user