#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
#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
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
#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
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
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
* 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
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
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
#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
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
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
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
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
* 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 */