diff options
| author | David S. Miller <davem@davemloft.net> | 2013-02-20 12:38:40 -0800 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-02-20 13:34:41 -0800 | 
| commit | 76968ad2eac6456270353de168b21f04f4b3d1d3 (patch) | |
| tree | b5181645596ff9cce2e250bdf5de10948868a01e /arch/sparc/include/asm/tsb.h | |
| parent | 0fbebed682ff2788dee58e8d7f7dda46e33aa10b (diff) | |
sparc64: Fix huge PMD to PTE translation for sun4u in TLB miss handler.
When we set the sun4u version of the PTE execute bit, it's:
	or	REG, _PAGE_EXEC_4U, REG
_PAGE_EXEC_4U is 0x1000, unfortunately the immedate field of the
'or' instruction is a signed 13-bit value.  So the above actually
assembles into:
	or	REG, -4096, REG
completely corrupting the final PTE value.
Set it with a:
	sethi	%hi(_PAGE_EXEC_4U), TMP
	or	REG, TMP, REG
sequence instead.
This fixes "git gc" crashes on sun4u machines.
Reported-by: Meelis Roos <mroos@linux.ee>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/include/asm/tsb.h')
| -rw-r--r-- | arch/sparc/include/asm/tsb.h | 28 | 
1 files changed, 19 insertions, 9 deletions
| diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h index b4c258de4443..e696432b950d 100644 --- a/arch/sparc/include/asm/tsb.h +++ b/arch/sparc/include/asm/tsb.h @@ -157,17 +157,26 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;  	andn		REG2, 0x7, REG2; \  	add		REG1, REG2, REG1; -	/* This macro exists only to make the PMD translator below easier -	 * to read.  It hides the ELF section switch for the sun4v code -	 * patching. +	/* These macros exists only to make the PMD translator below +	 * easier to read.  It hides the ELF section switch for the +	 * sun4v code patching.  	 */ -#define OR_PTE_BIT(REG, NAME)				\ +#define OR_PTE_BIT_1INSN(REG, NAME)			\  661:	or		REG, _PAGE_##NAME##_4U, REG;	\  	.section	.sun4v_1insn_patch, "ax";	\  	.word		661b;				\  	or		REG, _PAGE_##NAME##_4V, REG;	\  	.previous; +#define OR_PTE_BIT_2INSN(REG, TMP, NAME)		\ +661:	sethi		%hi(_PAGE_##NAME##_4U), TMP;	\ +	or		REG, TMP, REG;			\ +	.section	.sun4v_2insn_patch, "ax";	\ +	.word		661b;				\ +	mov		-1, TMP;			\ +	or		REG, _PAGE_##NAME##_4V, REG;	\ +	.previous; +  	/* Load into REG the PTE value for VALID, CACHE, and SZHUGE.  */  #define BUILD_PTE_VALID_SZHUGE_CACHE(REG)				   \  661:	sethi		%uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG;		   \ @@ -214,12 +223,13 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;  	 andn		REG1, PMD_HUGE_PROTBITS, REG2;			      \  	sllx		REG2, PMD_PADDR_SHIFT, REG2;			      \  	/* REG2 now holds PFN << PAGE_SHIFT */				      \ -	andcc		REG1, PMD_HUGE_EXEC, %g0;			      \ -	bne,a,pt	%xcc, 1f;					      \ -	 OR_PTE_BIT(REG2, EXEC);					      \ -1:	andcc		REG1, PMD_HUGE_WRITE, %g0;			      \ +	andcc		REG1, PMD_HUGE_WRITE, %g0;			      \  	bne,a,pt	%xcc, 1f;					      \ -	 OR_PTE_BIT(REG2, W);						      \ +	 OR_PTE_BIT_1INSN(REG2, W);					      \ +1:	andcc		REG1, PMD_HUGE_EXEC, %g0;			      \ +	be,pt		%xcc, 1f;					      \ +	 nop;								      \ +	OR_PTE_BIT_2INSN(REG2, REG1, EXEC);				      \  	/* REG1 can now be clobbered, build final PTE */		      \  1:	BUILD_PTE_VALID_SZHUGE_CACHE(REG1);				      \  	ba,pt		%xcc, PTE_LABEL;				      \ | 
