/* tlb-miss.S: TLB miss handlers
 *
 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/spr-regs.h>

	.section	.text.tlbmiss
	.balign		4

	.globl		__entry_insn_mmu_miss
__entry_insn_mmu_miss:
	break
	nop

	.globl		__entry_insn_mmu_exception
__entry_insn_mmu_exception:
	break
	nop

	.globl		__entry_data_mmu_miss
__entry_data_mmu_miss:
	break
	nop

	.globl		__entry_data_mmu_exception
__entry_data_mmu_exception:
	break
	nop

###############################################################################
#
# handle a lookup failure of one sort or another in a kernel TLB handler
# On entry:
#   GR29 - faulting address
#   SCR2 - saved CCR
#
###############################################################################
	.type		__tlb_kernel_fault,@function
__tlb_kernel_fault:
	# see if we're supposed to re-enable single-step mode upon return
	sethi.p		%hi(__break_tlb_miss_return_break),gr30
	setlo		%lo(__break_tlb_miss_return_break),gr30
	movsg		pcsr,gr31

	subcc		gr31,gr30,gr0,icc0
	beq		icc0,#0,__tlb_kernel_fault_sstep

	movsg		scr2,gr30
	movgs		gr30,ccr
	movgs		gr29,scr2			/* save EAR0 value */
	sethi.p		%hi(__kernel_current_task),gr29
	setlo		%lo(__kernel_current_task),gr29
	ldi.p		@(gr29,#0),gr29			/* restore GR29 */

	bra		__entry_kernel_handle_mmu_fault

	# we've got to re-enable single-stepping
__tlb_kernel_fault_sstep:
	sethi.p		%hi(__break_tlb_miss_real_return_info),gr30
	setlo		%lo(__break_tlb_miss_real_return_info),gr30
	lddi		@(gr30,0),gr30
	movgs		gr30,pcsr
	movgs		gr31,psr

	movsg		scr2,gr30
	movgs		gr30,ccr
	movgs		gr29,scr2			/* save EAR0 value */
	sethi.p		%hi(__kernel_current_task),gr29
	setlo		%lo(__kernel_current_task),gr29
	ldi.p		@(gr29,#0),gr29			/* restore GR29 */
	bra		__entry_kernel_handle_mmu_fault_sstep

	.size		__tlb_kernel_fault, .-__tlb_kernel_fault

###############################################################################
#
# handle a lookup failure of one sort or another in a user TLB handler
# On entry:
#   GR28 - faulting address
#   SCR2 - saved CCR
#
###############################################################################
	.type		__tlb_user_fault,@function
__tlb_user_fault:
	# see if we're supposed to re-enable single-step mode upon return
	sethi.p		%hi(__break_tlb_miss_return_break),gr30
	setlo		%lo(__break_tlb_miss_return_break),gr30
	movsg		pcsr,gr31
	subcc		gr31,gr30,gr0,icc0
	beq		icc0,#0,__tlb_user_fault_sstep

	movsg		scr2,gr30
	movgs		gr30,ccr
	bra		__entry_uspace_handle_mmu_fault

	# we've got to re-enable single-stepping
__tlb_user_fault_sstep:
	sethi.p		%hi(__break_tlb_miss_real_return_info),gr30
	setlo		%lo(__break_tlb_miss_real_return_info),gr30
	lddi		@(gr30,0),gr30
	movgs		gr30,pcsr
	movgs		gr31,psr
	movsg		scr2,gr30
	movgs		gr30,ccr
	bra		__entry_uspace_handle_mmu_fault_sstep

	.size		__tlb_user_fault, .-__tlb_user_fault

###############################################################################
#
# Kernel instruction TLB miss handler
# On entry:
#   GR1   - kernel stack pointer
#   GR28  - saved exception frame pointer
#   GR29  - faulting address
#   GR31  - EAR0 ^ SCR0
#   SCR0  - base of virtual range covered by cached PGE from last ITLB miss (or 0xffffffff)
#   DAMR3 - mapped page directory
#   DAMR4 - mapped page table as matched by SCR0
#
###############################################################################
	.globl		__entry_kernel_insn_tlb_miss
	.type		__entry_kernel_insn_tlb_miss,@function
__entry_kernel_insn_tlb_miss:
#if 0
	sethi.p		%hi(0xe1200004),gr30
	setlo		%lo(0xe1200004),gr30
	st		gr0,@(gr30,gr0)
	sethi.p		%hi(0xffc00100),gr30
	setlo		%lo(0xffc00100),gr30
	sth		gr30,@(gr30,gr0)
	membar
#endif

	movsg		ccr,gr30			/* save CCR */
	movgs		gr30,scr2

	# see if the cached page table mapping is appropriate
	srlicc.p	gr31,#26,gr0,icc0
	setlos		0x3ffc,gr30
	srli.p		gr29,#12,gr31			/* use EAR0[25:14] as PTE index */
	bne		icc0,#0,__itlb_k_PTD_miss

__itlb_k_PTD_mapped:
	# access the PTD with EAR0[25:14]
	# - DAMLR4 points to the virtual address of the appropriate page table
	# - the PTD holds 4096 PTEs
	# - the PTD must be accessed uncached
	# - the PTE must be marked accessed if it was valid
	#
	and		gr31,gr30,gr31
	movsg		damlr4,gr30
	add		gr30,gr31,gr31
	ldi		@(gr31,#0),gr30			/* fetch the PTE */
	andicc		gr30,#_PAGE_PRESENT,gr0,icc0
	ori.p		gr30,#_PAGE_ACCESSED,gr30
	beq		icc0,#0,__tlb_kernel_fault	/* jump if PTE invalid */
	sti.p		gr30,@(gr31,#0)			/* update the PTE */
	andi		gr30,#~_PAGE_ACCESSED,gr30

	# we're using IAMR1 as an extra TLB entry
	# - punt the entry here (if valid) to the real TLB and then replace with the new PTE
	# - need to check DAMR1 lest we cause an multiple-DAT-hit exception
	# - IAMPR1 has no WP bit, and we mustn't lose WP information
	movsg		iampr1,gr31
	andicc		gr31,#xAMPRx_V,gr0,icc0
	setlos.p	0xfffff000,gr31
	beq		icc0,#0,__itlb_k_nopunt		/* punt not required */

	movsg		iamlr1,gr31
	movgs		gr31,tplr			/* set TPLR.CXN */
	tlbpr		gr31,gr0,#4,#0			/* delete matches from TLB, IAMR1, DAMR1 */

	movsg		dampr1,gr31
	ori		gr31,#xAMPRx_V,gr31		/* entry was invalidated by tlbpr #4 */
	movgs		gr31,tppr
	movsg		iamlr1,gr31			/* set TPLR.CXN */
	movgs		gr31,tplr
	tlbpr		gr31,gr0,#2,#0			/* save to the TLB */
	movsg		tpxr,gr31			/* check the TLB write error flag */
	andicc.p	gr31,#TPXR_E,gr0,icc0
	setlos		#0xfffff000,gr31
	bne		icc0,#0,__tlb_kernel_fault

__itlb_k_nopunt:

	# assemble the new TLB entry
	and		gr29,gr31,gr29
	movsg		cxnr,gr31
	or		gr29,gr31,gr29
	movgs		gr29,iamlr1			/* xAMLR = address | context number */
	movgs		gr30,iampr1
	movgs		gr29,damlr1
	movgs		gr30,dampr1

	# return, restoring registers
	movsg		scr2,gr30
	movgs		gr30,ccr
	sethi.p		%hi(__kernel_current_task),gr29
	setlo		%lo(__kernel_current_task),gr29
	ldi		@(gr29,#0),gr29
	rett		#0
	beq		icc0,#3,0			/* prevent icache prefetch */

	# the PTE we want wasn't in the PTD we have mapped, so we need to go looking for a more
	# appropriate page table and map that instead
	#   - access the PGD with EAR0[31:26]
	#   - DAMLR3 points to the virtual address of the page directory
	#   - the PGD holds 64 PGEs and each PGE/PME points to a set of page tables
__itlb_k_PTD_miss:
	srli		gr29,#26,gr31			/* calculate PGE offset */
	slli		gr31,#8,gr31			/* and clear bottom bits */

	movsg		damlr3,gr30
	ld		@(gr31,gr30),gr30		/* access the PGE */

	andicc.p	gr30,#_PAGE_PRESENT,gr0,icc0
	andicc		gr30,#xAMPRx_SS,gr0,icc1

	# map this PTD instead and record coverage address
	ori.p		gr30,#xAMPRx_L|xAMPRx_SS_16Kb|xAMPRx_S|xAMPRx_C|xAMPRx_V,gr30
	beq		icc0,#0,__tlb_kernel_fault	/* jump if PGE not present */
	slli.p		gr31,#18,gr31
	bne		icc1,#0,__itlb_k_bigpage
	movgs		gr30,dampr4
	movgs		gr31,scr0

	# we can now resume normal service
	setlos		0x3ffc,gr30
	srli.p		gr29,#12,gr31			/* use EAR0[25:14] as PTE index */
	bra		__itlb_k_PTD_mapped

__itlb_k_bigpage:
	break
	nop

	.size		__entry_kernel_insn_tlb_miss, .-__entry_kernel_insn_tlb_miss

###############################################################################
#
# Kernel data TLB miss handler
# On entry:
#   GR1   - kernel stack pointer
#   GR28  - saved exception frame pointer
#   GR29  - faulting address
#   GR31  - EAR0 ^ SCR1
#   SCR1  - base of virtual range covered by cached PGE from last DTLB miss (or 0xffffffff)
#   DAMR3 - mapped page directory
#   DAMR5 - mapped page table as matched by SCR1
#
###############################################################################
	.globl		__entry_kernel_data_tlb_miss
	.type		__entry_kernel_data_tlb_miss,@function
__entry_kernel_data_tlb_miss:
#if 0
	sethi.p		%hi(0xe1200004),gr30
	setlo		%lo(0xe1200004),gr30
	st		gr0,@(gr30,gr0)
	sethi.p		%hi(0xffc00100),gr30
	setlo		%lo(0xffc00100),gr30
	sth		gr30,@(gr30,gr0)
	membar
#endif

	movsg		ccr,gr30			/* save CCR */
	movgs		gr30,scr2

	# see if the cached page table mapping is appropriate
	srlicc.p	gr31,#26,gr0,icc0
	setlos		0x3ffc,gr30
	srli.p		gr29,#12,gr31			/* use EAR0[25:14] as PTE index */
	bne		icc0,#0,__dtlb_k_PTD_miss

__dtlb_k_PTD_mapped:
	# access the PTD with EAR0[25:14]
	# - DAMLR5 points to the virtual address of the appropriate page table
	# - the PTD holds 4096 PTEs
	# - the PTD must be accessed uncached
	# - the PTE must be marked accessed if it was valid
	#
	and		gr31,gr30,gr31
	movsg		damlr5,gr30
	add		gr30,gr31,gr31
	ldi		@(gr31,#0),gr30			/* fetch the PTE */
	andicc		gr30,#_PAGE_PRESENT,gr0,icc0
	ori.p		gr30,#_PAGE_ACCESSED,gr30
	beq		icc0,#0,__tlb_kernel_fault	/* jump if PTE invalid */
	sti.p		gr30,@(gr31,#0)			/* update the PTE */
	andi		gr30,#~_PAGE_ACCESSED,gr30

	# we're using DAMR1 as an extra TLB entry
	# - punt the entry here (if valid) to the real TLB and then replace with the new PTE
	# - need to check IAMR1 lest we cause an multiple-DAT-hit exception
	movsg		dampr1,gr31
	andicc		gr31,#xAMPRx_V,gr0,icc0
	setlos.p	0xfffff000,gr31
	beq		icc0,#0,__dtlb_k_nopunt		/* punt not required */

	movsg		damlr1,gr31
	movgs		gr31,tplr			/* set TPLR.CXN */
	tlbpr		gr31,gr0,#4,#0			/* delete matches from TLB, IAMR1, DAMR1 */

	movsg		dampr1,gr31
	ori		gr31,#xAMPRx_V,gr31		/* entry was invalidated by tlbpr #4 */
	movgs		gr31,tppr
	movsg		damlr1,gr31			/* set TPLR.CXN */
	movgs		gr31,tplr
	tlbpr		gr31,gr0,#2,#0			/* save to the TLB */
	movsg		tpxr,gr31			/* check the TLB write error flag */
	andicc.p	gr31,#TPXR_E,gr0,icc0
	setlos		#0xfffff000,gr31
	bne		icc0,#0,__tlb_kernel_fault

__dtlb_k_nopunt:

	# assemble the new TLB entry
	and		gr29,gr31,gr29
	movsg		cxnr,gr31
	or		gr29,gr31,gr29
	movgs		gr29,iamlr1			/* xAMLR = address | context number */
	movgs		gr30,iampr1
	movgs		gr29,damlr1
	movgs		gr30,dampr1

	# return, restoring registers
	movsg		scr2,gr30
	movgs		gr30,ccr
	sethi.p		%hi(__kernel_current_task),gr29
	setlo		%lo(__kernel_current_task),gr29
	ldi		@(gr29,#0),gr29
	rett		#0
	beq		icc0,#3,0			/* prevent icache prefetch */

	# the PTE we want wasn't in the PTD we have mapped, so we need to go looking for a more
	# appropriate page table and map that instead
	#   - access the PGD with EAR0[31:26]
	#   - DAMLR3 points to the virtual address of the page directory
	#   - the PGD holds 64 PGEs and each PGE/PME points to a set of page tables
__dtlb_k_PTD_miss:
	srli		gr29,#26,gr31			/* calculate PGE offset */
	slli		gr31,#8,gr31			/* and clear bottom bits */

	movsg		damlr3,gr30
	ld		@(gr31,gr30),gr30		/* access the PGE */

	andicc.p	gr30,#_PAGE_PRESENT,gr0,icc0
	andicc		gr30,#xAMPRx_SS,gr0,icc1

	# map this PTD instead and record coverage address
	ori.p		gr30,#xAMPRx_L|xAMPRx_SS_16Kb|xAMPRx_S|xAMPRx_C|xAMPRx_V,gr30
	beq		icc0,#0,__tlb_kernel_fault	/* jump if PGE not present */
	slli.p		gr31,#18,gr31
	bne		icc1,#0,__dtlb_k_bigpage
	movgs		gr30,dampr5
	movgs		gr31,scr1

	# we can now resume normal service
	setlos		0x3ffc,gr30
	srli.p		gr29,#12,gr31			/* use EAR0[25:14] as PTE index */
	bra		__dtlb_k_PTD_mapped

__dtlb_k_bigpage:
	break
	nop

	.size		__entry_kernel_data_tlb_miss, .-__entry_kernel_data_tlb_miss

###############################################################################
#
# Userspace instruction TLB miss handler (with PGE prediction)
# On entry:
#   GR28  - faulting address
#   GR31  - EAR0 ^ SCR0
#   SCR0  - base of virtual range covered by cached PGE from last ITLB miss (or 0xffffffff)
#   DAMR3 - mapped page directory
#   DAMR4 - mapped page table as matched by SCR0
#
###############################################################################
	.globl		__entry_user_insn_tlb_miss
	.type		__entry_user_insn_tlb_miss,@function
__entry_user_insn_tlb_miss:
#if 0
	sethi.p		%hi(0xe1200004),gr30
	setlo		%lo(0xe1200004),gr30
	st		gr0,@(gr30,gr0)
	sethi.p		%hi(0xffc00100),gr30
	setlo		%lo(0xffc00100),gr30
	sth		gr30,@(gr30,gr0)
	membar
#endif

	movsg		ccr,gr30			/* save CCR */
	movgs		gr30,scr2

	# see if the cached page table mapping is appropriate
	srlicc.p	gr31,#26,gr0,icc0
	setlos		0x3ffc,gr30
	srli.p		gr28,#12,gr31			/* use EAR0[25:14] as PTE index */
	bne		icc0,#0,__itlb_u_PTD_miss

__itlb_u_PTD_mapped:
	# access the PTD with EAR0[25:14]
	# - DAMLR4 points to the virtual address of the appropriate page table
	# - the PTD holds 4096 PTEs
	# - the PTD must be accessed uncached
	# - the PTE must be marked accessed if it was valid
	#
	and		gr31,gr30,gr31
	movsg		damlr4,gr30
	add		gr30,gr31,gr31
	ldi		@(gr31,#0),gr30			/* fetch the PTE */
	andicc		gr30,#_PAGE_PRESENT,gr0,icc0
	ori.p		gr30,#_PAGE_ACCESSED,gr30
	beq		icc0,#0,__tlb_user_fault	/* jump if PTE invalid */
	sti.p		gr30,@(gr31,#0)			/* update the PTE */
	andi		gr30,#~_PAGE_ACCESSED,gr30

	# we're using IAMR1/DAMR1 as an extra TLB entry
	# - punt the entry here (if valid) to the real TLB and then replace with the new PTE
	movsg		dampr1,gr31
	andicc		gr31,#xAMPRx_V,gr0,icc0
	setlos.p	0xfffff000,gr31
	beq		icc0,#0,__itlb_u_nopunt		/* punt not required */

	movsg		dampr1,gr31
	movgs		gr31,tppr
	movsg		damlr1,gr31			/* set TPLR.CXN */
	movgs		gr31,tplr
	tlbpr		gr31,gr0,#2,#0			/* save to the TLB */
	movsg		tpxr,gr31			/* check the TLB write error flag */
	andicc.p	gr31,#TPXR_E,gr0,icc0
	setlos		#0xfffff000,gr31
	bne		icc0,#0,__tlb_user_fault

__itlb_u_nopunt:

	# assemble the new TLB entry
	and		gr28,gr31,gr28
	movsg		cxnr,gr31
	or		gr28,gr31,gr28
	movgs		gr28,iamlr1			/* xAMLR = address | context number */
	movgs		gr30,iampr1
	movgs		gr28,damlr1
	movgs		gr30,dampr1

	# return, restoring registers
	movsg		scr2,gr30
	movgs		gr30,ccr
	rett		#0
	beq		icc0,#3,0			/* prevent icache prefetch */

	# the PTE we want wasn't in the PTD we have mapped, so we need to go looking for a more
	# appropriate page table and map that instead
	#   - access the PGD with EAR0[31:26]
	#   - DAMLR3 points to the virtual address of the page directory
	#   - the PGD holds 64 PGEs and each PGE/PME points to a set of page tables
__itlb_u_PTD_miss:
	srli		gr28,#26,gr31			/* calculate PGE offset */
	slli		gr31,#8,gr31			/* and clear bottom bits */

	movsg		damlr3,gr30
	ld		@(gr31,gr30),gr30		/* access the PGE */

	andicc.p	gr30,#_PAGE_PRESENT,gr0,icc0
	andicc		gr30,#xAMPRx_SS,gr0,icc1

	# map this PTD instead and record coverage address
	ori.p		gr30,#xAMPRx_L|xAMPRx_SS_16Kb|xAMPRx_S|xAMPRx_C|xAMPRx_V,gr30
	beq		icc0,#0,__tlb_user_fault	/* jump if PGE not present */
	slli.p		gr31,#18,gr31
	bne		icc1,#0,__itlb_u_bigpage
	movgs		gr30,dampr4
	movgs		gr31,scr0

	# we can now resume normal service
	setlos		0x3ffc,gr30
	srli.p		gr28,#12,gr31			/* use EAR0[25:14] as PTE index */
	bra		__itlb_u_PTD_mapped

__itlb_u_bigpage:
	break
	nop

	.size		__entry_user_insn_tlb_miss, .-__entry_user_insn_tlb_miss

###############################################################################
#
# Userspace data TLB miss handler
# On entry:
#   GR28  - faulting address
#   GR31  - EAR0 ^ SCR1
#   SCR1  - base of virtual range covered by cached PGE from last DTLB miss (or 0xffffffff)
#   DAMR3 - mapped page directory
#   DAMR5 - mapped page table as matched by SCR1
#
###############################################################################
	.globl		__entry_user_data_tlb_miss
	.type		__entry_user_data_tlb_miss,@function
__entry_user_data_tlb_miss:
#if 0
	sethi.p		%hi(0xe1200004),gr30
	setlo		%lo(0xe1200004),gr30
	st		gr0,@(gr30,gr0)
	sethi.p		%hi(0xffc00100),gr30
	setlo		%lo(0xffc00100),gr30
	sth		gr30,@(gr30,gr0)
	membar
#endif

	movsg		ccr,gr30			/* save CCR */
	movgs		gr30,scr2

	# see if the cached page table mapping is appropriate
	srlicc.p	gr31,#26,gr0,icc0
	setlos		0x3ffc,gr30
	srli.p		gr28,#12,gr31			/* use EAR0[25:14] as PTE index */
	bne		icc0,#0,__dtlb_u_PTD_miss

__dtlb_u_PTD_mapped:
	# access the PTD with EAR0[25:14]
	# - DAMLR5 points to the virtual address of the appropriate page table
	# - the PTD holds 4096 PTEs
	# - the PTD must be accessed uncached
	# - the PTE must be marked accessed if it was valid
	#
	and		gr31,gr30,gr31
	movsg		damlr5,gr30

__dtlb_u_using_iPTD:
	add		gr30,gr31,gr31
	ldi		@(gr31,#0),gr30			/* fetch the PTE */
	andicc		gr30,#_PAGE_PRESENT,gr0,icc0
	ori.p		gr30,#_PAGE_ACCESSED,gr30
	beq		icc0,#0,__tlb_user_fault	/* jump if PTE invalid */
	sti.p		gr30,@(gr31,#0)			/* update the PTE */
	andi		gr30,#~_PAGE_ACCESSED,gr30

	# we're using DAMR1 as an extra TLB entry
	# - punt the entry here (if valid) to the real TLB and then replace with the new PTE
	movsg		dampr1,gr31
	andicc		gr31,#xAMPRx_V,gr0,icc0
	setlos.p	0xfffff000,gr31
	beq		icc0,#0,__dtlb_u_nopunt		/* punt not required */

	movsg		dampr1,gr31
	movgs		gr31,tppr
	movsg		damlr1,gr31			/* set TPLR.CXN */
	movgs		gr31,tplr
	tlbpr		gr31,gr0,#2,#0			/* save to the TLB */
	movsg		tpxr,gr31			/* check the TLB write error flag */
	andicc.p	gr31,#TPXR_E,gr0,icc0
	setlos		#0xfffff000,gr31
	bne		icc0,#0,__tlb_user_fault

__dtlb_u_nopunt:

	# assemble the new TLB entry
	and		gr28,gr31,gr28
	movsg		cxnr,gr31
	or		gr28,gr31,gr28
	movgs		gr28,iamlr1			/* xAMLR = address | context number */
	movgs		gr30,iampr1
	movgs		gr28,damlr1
	movgs		gr30,dampr1

	# return, restoring registers
	movsg		scr2,gr30
	movgs		gr30,ccr
	rett		#0
	beq		icc0,#3,0			/* prevent icache prefetch */

	# the PTE we want wasn't in the PTD we have mapped, so we need to go looking for a more
	# appropriate page table and map that instead
	#   - first of all, check the insn PGE cache - we may well get a hit there
	#   - access the PGD with EAR0[31:26]
	#   - DAMLR3 points to the virtual address of the page directory
	#   - the PGD holds 64 PGEs and each PGE/PME points to a set of page tables
__dtlb_u_PTD_miss:
	movsg		scr0,gr31			/* consult the insn-PGE-cache key */
	xor		gr28,gr31,gr31
	srlicc		gr31,#26,gr0,icc0
	srli		gr28,#12,gr31			/* use EAR0[25:14] as PTE index */
	bne		icc0,#0,__dtlb_u_iPGE_miss

	# what we're looking for is covered by the insn-PGE-cache
	setlos		0x3ffc,gr30
	and		gr31,gr30,gr31
	movsg		damlr4,gr30
	bra		__dtlb_u_using_iPTD

__dtlb_u_iPGE_miss:
	srli		gr28,#26,gr31			/* calculate PGE offset */
	slli		gr31,#8,gr31			/* and clear bottom bits */

	movsg		damlr3,gr30
	ld		@(gr31,gr30),gr30		/* access the PGE */

	andicc.p	gr30,#_PAGE_PRESENT,gr0,icc0
	andicc		gr30,#xAMPRx_SS,gr0,icc1

	# map this PTD instead and record coverage address
	ori.p		gr30,#xAMPRx_L|xAMPRx_SS_16Kb|xAMPRx_S|xAMPRx_C|xAMPRx_V,gr30
	beq		icc0,#0,__tlb_user_fault	/* jump if PGE not present */
	slli.p		gr31,#18,gr31
	bne		icc1,#0,__dtlb_u_bigpage
	movgs		gr30,dampr5
	movgs		gr31,scr1

	# we can now resume normal service
	setlos		0x3ffc,gr30
	srli.p		gr28,#12,gr31			/* use EAR0[25:14] as PTE index */
	bra		__dtlb_u_PTD_mapped

__dtlb_u_bigpage:
	break
	nop

	.size		__entry_user_data_tlb_miss, .-__entry_user_data_tlb_miss
