This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / frv / mm / tlb-miss.S
diff --git a/arch/frv/mm/tlb-miss.S b/arch/frv/mm/tlb-miss.S
new file mode 100644 (file)
index 0000000..8729f7d
--- /dev/null
@@ -0,0 +1,631 @@
+/* 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/config.h>
+#include <linux/linkage.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/highmem.h>
+#include <asm/spr-regs.h>
+
+       .section        .text
+       .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