sun4v_tlb_miss.S 10.5 KB
Newer Older
1 2 3 4 5 6 7 8
/* sun4v_tlb_miss.S: Sun4v TLB miss handlers.
 *
 * Copyright (C) 2006 <davem@davemloft.net>
 */

	.text
	.align	32

9 10 11 12 13 14 15 16 17
	/* Load ITLB fault information into VADDR and CTX, using BASE.  */
#define LOAD_ITLB_INFO(BASE, VADDR, CTX) \
	ldx	[BASE + HV_FAULT_I_ADDR_OFFSET], VADDR; \
	ldx	[BASE + HV_FAULT_I_CTX_OFFSET], CTX;

	/* Load DTLB fault information into VADDR and CTX, using BASE.  */
#define LOAD_DTLB_INFO(BASE, VADDR, CTX) \
	ldx	[BASE + HV_FAULT_D_ADDR_OFFSET], VADDR; \
	ldx	[BASE + HV_FAULT_D_CTX_OFFSET], CTX;
18

19
	/* DEST = (VADDR >> 22)
20
	 *
21
	 * Branch to ZERO_CTX_LABEL if context is zero.
22
	 */
23 24
#define	COMPUTE_TAG_TARGET(DEST, VADDR, CTX, ZERO_CTX_LABEL) \
	srlx	VADDR, 22, DEST; \
25
	brz,pn	CTX, ZERO_CTX_LABEL; \
26
	 nop;
27 28 29 30 31

	/* Create TSB pointer.  This is something like:
	 *
	 * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
	 * tsb_base = tsb_reg & ~0x7UL;
32
	 * tsb_index = ((vaddr >> HASH_SHIFT) & tsb_mask);
33 34
	 * tsb_ptr = tsb_base + (tsb_index * 16);
	 */
35
#define COMPUTE_TSB_PTR(TSB_PTR, VADDR, HASH_SHIFT, TMP1, TMP2) \
36 37 38 39
	and	TSB_PTR, 0x7, TMP1;			\
	mov	512, TMP2;				\
	andn	TSB_PTR, 0x7, TSB_PTR;			\
	sllx	TMP2, TMP1, TMP2;			\
40
	srlx	VADDR, HASH_SHIFT, TMP1;		\
41 42 43 44 45 46 47 48 49 50 51 52 53 54
	sub	TMP2, 1, TMP2;				\
	and	TMP1, TMP2, TMP1;			\
	sllx	TMP1, 4, TMP1;				\
	add	TSB_PTR, TMP1, TSB_PTR;

sun4v_itlb_miss:
	/* Load MMU Miss base into %g2.  */
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	
	/* Load UTSB reg into %g1.  */
	mov	SCRATCHPAD_UTSBREG1, %g1
	ldxa	[%g1] ASI_SCRATCHPAD, %g1

	LOAD_ITLB_INFO(%g2, %g4, %g5)
55
	COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_itlb_4v)
56
	COMPUTE_TSB_PTR(%g1, %g4, PAGE_SHIFT, %g3, %g7)
57 58

	/* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
59
	ldda	[%g1] ASI_QUAD_LDD_PHYS_4V, %g2
60 61 62
	cmp	%g2, %g6
	bne,a,pn %xcc, tsb_miss_page_table_walk
	 mov	FAULT_CODE_ITLB, %g3
63
	andcc	%g3, _PAGE_EXEC_4V, %g0
64 65 66 67 68 69 70 71 72 73
	be,a,pn	%xcc, tsb_do_fault
	 mov	FAULT_CODE_ITLB, %g3

	/* We have a valid entry, make hypervisor call to load
	 * I-TLB and return from trap.
	 *
	 * %g3:	PTE
	 * %g4:	vaddr
	 */
sun4v_itlb_load:
74
	ldxa	[%g0] ASI_SCRATCHPAD, %g6
75 76 77 78 79
	mov	%o0, %g1		! save %o0
	mov	%o1, %g2		! save %o1
	mov	%o2, %g5		! save %o2
	mov	%o3, %g7		! save %o3
	mov	%g4, %o0		! vaddr
80
	ldx	[%g6 + HV_FAULT_I_CTX_OFFSET], %o1	! ctx
81 82 83
	mov	%g3, %o2		! PTE
	mov	HV_MMU_IMMU, %o3	! flags
	ta	HV_MMU_MAP_ADDR_TRAP
84 85
	brnz,pn	%o0, sun4v_itlb_error
	 mov	%g2, %o1		! restore %o1
86 87 88 89 90 91 92
	mov	%g1, %o0		! restore %o0
	mov	%g5, %o2		! restore %o2
	mov	%g7, %o3		! restore %o3

	retry

sun4v_dtlb_miss:
93 94
	/* Load MMU Miss base into %g2.  */
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
95 96
	
	/* Load UTSB reg into %g1.  */
97
	mov	SCRATCHPAD_UTSBREG1, %g1
98
	ldxa	[%g1] ASI_SCRATCHPAD, %g1
99

100
	LOAD_DTLB_INFO(%g2, %g4, %g5)
101
	COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_dtlb_4v)
102
	COMPUTE_TSB_PTR(%g1, %g4, PAGE_SHIFT, %g3, %g7)
103 104

	/* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
105
	ldda	[%g1] ASI_QUAD_LDD_PHYS_4V, %g2
106 107
	cmp	%g2, %g6
	bne,a,pn %xcc, tsb_miss_page_table_walk
108
	 mov	FAULT_CODE_DTLB, %g3
109 110 111 112 113 114 115 116

	/* We have a valid entry, make hypervisor call to load
	 * D-TLB and return from trap.
	 *
	 * %g3:	PTE
	 * %g4:	vaddr
	 */
sun4v_dtlb_load:
117
	ldxa	[%g0] ASI_SCRATCHPAD, %g6
118 119 120 121 122
	mov	%o0, %g1		! save %o0
	mov	%o1, %g2		! save %o1
	mov	%o2, %g5		! save %o2
	mov	%o3, %g7		! save %o3
	mov	%g4, %o0		! vaddr
123
	ldx	[%g6 + HV_FAULT_D_CTX_OFFSET], %o1	! ctx
124 125 126
	mov	%g3, %o2		! PTE
	mov	HV_MMU_DMMU, %o3	! flags
	ta	HV_MMU_MAP_ADDR_TRAP
127 128
	brnz,pn	%o0, sun4v_dtlb_error
	 mov	%g2, %o1		! restore %o1
129 130 131 132 133 134 135
	mov	%g1, %o0		! restore %o0
	mov	%g5, %o2		! restore %o2
	mov	%g7, %o3		! restore %o3

	retry

sun4v_dtlb_prot:
136 137
	SET_GL(1)

138
	/* Load MMU Miss base into %g5.  */
139
	ldxa	[%g0] ASI_SCRATCHPAD, %g5
140
	
141
	ldx	[%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
142 143
	rdpr	%tl, %g1
	cmp	%g1, 1
144 145
	bgu,pn	%xcc, winfix_trampoline
	 mov	FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
146 147
	ba,pt	%xcc, sparc64_realfault_common
	 nop
148

149 150 151 152
	/* Called from trap table:
	 * %g4:	vaddr
	 * %g5:	context
	 * %g6: TAG TARGET
153 154
	 */
sun4v_itsb_miss:
155 156 157
	mov	SCRATCHPAD_UTSBREG1, %g1
	ldxa	[%g1] ASI_SCRATCHPAD, %g1
	brz,pn	%g5, kvmap_itlb_4v
158
	 mov	FAULT_CODE_ITLB, %g3
159
	ba,a,pt	%xcc, sun4v_tsb_miss_common
160

161 162 163 164
	/* Called from trap table:
	 * %g4:	vaddr
	 * %g5:	context
	 * %g6: TAG TARGET
165 166
	 */
sun4v_dtsb_miss:
167 168 169 170
	mov	SCRATCHPAD_UTSBREG1, %g1
	ldxa	[%g1] ASI_SCRATCHPAD, %g1
	brz,pn	%g5, kvmap_dtlb_4v
	 mov	FAULT_CODE_DTLB, %g3
171

172 173
	/* fallthrough */

174
sun4v_tsb_miss_common:
175
	COMPUTE_TSB_PTR(%g1, %g4, PAGE_SHIFT, %g5, %g7)
176 177

	sub	%g2, TRAP_PER_CPU_FAULT_INFO, %g2
178

179
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
180 181 182 183 184
	mov	SCRATCHPAD_UTSBREG2, %g5
	ldxa	[%g5] ASI_SCRATCHPAD, %g5
	cmp	%g5, -1
	be,pt	%xcc, 80f
	 nop
185
	COMPUTE_TSB_PTR(%g5, %g4, REAL_HPAGE_SHIFT, %g2, %g7)
186 187 188 189 190 191 192 193

	/* That clobbered %g2, reload it.  */
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	sub	%g2, TRAP_PER_CPU_FAULT_INFO, %g2

80:	stx	%g5, [%g2 + TRAP_PER_CPU_TSB_HUGE_TEMP]
#endif

194 195
	ba,pt	%xcc, tsb_miss_page_table_walk_sun4v_fastpath
	 ldx	[%g2 + TRAP_PER_CPU_PGD_PADDR], %g7
196

197
sun4v_itlb_error:
198 199 200 201 202
	rdpr	%tl, %g1
	cmp	%g1, 1
	ble,pt	%icc, sun4v_bad_ra
	 or	%g0, FAULT_CODE_BAD_RA | FAULT_CODE_ITLB, %g1

203 204 205
	sethi	%hi(sun4v_err_itlb_vaddr), %g1
	stx	%g4, [%g1 + %lo(sun4v_err_itlb_vaddr)]
	sethi	%hi(sun4v_err_itlb_ctx), %g1
206 207
	ldxa	[%g0] ASI_SCRATCHPAD, %g6
	ldx	[%g6 + HV_FAULT_I_CTX_OFFSET], %o1
208 209 210 211 212 213
	stx	%o1, [%g1 + %lo(sun4v_err_itlb_ctx)]
	sethi	%hi(sun4v_err_itlb_pte), %g1
	stx	%g3, [%g1 + %lo(sun4v_err_itlb_pte)]
	sethi	%hi(sun4v_err_itlb_error), %g1
	stx	%o0, [%g1 + %lo(sun4v_err_itlb_error)]

214
	sethi	%hi(1f), %g7
215 216
	rdpr	%tl, %g4
	ba,pt	%xcc, etraptl1
217
1:	 or	%g7, %lo(1f), %g7
218
	mov	%l4, %o1
219 220 221 222 223 224
	call	sun4v_itlb_error_report
	 add	%sp, PTREGS_OFF, %o0

	/* NOTREACHED */

sun4v_dtlb_error:
225 226 227 228 229
	rdpr	%tl, %g1
	cmp	%g1, 1
	ble,pt	%icc, sun4v_bad_ra
	 or	%g0, FAULT_CODE_BAD_RA | FAULT_CODE_DTLB, %g1

230 231 232
	sethi	%hi(sun4v_err_dtlb_vaddr), %g1
	stx	%g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)]
	sethi	%hi(sun4v_err_dtlb_ctx), %g1
233 234
	ldxa	[%g0] ASI_SCRATCHPAD, %g6
	ldx	[%g6 + HV_FAULT_D_CTX_OFFSET], %o1
235 236 237 238 239 240
	stx	%o1, [%g1 + %lo(sun4v_err_dtlb_ctx)]
	sethi	%hi(sun4v_err_dtlb_pte), %g1
	stx	%g3, [%g1 + %lo(sun4v_err_dtlb_pte)]
	sethi	%hi(sun4v_err_dtlb_error), %g1
	stx	%o0, [%g1 + %lo(sun4v_err_dtlb_error)]

241
	sethi	%hi(1f), %g7
242 243
	rdpr	%tl, %g4
	ba,pt	%xcc, etraptl1
244
1:	 or	%g7, %lo(1f), %g7
245
	mov	%l4, %o1
246 247 248 249 250
	call	sun4v_dtlb_error_report
	 add	%sp, PTREGS_OFF, %o0

	/* NOTREACHED */

251 252 253 254 255 256 257
sun4v_bad_ra:
	or	%g0, %g4, %g5
	ba,pt	%xcc, sparc64_realfault_common
	 or	%g1, %g0, %g4

	/* NOTREACHED */

258 259
	/* Instruction Access Exception, tl0. */
sun4v_iacc:
260 261 262 263
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	ldx	[%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
	ldx	[%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
	ldx	[%g2 + HV_FAULT_I_CTX_OFFSET], %g5
264 265 266 267 268 269 270 271
	sllx	%g3, 16, %g3
	or	%g5, %g3, %g5
	ba,pt	%xcc, etrap
	 rd	%pc, %g7
	mov	%l4, %o1
	mov	%l5, %o2
	call	sun4v_insn_access_exception
	 add	%sp, PTREGS_OFF, %o0
272
	ba,a,pt	%xcc, rtrap
273 274 275

	/* Instruction Access Exception, tl1. */
sun4v_iacc_tl1:
276 277 278 279
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	ldx	[%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
	ldx	[%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
	ldx	[%g2 + HV_FAULT_I_CTX_OFFSET], %g5
280 281 282 283 284 285 286 287
	sllx	%g3, 16, %g3
	or	%g5, %g3, %g5
	ba,pt	%xcc, etraptl1
	 rd	%pc, %g7
	mov	%l4, %o1
	mov	%l5, %o2
	call	sun4v_insn_access_exception_tl1
	 add	%sp, PTREGS_OFF, %o0
288
	ba,a,pt	%xcc, rtrap
289 290 291

	/* Data Access Exception, tl0. */
sun4v_dacc:
292 293 294 295
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
296 297 298 299 300 301 302 303
	sllx	%g3, 16, %g3
	or	%g5, %g3, %g5
	ba,pt	%xcc, etrap
	 rd	%pc, %g7
	mov	%l4, %o1
	mov	%l5, %o2
	call	sun4v_data_access_exception
	 add	%sp, PTREGS_OFF, %o0
304
	ba,a,pt	%xcc, rtrap
305 306 307

	/* Data Access Exception, tl1. */
sun4v_dacc_tl1:
308 309 310 311
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
312 313 314 315 316 317 318 319
	sllx	%g3, 16, %g3
	or	%g5, %g3, %g5
	ba,pt	%xcc, etraptl1
	 rd	%pc, %g7
	mov	%l4, %o1
	mov	%l5, %o2
	call	sun4v_data_access_exception_tl1
	 add	%sp, PTREGS_OFF, %o0
320
	ba,a,pt	%xcc, rtrap
321 322 323

	/* Memory Address Unaligned.  */
sun4v_mna:
324 325 326 327 328 329 330
	/* Window fixup? */
	rdpr	%tl, %g2
	cmp	%g2, 1
	ble,pt	%icc, 1f
	 nop

	SET_GL(1)
331 332
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g5
333
	mov	HV_FAULT_TYPE_UNALIGNED, %g3
334
	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g4
335 336 337 338 339 340 341
	sllx	%g3, 16, %g3
	or	%g4, %g3, %g4
	ba,pt	%xcc, winfix_mna
	 rdpr	%tpc, %g3
	/* not reached */

1:	ldxa	[%g0] ASI_SCRATCHPAD, %g2
342
	mov	HV_FAULT_TYPE_UNALIGNED, %g3
343 344
	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
345 346 347 348 349 350 351
	sllx	%g3, 16, %g3
	or	%g5, %g3, %g5

	ba,pt	%xcc, etrap
	 rd	%pc, %g7
	mov	%l4, %o1
	mov	%l5, %o2
352
	call	sun4v_do_mna
353
	 add	%sp, PTREGS_OFF, %o0
354
	ba,a,pt	%xcc, rtrap
B
Babu Moger 已提交
355
	 nop
356 357 358 359 360 361 362

	/* Privileged Action.  */
sun4v_privact:
	ba,pt	%xcc, etrap
	 rd	%pc, %g7
	call	do_privact
	 add	%sp, PTREGS_OFF, %o0
363
	ba,a,pt	%xcc, rtrap
364 365 366

	/* Unaligned ldd float, tl0. */
sun4v_lddfmna:
367 368 369 370
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
371 372 373 374 375 376 377 378
	sllx	%g3, 16, %g3
	or	%g5, %g3, %g5
	ba,pt	%xcc, etrap
	 rd	%pc, %g7
	mov	%l4, %o1
	mov	%l5, %o2
	call	handle_lddfmna
	 add	%sp, PTREGS_OFF, %o0
379
	ba,a,pt	%xcc, rtrap
380 381 382

	/* Unaligned std float, tl0. */
sun4v_stdfmna:
383 384 385 386
	ldxa	[%g0] ASI_SCRATCHPAD, %g2
	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
387 388 389 390 391 392 393 394
	sllx	%g3, 16, %g3
	or	%g5, %g3, %g5
	ba,pt	%xcc, etrap
	 rd	%pc, %g7
	mov	%l4, %o1
	mov	%l5, %o2
	call	handle_stdfmna
	 add	%sp, PTREGS_OFF, %o0
395
	ba,a,pt	%xcc, rtrap
396

397 398 399 400 401 402 403 404 405
#define BRANCH_ALWAYS	0x10680000
#define NOP		0x01000000
#define SUN4V_DO_PATCH(OLD, NEW)	\
	sethi	%hi(NEW), %g1; \
	or	%g1, %lo(NEW), %g1; \
	sethi	%hi(OLD), %g2; \
	or	%g2, %lo(OLD), %g2; \
	sub	%g1, %g2, %g1; \
	sethi	%hi(BRANCH_ALWAYS), %g3; \
406 407
	sll	%g1, 11, %g1; \
	srl	%g1, 11 + 2, %g1; \
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
	or	%g3, %lo(BRANCH_ALWAYS), %g3; \
	or	%g3, %g1, %g3; \
	stw	%g3, [%g2]; \
	sethi	%hi(NOP), %g3; \
	or	%g3, %lo(NOP), %g3; \
	stw	%g3, [%g2 + 0x4]; \
	flush	%g2;

	.globl	sun4v_patch_tlb_handlers
	.type	sun4v_patch_tlb_handlers,#function
sun4v_patch_tlb_handlers:
	SUN4V_DO_PATCH(tl0_iamiss, sun4v_itlb_miss)
	SUN4V_DO_PATCH(tl1_iamiss, sun4v_itlb_miss)
	SUN4V_DO_PATCH(tl0_damiss, sun4v_dtlb_miss)
	SUN4V_DO_PATCH(tl1_damiss, sun4v_dtlb_miss)
	SUN4V_DO_PATCH(tl0_daprot, sun4v_dtlb_prot)
	SUN4V_DO_PATCH(tl1_daprot, sun4v_dtlb_prot)
425 426 427 428 429 430 431 432 433
	SUN4V_DO_PATCH(tl0_iax, sun4v_iacc)
	SUN4V_DO_PATCH(tl1_iax, sun4v_iacc_tl1)
	SUN4V_DO_PATCH(tl0_dax, sun4v_dacc)
	SUN4V_DO_PATCH(tl1_dax, sun4v_dacc_tl1)
	SUN4V_DO_PATCH(tl0_mna, sun4v_mna)
	SUN4V_DO_PATCH(tl1_mna, sun4v_mna)
	SUN4V_DO_PATCH(tl0_lddfmna, sun4v_lddfmna)
	SUN4V_DO_PATCH(tl0_stdfmna, sun4v_stdfmna)
	SUN4V_DO_PATCH(tl0_privact, sun4v_privact)
434 435 436
	retl
	 nop
	.size	sun4v_patch_tlb_handlers,.-sun4v_patch_tlb_handlers