aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/include
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-02-20 15:38:40 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-20 16:34:41 -0500
commit76968ad2eac6456270353de168b21f04f4b3d1d3 (patch)
treeb5181645596ff9cce2e250bdf5de10948868a01e /arch/sparc/include
parent0fbebed682ff2788dee58e8d7f7dda46e33aa10b (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')
-rw-r--r--arch/sparc/include/asm/tsb.h28
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;
157 andn REG2, 0x7, REG2; \ 157 andn REG2, 0x7, REG2; \
158 add REG1, REG2, REG1; 158 add REG1, REG2, REG1;
159 159
160 /* This macro exists only to make the PMD translator below easier 160 /* These macros exists only to make the PMD translator below
161 * to read. It hides the ELF section switch for the sun4v code 161 * easier to read. It hides the ELF section switch for the
162 * patching. 162 * sun4v code patching.
163 */ 163 */
164#define OR_PTE_BIT(REG, NAME) \ 164#define OR_PTE_BIT_1INSN(REG, NAME) \
165661: or REG, _PAGE_##NAME##_4U, REG; \ 165661: or REG, _PAGE_##NAME##_4U, REG; \
166 .section .sun4v_1insn_patch, "ax"; \ 166 .section .sun4v_1insn_patch, "ax"; \
167 .word 661b; \ 167 .word 661b; \
168 or REG, _PAGE_##NAME##_4V, REG; \ 168 or REG, _PAGE_##NAME##_4V, REG; \
169 .previous; 169 .previous;
170 170
171#define OR_PTE_BIT_2INSN(REG, TMP, NAME) \
172661: sethi %hi(_PAGE_##NAME##_4U), TMP; \
173 or REG, TMP, REG; \
174 .section .sun4v_2insn_patch, "ax"; \
175 .word 661b; \
176 mov -1, TMP; \
177 or REG, _PAGE_##NAME##_4V, REG; \
178 .previous;
179
171 /* Load into REG the PTE value for VALID, CACHE, and SZHUGE. */ 180 /* Load into REG the PTE value for VALID, CACHE, and SZHUGE. */
172#define BUILD_PTE_VALID_SZHUGE_CACHE(REG) \ 181#define BUILD_PTE_VALID_SZHUGE_CACHE(REG) \
173661: sethi %uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG; \ 182661: 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;
214 andn REG1, PMD_HUGE_PROTBITS, REG2; \ 223 andn REG1, PMD_HUGE_PROTBITS, REG2; \
215 sllx REG2, PMD_PADDR_SHIFT, REG2; \ 224 sllx REG2, PMD_PADDR_SHIFT, REG2; \
216 /* REG2 now holds PFN << PAGE_SHIFT */ \ 225 /* REG2 now holds PFN << PAGE_SHIFT */ \
217 andcc REG1, PMD_HUGE_EXEC, %g0; \ 226 andcc REG1, PMD_HUGE_WRITE, %g0; \
218 bne,a,pt %xcc, 1f; \
219 OR_PTE_BIT(REG2, EXEC); \
2201: andcc REG1, PMD_HUGE_WRITE, %g0; \
221 bne,a,pt %xcc, 1f; \ 227 bne,a,pt %xcc, 1f; \
222 OR_PTE_BIT(REG2, W); \ 228 OR_PTE_BIT_1INSN(REG2, W); \
2291: andcc REG1, PMD_HUGE_EXEC, %g0; \
230 be,pt %xcc, 1f; \
231 nop; \
232 OR_PTE_BIT_2INSN(REG2, REG1, EXEC); \
223 /* REG1 can now be clobbered, build final PTE */ \ 233 /* REG1 can now be clobbered, build final PTE */ \
2241: BUILD_PTE_VALID_SZHUGE_CACHE(REG1); \ 2341: BUILD_PTE_VALID_SZHUGE_CACHE(REG1); \
225 ba,pt %xcc, PTE_LABEL; \ 235 ba,pt %xcc, PTE_LABEL; \