patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / parisc / kernel / entry.S
index 040956b..9c28494 100644 (file)
 #ifdef __LP64__
 #define CMPIB           cmpib,*
 #define CMPB            cmpb,*
+#define COND(x)                *x
 
        .level 2.0w
 #else
 #define CMPIB           cmpib,
 #define CMPB            cmpb,
+#define COND(x)                x
 
        .level 2.0
 #endif
        .align          32
        .endm
 
+       /* The following are simple 32 vs 64 bit instruction
+        * abstractions for the macros */
+       .macro          EXTR    reg1,start,length,reg2
+#ifdef __LP64__
+       extrd,u         \reg1,32+\start,\length,\reg2
+#else
+       extrw,u         \reg1,\start,\length,\reg2
+#endif
+       .endm
+
+       .macro          DEP     reg1,start,length,reg2
+#ifdef __LP64__
+       depd            \reg1,32+\start,\length,\reg2
+#else
+       depw            \reg1,\start,\length,\reg2
+#endif
+       .endm
+
+       .macro          DEPI    val,start,length,reg
+#ifdef __LP64__
+       depdi           \val,32+\start,\length,\reg
+#else
+       depwi           \val,\start,\length,\reg
+#endif
+       .endm
+
+       /* In LP64, the space contains part of the upper 32 bits of the
+        * fault.  We have to extract this and place it in the va,
+        * zeroing the corresponding bits in the space register */
+       .macro          space_adjust    spc,va,tmp
+#ifdef __LP64__
+       extrd,u         \spc,63,SPACEID_SHIFT,\tmp
+       depd            %r0,63,SPACEID_SHIFT,\spc
+       depd            \tmp,31,SPACEID_SHIFT,\va
+#endif
+       .endm
+
+       .import         swapper_pg_dir,code
+
+       /* Get the pgd.  For faults on space zero (kernel space), this
+        * is simply swapper_pg_dir.  For user space faults, the
+        * pgd is stored in %cr25 */
+       .macro          get_pgd         spc,reg
+       ldil            L%PA(swapper_pg_dir),\reg
+       ldo             R%PA(swapper_pg_dir)(\reg),\reg
+       or,COND(=)      %r0,\spc,%r0
+       mfctl           %cr25,\reg
+       .endm
+
+       /* Only allow faults on different spaces from the
+        * currently active one if we're the kernel */
+       .macro          space_check     spc,tmp,fault
+       mfsp            %sr7,\tmp
+       or,COND(<>)     %r0,\spc,%r0    /* user may execute gateway page
+                                        * as kernel, so defeat the space
+                                        * check if it is */
+       copy            \spc,\tmp
+       or,COND(=)      %r0,\tmp,%r0    /* nullify if executing as kernel */
+       cmpb,COND(<>),n \tmp,\spc,\fault
+       .endm
+
+       /* Look up a PTE in a 2-Level scheme (faulting at each
+        * level if the entry isn't present 
+        *
+        * NOTE: we use ldw even for LP64 because our pte
+        * and pmd are allocated <4GB */
+       .macro          L2_ptep pmd,pte,index,va,fault
+#if PT_NLEVELS == 3
+       EXTR            \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
+#else
+       EXTR            \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
+#endif
+       DEP             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
+       copy            %r0,\pte
+       ldw,s           \index(\pmd),\pmd
+       EXTR            \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
+       bb,>=,n         \pmd,_PAGE_PRESENT_BIT,\fault
+       DEP             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
+       shladd          \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
+       LDREG           %r0(\pmd),\pte          /* pmd is now pte */
+       bb,>=,n         \pte,_PAGE_PRESENT_BIT,\fault
+       .endm
+
+       /* Look up PTE in a 3-Level scheme.
+        *
+        * Here we implement a Hybrid L2/L3 scheme: we allocate the
+        * first pmd adjacent to the pgd.  This means that we can
+        * subtract a constant offset to get to it.  The pmd and pgd
+        * sizes are arranged so that a single pmd covers 4GB (giving
+        * a full LP64 process access to 8TB) so our lookups are
+        * effectively L2 for the first 4GB of the kernel (i.e. for
+        * all ILP32 processes and all the kernel for machines with
+        * under 4GB of memory) */
+       .macro          L3_ptep pgd,pte,index,va,fault
+       extrd,u         \va,63-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
+       copy            %r0,\pte
+       extrd,u,*=      \va,31,32,%r0
+       ldw,s           \index(\pgd),\pgd
+       extrd,u,*<>     \va,31,32,%r0
+       ldo             ASM_PGD_PMD_OFFSET(\pgd),\pgd
+       extrd,u,*=      \va,31,32,%r0
+       bb,>=,n         \pgd,_PAGE_PRESENT_BIT,\fault
+       L2_ptep         \pgd,\pte,\index,\va,\fault
+       .endm
+
+       /* Set the _PAGE_ACCESSED bit of the PTE.  Be clever and
+        * don't needlessly dirty the cache line if it was already set */
+       .macro          update_ptep     ptep,pte,tmp,tmp1
+       ldi             _PAGE_ACCESSED,\tmp1
+       or              \tmp1,\pte,\tmp
+       and,COND(<>)    \tmp1,\pte,%r0
+       STREG           \tmp,0(\ptep)
+       .endm
+
+       /* Set the dirty bit (and accessed bit).  No need to be
+        * clever, this is only used from the dirty fault */
+       .macro          update_dirty    ptep,pte,tmp,tmp1
+       ldi             _PAGE_ACCESSED|_PAGE_DIRTY,\tmp
+       or              \tmp,\pte,\pte
+       STREG           \pte,0(\ptep)
+       .endm
+
+       /* Convert the pte and prot to tlb insertion values.  How
+        * this happens is quite subtle, read below */
+       .macro          make_insert_tlb spc,pte,prot
+       space_to_prot   \spc \prot        /* create prot id from space */
+       /* The following is the real subtlety.  This is depositing
+        * T <-> _PAGE_REFTRAP
+        * D <-> _PAGE_DIRTY
+        * B <-> _PAGE_DMB (memory break)
+        *
+        * Then incredible subtlety: The access rights are
+        * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ
+        * See 3-14 of the parisc 2.0 manual
+        *
+        * Finally, _PAGE_READ goes in the top bit of PL1 (so we
+        * trigger an access rights trap in user space if the user
+        * tries to read an unreadable page */
+       depd            \pte,8,7,\prot
+
+       /* PAGE_USER indicates the page can be read with user privileges,
+        * so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
+        * contains _PAGE_READ */
+       extrd,u,*=      \pte,_PAGE_USER_BIT+32,1,%r0
+       depdi           7,11,3,\prot
+       /* If we're a gateway page, drop PL2 back to zero for promotion
+        * to kernel privilege (so we can execute the page as kernel).
+        * Any privilege promotion page always denys read and write */
+       extrd,u,*=      \pte,_PAGE_GATEWAY_BIT+32,1,%r0
+       depd            %r0,11,2,\prot  /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for iitlbt */
+
+       depd            %r0,63,PAGE_SHIFT,\pte
+       extrd,u         \pte,56,32,\pte
+       .endm
+
+       /* Identical macro to make_insert_tlb above, except it
+        * makes the tlb entry for the differently formatted pa11
+        * insertion instructions */
+       .macro          make_insert_tlb_11      spc,pte,prot
+       zdep            \spc,30,15,\prot
+       dep             \pte,8,7,\prot
+       extru,=         \pte,_PAGE_NO_CACHE_BIT,1,%r0
+       depi            1,12,1,\prot
+       extru,=         \pte,_PAGE_USER_BIT,1,%r0
+       depi            7,11,3,\prot   /* Set for user space (1 rsvd for read) */
+       extru,=         \pte,_PAGE_GATEWAY_BIT,1,%r0
+       depi            0,11,2,\prot    /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for iitlba */
+
+       depi            0,31,12,\pte
+       extru           \pte,24,25,\pte
+
+       .endm
+
+       /* This is for ILP32 PA2.0 only.  The TLB insertion needs
+        * to extend into I/O space if the address is 0xfXXXXXXX
+        * so we extend the f's into the top word of the pte in
+        * this case */
+       .macro          f_extend        pte,tmp
+       extrd,s         \pte,42,4,\tmp
+       addi,<>         1,\tmp,%r0
+       extrd,s         \pte,63,25,\pte
+       .endm
+
+       /* The alias region is an 8MB aligned 16MB to do clear and
+        * copy user pages at addresses congruent with the user
+        * virtual address.
+        *
+        * To use the alias page, you set %r26 up with the to TLB
+        * entry (identifying the physical page) and %r23 up with
+        * the from tlb entry (or nothing if only a to entry---for
+        * clear_user_page_asm) */
+       .macro          do_alias        spc,tmp,tmp1,va,pte,prot,fault
+       cmpib,COND(<>),n 0,\spc,\fault
+       ldil            L%(TMPALIAS_MAP_START),\tmp
+#if defined(__LP64__) && (TMPALIAS_MAP_START >= 0x80000000)
+       /* on LP64, ldi will sign extend into the upper 32 bits,
+        * which is behaviour we don't want */
+       depdi           0,31,32,\tmp
+#endif
+       copy            \va,\tmp1
+       DEPI            0,31,23,\tmp1
+       cmpb,COND(<>),n \tmp,\tmp1,\fault
+       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),\prot
+       depd,z          \prot,8,7,\prot
+       /*
+        * OK, it is in the temp alias region, check whether "from" or "to".
+        * Check "subtle" note in pacache.S re: r23/r26.
+        */
+#ifdef __LP64__
+       extrd,u,*=      \va,41,1,%r0
+#else
+       extrw,u,=       \va,9,1,%r0
+#endif
+       or,COND(tr)     %r23,%r0,\pte
+       or              %r26,%r0,\pte
+       .endm 
+
+
        /*
         * Align fault_vector_20 on 4K boundary so that both
         * fault_vector_11 and fault_vector_20 are on the
@@ -979,82 +1203,23 @@ skip_save_ior:
 #ifdef __LP64__
 
 dtlb_miss_20w:
-       extrd,u         spc,63,7,t1     /* adjust va */
-       depd            t1,31,7,va      /* adjust va */
-       depdi           0,63,7,spc      /* adjust space */
-       mfctl           %cr25,ptp       /* Assume user space miss */
-       or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extrd,u         va,33,9,t1      /* Get pgd index */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,*<>,n       t0,spc,dtlb_fault /* forward */
-
-       /* First level page table lookup */
-
-       ldd,s           t1(ptp),ptp
-       extrd,u         va,42,9,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
-       depdi           0,63,12,ptp     /* clear prot bits */
-
-       /* Second level page table lookup */
+       space_adjust    spc,va,t0
+       get_pgd         spc,ptp
+       space_check     spc,t0,dtlb_fault
 
-       ldd,s           t0(ptp),ptp
-       extrd,u         va,51,9,t0     /* get third-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
-       depdi           0,63,12,ptp     /* clear prot bits */
+       L3_ptep         ptp,pte,t0,va,dtlb_check_alias_20w
 
-       /* Third level page table lookup */
-
-       shladd           t0,3,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldd              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
-
-       /* Check whether the "accessed" bit was set, otherwise do so */
-
-       or              t1,pte,t0       /* t0 has R bit set */
-       and,*<>         t1,pte,%r0      /* test and nullify if already set */
-       std             t0,0(ptp)       /* write back pte */
-
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
-
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for idtlbt */
+       update_ptep     ptp,pte,t0,t1
 
-       depdi           0,63,12,pte
-       extrd,u         pte,56,52,pte
+       make_insert_tlb spc,pte,prot
+       
        idtlbt          pte,prot
 
        rfir
        nop
 
 dtlb_check_alias_20w:
-
-       /* Check to see if fault is in the temporary alias region */
-
-       cmpib,*<>,n     0,spc,dtlb_fault /* forward */
-       ldil            L%(TMPALIAS_MAP_START),t0
-       copy            va,t1
-       depdi           0,63,23,t1
-       cmpb,*<>,n      t0,t1,dtlb_fault /* forward */
-       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
-       depd,z          prot,8,7,prot
-
-       /*
-        * OK, it is in the temp alias region, check whether "from" or "to".
-        * Check "subtle" note in pacache.S re: r23/r26.
-        */
-
-       extrd,u,*=      va,41,1,r0
-       or,*tr          %r23,%r0,pte    /* If "from" use "from" page */
-       or,*            %r26,%r0,pte    /* else "to", use "to" page  */
+       do_alias        spc,t0,t1,va,pte,prot,dtlb_fault
 
        idtlbt          pte,prot
 
@@ -1062,51 +1227,16 @@ dtlb_check_alias_20w:
        nop
 
 nadtlb_miss_20w:
-       extrd,u         spc,63,7,t1     /* adjust va */
-       depd            t1,31,7,va      /* adjust va */
-       depdi           0,63,7,spc      /* adjust space */
-       mfctl           %cr25,ptp       /* Assume user space miss */
-       or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extrd,u         va,33,9,t1      /* Get pgd index */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,*<>,n       t0,spc,nadtlb_fault /* forward */
-
-       /* First level page table lookup */
-
-       ldd,s           t1(ptp),ptp
-       extrd,u         va,42,9,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
-       depdi           0,63,12,ptp     /* clear prot bits */
-
-       /* Second level page table lookup */
-
-       ldd,s           t0(ptp),ptp
-       extrd,u         va,51,9,t0     /* get third-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
-       depdi           0,63,12,ptp     /* clear prot bits */
-
-       /* Third level page table lookup */
+       space_adjust    spc,va,t0
+       get_pgd         spc,ptp
+       space_check     spc,t0,nadtlb_fault
 
-       shladd           t0,3,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldd              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
+       L3_ptep         ptp,pte,t0,va,nadtlb_check_flush_20w
 
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
+       update_ptep     ptp,pte,t0,t1
 
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+       make_insert_tlb spc,pte,prot
 
-       /* Get rid of prot bits and convert to page addr for idtlbt */
-
-       depdi           0,63,12,pte
-       extrd,u         pte,56,52,pte
        idtlbt          pte,prot
 
        rfir
@@ -1132,49 +1262,15 @@ nadtlb_check_flush_20w:
 #else
 
 dtlb_miss_11:
-       mfctl           %cr25,ptp       /* Assume user space miss */
-       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extru           va,9,10,t1      /* Get pgd index */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,dtlb_fault /* forward */
-
-       /* First level page table lookup */
-
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
-       depi            0,31,12,ptp     /* clear prot bits */
+       get_pgd         spc,ptp
 
-       /* Second level page table lookup */
+       space_check     spc,t0,dtlb_fault
 
-       sh2addl          t0,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
+       L2_ptep         ptp,pte,t0,va,dtlb_check_alias_11
 
-       /* Check whether the "accessed" bit was set, otherwise do so */
+       update_ptep     ptp,pte,t0,t1
 
-       or              t1,pte,t0       /* t0 has R bit set */
-       and,<>          t1,pte,%r0      /* test and nullify if already set */
-       stw             t0,0(ptp)       /* write back pte */
-
-       zdep            spc,30,15,prot  /* create prot id from space */
-       dep             pte,8,7,prot    /* add in prot bits from pte */
-
-       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
-       depi            1,12,1,prot
-       extru,=         pte,_PAGE_USER_BIT,1,r0
-       depi            7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
-       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for idtlba */
-
-       depi            0,31,12,pte
-       extru           pte,24,25,pte
+       make_insert_tlb_11      spc,pte,prot
 
        mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
@@ -1215,43 +1311,16 @@ dtlb_check_alias_11:
        nop
 
 nadtlb_miss_11:
-       mfctl           %cr25,ptp       /* Assume user space miss */
-       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extru           va,9,10,t1      /* Get pgd index */
+       get_pgd         spc,ptp
 
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
+       space_check     spc,t0,nadtlb_fault
 
-       /* First level page table lookup */
+       L2_ptep         ptp,pte,t0,va,nadtlb_check_flush_11
 
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
-       depi            0,31,12,ptp     /* clear prot bits */
+       update_ptep     ptp,pte,t0,t1
 
-       /* Second level page table lookup */
+       make_insert_tlb_11      spc,pte,prot
 
-       sh2addl          t0,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
-
-       zdep            spc,30,15,prot  /* create prot id from space */
-       dep             pte,8,7,prot    /* add in prot bits from pte */
-
-       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
-       depi            1,12,1,prot
-       extru,=         pte,_PAGE_USER_BIT,1,r0
-       depi            7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
-       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for idtlba */
-
-       depi            0,31,12,pte
-       extru           pte,24,25,pte
 
        mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
@@ -1289,120 +1358,44 @@ nadtlb_check_flush_11:
        nop
 
 dtlb_miss_20:
-       mfctl           %cr25,ptp       /* Assume user space miss */
-       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extru           va,9,10,t1      /* Get pgd index */
+       space_adjust    spc,va,t0
+       get_pgd         spc,ptp
+       space_check     spc,t0,dtlb_fault
 
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,dtlb_fault /* forward */
+       L2_ptep         ptp,pte,t0,va,dtlb_check_alias_20
 
-       /* First level page table lookup */
+       update_ptep     ptp,pte,t0,t1
 
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
-       depi            0,31,12,ptp     /* clear prot bits */
+       make_insert_tlb spc,pte,prot
 
-       /* Second level page table lookup */
+       f_extend        pte,t0
 
-       sh2addl          t0,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
-
-       /* Check whether the "accessed" bit was set, otherwise do so */
-
-       or              t1,pte,t0       /* t0 has R bit set */
-       and,<>          t1,pte,%r0      /* test and nullify if already set */
-       stw             t0,0(ptp)       /* write back pte */
-
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
-
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for idtlbt */
-
-       extrd,s         pte,35,4,t0
-       depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0 
-        extrd,u,*tr     pte,56,25,pte 
-       extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */ 
        idtlbt          pte,prot
 
        rfir
        nop
 
 dtlb_check_alias_20:
-
-       /* Check to see if fault is in the temporary alias region */
-
-       cmpib,<>,n      0,spc,dtlb_fault /* forward */
-       ldil            L%(TMPALIAS_MAP_START),t0
-       copy            va,t1
-       depwi           0,31,23,t1
-       cmpb,<>,n       t0,t1,dtlb_fault /* forward */
-       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
-       depd,z          prot,8,7,prot
-
-       /*
-        * OK, it is in the temp alias region, check whether "from" or "to".
-        * Check "subtle" note in pacache.S re: r23/r26.
-        */
-
-       extrw,u,=       va,9,1,r0
-       or,tr           %r23,%r0,pte    /* If "from" use "from" page */
-       or              %r26,%r0,pte    /* else "to", use "to" page  */
-
+       do_alias        spc,t0,t1,va,pte,prot,dtlb_fault
+       
        idtlbt          pte,prot
 
        rfir
        nop
 
 nadtlb_miss_20:
-       mfctl           %cr25,ptp       /* Assume user space miss */
-       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extru           va,9,10,t1      /* Get pgd index */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
-
-       /* First level page table lookup */
+       get_pgd         spc,ptp
 
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
-       depi            0,31,12,ptp     /* clear prot bits */
+       space_check     spc,t0,nadtlb_fault
 
-       /* Second level page table lookup */
+       L2_ptep         ptp,pte,t0,va,nadtlb_check_flush_20
 
-       sh2addl          t0,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
+       update_ptep     ptp,pte,t0,t1
 
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
+       make_insert_tlb spc,pte,prot
 
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for idtlbt */
-
-        extrd,s         pte,35,4,t0
-        depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
-        extrd,u,*tr     pte,56,25,pte
-        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+       f_extend        pte,t0
+       
         idtlbt          pte,prot
 
        rfir
@@ -1475,119 +1468,33 @@ itlb_miss_20w:
         * on the gateway page which is in the kernel address space.
         */
 
-       extrd,u         spc,63,7,t1     /* adjust va */
-       depd            t1,31,7,va      /* adjust va */
-       depdi           0,63,7,spc      /* adjust space */
-       cmpib,*=        0,spc,itlb_miss_kernel_20w
-       extrd,u         va,33,9,t1      /* Get pgd index */
-
-       mfctl           %cr25,ptp       /* load user pgd */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,*<>,n      t0,spc,itlb_fault /* forward */
-
-       /* First level page table lookup */
-
-itlb_miss_common_20w:
-       ldd,s           t1(ptp),ptp
-       extrd,u         va,42,9,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
-       depdi           0,63,12,ptp     /* clear prot bits */
+       space_adjust    spc,va,t0
+       get_pgd         spc,ptp
+       space_check     spc,t0,itlb_fault
 
-       /* Second level page table lookup */
+       L3_ptep         ptp,pte,t0,va,itlb_fault
 
-       ldd,s           t0(ptp),ptp
-       extrd,u         va,51,9,t0     /* get third-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
-       depdi           0,63,12,ptp     /* clear prot bits */
+       update_ptep     ptp,pte,t0,t1
 
-       /* Third level page table lookup */
-
-       shladd           t0,3,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldd              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,itlb_fault
-
-       /* Check whether the "accessed" bit was set, otherwise do so */
-
-       or              t1,pte,t0       /* t0 has R bit set */
-       and,*<>         t1,pte,%r0      /* test and nullify if already set */
-       std             t0,0(ptp)       /* write back pte */
-
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
-
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for iitlbt */
-
-       depdi           0,63,12,pte
-       extrd,u         pte,56,32,pte
+       make_insert_tlb spc,pte,prot
+       
        iitlbt          pte,prot
 
        rfir
        nop
 
-itlb_miss_kernel_20w:
-       b               itlb_miss_common_20w
-       mfctl           %cr24,ptp       /* Load kernel pgd */
 #else
 
 itlb_miss_11:
+       get_pgd         spc,ptp
 
-       /*
-        * I miss is a little different, since we allow users to fault
-        * on the gateway page which is in the kernel address space.
-        */
-
-       cmpib,=         0,spc,itlb_miss_kernel_11
-       extru           va,9,10,t1      /* Get pgd index */
-
-       mfctl           %cr25,ptp       /* load user pgd */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,itlb_fault /* forward */
-
-       /* First level page table lookup */
-
-itlb_miss_common_11:
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
-       depi            0,31,12,ptp     /* clear prot bits */
-
-       /* Second level page table lookup */
+       space_check     spc,t0,itlb_fault
 
-       sh2addl          t0,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,itlb_fault
+       L2_ptep         ptp,pte,t0,va,itlb_fault
 
-       /* Check whether the "accessed" bit was set, otherwise do so */
+       update_ptep     ptp,pte,t0,t1
 
-       or              t1,pte,t0       /* t0 has R bit set */
-       and,<>          t1,pte,%r0      /* test and nullify if already set */
-       stw             t0,0(ptp)       /* write back pte */
-
-       zdep            spc,30,15,prot  /* create prot id from space */
-       dep             pte,8,7,prot    /* add in prot bits from pte */
-
-       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
-       depi            1,12,1,prot
-       extru,=         pte,_PAGE_USER_BIT,1,r0
-       depi            7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
-       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for iitlba */
-
-       depi            0,31,12,pte
-       extru           pte,24,25,pte
+       make_insert_tlb_11      spc,pte,prot
 
        mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
@@ -1600,106 +1507,35 @@ itlb_miss_common_11:
        rfir
        nop
 
-itlb_miss_kernel_11:
-       b               itlb_miss_common_11
-       mfctl           %cr24,ptp       /* Load kernel pgd */
-
 itlb_miss_20:
+       get_pgd         spc,ptp
 
-       /*
-        * I miss is a little different, since we allow users to fault
-        * on the gateway page which is in the kernel address space.
-        */
-
-       cmpib,=         0,spc,itlb_miss_kernel_20
-       extru           va,9,10,t1      /* Get pgd index */
-
-       mfctl           %cr25,ptp       /* load user pgd */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,itlb_fault /* forward */
+       space_check     spc,t0,itlb_fault
 
-       /* First level page table lookup */
+       L2_ptep         ptp,pte,t0,va,itlb_fault
 
-itlb_miss_common_20:
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
-       depi            0,31,12,ptp     /* clear prot bits */
+       update_ptep     ptp,pte,t0,t1
 
-       /* Second level page table lookup */
+       make_insert_tlb spc,pte,prot
 
-       sh2addl          t0,ptp,ptp
-       ldi             _PAGE_ACCESSED,t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,itlb_fault
+       f_extend        pte,t0  
 
-       /* Check whether the "accessed" bit was set, otherwise do so */
-
-       or              t1,pte,t0       /* t0 has R bit set */
-       and,<>          t1,pte,%r0      /* test and nullify if already set */
-       stw             t0,0(ptp)       /* write back pte */
-
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
-
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for iitlbt */
-
-        extrd,s         pte,35,4,t0 
-        depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
-        extrd,u,*tr     pte,56,25,pte 
-        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
        iitlbt          pte,prot
 
        rfir
        nop
 
-
-itlb_miss_kernel_20:
-       b               itlb_miss_common_20
-       mfctl           %cr24,ptp       /* Load kernel pgd */
 #endif
 
 #ifdef __LP64__
 
 dbit_trap_20w:
-       extrd,u         spc,63,7,t1     /* adjust va */
-       depd            t1,31,7,va      /* adjust va */
-       depdi           0,1,2,va        /* adjust va */
-       depdi           0,63,7,spc      /* adjust space */
-       mfctl           %cr25,ptp       /* Assume user space miss */
-       or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extrd,u         va,33,9,t1      /* Get pgd index */
+       space_adjust    spc,va,t0
+       get_pgd         spc,ptp
+       space_check     spc,t0,dbit_fault
 
-       mfsp            %sr7,t0         /* Get current space */
-       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,*<>,n       t0,spc,dbit_fault /* forward */
+       L3_ptep         ptp,pte,t0,va,dbit_fault
 
-       /* First level page table lookup */
-
-       ldd,s           t1(ptp),ptp
-       extrd,u         va,42,9,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
-       depdi           0,63,12,ptp     /* clear prot bits */
-
-       /* Second level page table lookup */
-
-       ldd,s           t0(ptp),ptp
-       extrd,u         va,51,9,t0     /* get third-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
-       depdi           0,63,12,ptp     /* clear prot bits */
-
-       /* Third level page table lookup */
-
-       shladd           t0,3,ptp,ptp
 #ifdef CONFIG_SMP
        CMPIB=,n        0,spc,dbit_nolock_20w
        ldil            L%PA(pa_dbit_lock),t0
@@ -1712,27 +1548,10 @@ dbit_spin_20w:
 
 dbit_nolock_20w:
 #endif
-       ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
-       ldd              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
-
-       /* Set Accessed and Dirty bits in the pte */
-
-       or              t1,pte,pte
-       std             pte,0(ptp)      /* write back pte */
+       update_dirty    ptp,pte,t0,t1
 
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
-
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for idtlbt */
-
-       depdi           0,63,12,pte
-       extrd,u         pte,56,52,pte
+       make_insert_tlb spc,pte,prot
+               
        idtlbt          pte,prot
 #ifdef CONFIG_SMP
        CMPIB=,n        0,spc,dbit_nounlock_20w
@@ -1747,25 +1566,13 @@ dbit_nounlock_20w:
 #else
 
 dbit_trap_11:
-       mfctl           %cr25,ptp       /* Assume user space trap */
-       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extru           va,9,10,t1      /* Get pgd index */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,dbit_fault /* forward */
 
-       /* First level page table lookup */
+       get_pgd         spc,ptp
 
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
-       depi            0,31,12,ptp     /* clear prot bits */
+       space_check     spc,t0,dbit_fault
 
-       /* Second level page table lookup */
+       L2_ptep         ptp,pte,t0,va,dbit_fault
 
-       sh2addl          t0,ptp,ptp
 #ifdef CONFIG_SMP
        CMPIB=,n        0,spc,dbit_nolock_11
        ldil            L%PA(pa_dbit_lock),t0
@@ -1778,29 +1585,9 @@ dbit_spin_11:
 
 dbit_nolock_11:
 #endif
-       ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
+       update_dirty    ptp,pte,t0,t1
 
-       /* Set Accessed and Dirty bits in the pte */
-
-       or              t1,pte,pte
-       stw             pte,0(ptp)      /* write back pte */
-
-       zdep            spc,30,15,prot  /* create prot id from space */
-       dep             pte,8,7,prot    /* add in prot bits from pte */
-
-       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
-       depi            1,12,1,prot
-       extru,=         pte,_PAGE_USER_BIT,1,r0
-       depi            7,11,3,prot /* Set for user space (1 rsvd for read) */
-       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
-       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-       /* Get rid of prot bits and convert to page addr for idtlba */
-
-       depi            0,31,12,pte
-       extru           pte,24,25,pte
+       make_insert_tlb_11      spc,pte,prot
 
        mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
@@ -1821,25 +1608,12 @@ dbit_nounlock_11:
        nop
 
 dbit_trap_20:
-       mfctl           %cr25,ptp       /* Assume user space trap */
-       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
-       mfctl           %cr24,ptp       /* Load kernel pgd instead */
-       extru           va,9,10,t1      /* Get pgd index */
-
-       mfsp            %sr7,t0         /* Get current space */
-       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       cmpb,<>,n       t0,spc,dbit_fault /* forward */
+       get_pgd         spc,ptp
 
-       /* First level page table lookup */
+       space_check     spc,t0,dbit_fault
 
-       ldwx,s          t1(ptp),ptp
-       extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
-       depi            0,31,12,ptp     /* clear prot bits */
+       L2_ptep         ptp,pte,t0,va,dbit_fault
 
-       /* Second level page table lookup */
-
-       sh2addl          t0,ptp,ptp
 #ifdef CONFIG_SMP
        CMPIB=,n        0,spc,dbit_nolock_20
        ldil            L%PA(pa_dbit_lock),t0
@@ -1852,28 +1626,12 @@ dbit_spin_20:
 
 dbit_nolock_20:
 #endif
-       ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
-       ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
-
-       /* Set Accessed and Dirty bits in the pte */
+       update_dirty    ptp,pte,t0,t1
 
-       or              t1,pte,pte
-       stw             pte,0(ptp)      /* write back pte */
+       make_insert_tlb spc,pte,prot
 
-       space_to_prot   spc prot        /* create prot id from space */
-       depd            pte,8,7,prot    /* add in prot bits from pte */
-
-       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
-       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
-       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
-       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
-
-        extrd,s         pte,35,4,t0 
-        depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
-        extrd,u,*tr     pte,56,25,pte 
-        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+       f_extend        pte,t0
+       
         idtlbt          pte,prot
 
 #ifdef CONFIG_SMP
@@ -2285,9 +2043,13 @@ syscall_check_sig:
        bb,<,n  %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
 
 syscall_restore:
-       LDREG   TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19    /* get ti flags */
-       bb,<    %r19, 31-TIF_SYSCALL_TRACE,syscall_restore_rfi
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* delay slot! */
+       /* Are we being ptraced? */
+       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
+
+       LDREG   TASK_PTRACE(%r1), %r19
+       bb,<    %r19,31,syscall_restore_rfi
+       nop
+
        ldo     TASK_PT_FR31(%r1),%r19             /* reload fpregs */
        rest_fp %r19
 
@@ -2337,7 +2099,6 @@ syscall_restore:
         * the most efficient way of doing things, but it works.
         */
 syscall_restore_rfi:
-       LDREG   TASK_PTRACE(%r1), %r19
        ldo     -1(%r0),%r2                        /* Set recovery cntr to -1 */
        mtctl   %r2,%cr0                           /*   for immediate trap */
        LDREG   TASK_PT_PSW(%r1),%r2               /* Get old PSW */