mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									3eeacd9f4e
								
							
						
					
					
						commit
						4c2de74cc8
					
				
					 7 changed files with 19 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -236,11 +236,10 @@
 | 
			
		|||
 * PPR save/restore macros used in exceptions_64s.S  
 | 
			
		||||
 * Used for P7 or later processors
 | 
			
		||||
 */
 | 
			
		||||
#define SAVE_PPR(area, ra, rb)						\
 | 
			
		||||
#define SAVE_PPR(area, ra)						\
 | 
			
		||||
BEGIN_FTR_SECTION_NESTED(940)						\
 | 
			
		||||
	ld	ra,PACACURRENT(r13);					\
 | 
			
		||||
	ld	rb,area+EX_PPR(r13);	/* Read PPR from paca */	\
 | 
			
		||||
	std	rb,TASKTHREADPPR(ra);					\
 | 
			
		||||
	ld	ra,area+EX_PPR(r13);	/* Read PPR from paca */	\
 | 
			
		||||
	std	ra,_PPR(r1);						\
 | 
			
		||||
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,940)
 | 
			
		||||
 | 
			
		||||
#define RESTORE_PPR_PACA(area, ra)					\
 | 
			
		||||
| 
						 | 
				
			
			@ -508,7 +507,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
 | 
			
		|||
3:	EXCEPTION_PROLOG_COMMON_1();					   \
 | 
			
		||||
	beq	4f;			/* if from kernel mode		*/ \
 | 
			
		||||
	ACCOUNT_CPU_USER_ENTRY(r13, r9, r10);				   \
 | 
			
		||||
	SAVE_PPR(area, r9, r10);					   \
 | 
			
		||||
	SAVE_PPR(area, r9);						   \
 | 
			
		||||
4:	EXCEPTION_PROLOG_COMMON_2(area)					   \
 | 
			
		||||
	EXCEPTION_PROLOG_COMMON_3(n)					   \
 | 
			
		||||
	ACCOUNT_STOLEN_TIME
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,9 +32,9 @@
 | 
			
		|||
/* Default SMT priority is set to 3. Use 11- 13bits to save priority. */
 | 
			
		||||
#define PPR_PRIORITY 3
 | 
			
		||||
#ifdef __ASSEMBLY__
 | 
			
		||||
#define INIT_PPR (PPR_PRIORITY << 50)
 | 
			
		||||
#define DEFAULT_PPR (PPR_PRIORITY << 50)
 | 
			
		||||
#else
 | 
			
		||||
#define INIT_PPR ((u64)PPR_PRIORITY << 50)
 | 
			
		||||
#define DEFAULT_PPR ((u64)PPR_PRIORITY << 50)
 | 
			
		||||
#endif /* __ASSEMBLY__ */
 | 
			
		||||
#endif /* CONFIG_PPC64 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -341,7 +341,6 @@ struct thread_struct {
 | 
			
		|||
	 * onwards.
 | 
			
		||||
	 */
 | 
			
		||||
	int		dscr_inherit;
 | 
			
		||||
	unsigned long	ppr;	/* used to save/restore SMT priority */
 | 
			
		||||
	unsigned long	tidr;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_PPC_BOOK3S_64
 | 
			
		||||
| 
						 | 
				
			
			@ -389,7 +388,6 @@ struct thread_struct {
 | 
			
		|||
	.regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
 | 
			
		||||
	.addr_limit = KERNEL_DS, \
 | 
			
		||||
	.fpexc_mode = 0, \
 | 
			
		||||
	.ppr = INIT_PPR, \
 | 
			
		||||
	.fscr = FSCR_TAR | FSCR_EBB \
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,10 @@ struct pt_regs
 | 
			
		|||
			unsigned long result;
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PPC64
 | 
			
		||||
	unsigned long ppr;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue