/* * Linux/PA-RISC Project (http://www.parisc-linux.org/) * * kernel entry points (interruptions, system call wrappers) * Copyright (C) 1999,2000 Philipp Rumpf * Copyright (C) 1999 SuSE GmbH Nuernberg * Copyright (C) 2000 Hewlett-Packard (John Marvin) * Copyright (C) 1999 Hewlett-Packard (Frank Rowand) * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <asm/asm-offsets.h> /* we have the following possibilities to act on an interruption: * - handle in assembly and use shadowed registers only * - save registers to kernel stack and handle in assembly or C */ #include <asm/psw.h>#include <asm/cache.h> /* for L1_CACHE_SHIFT */#include <asm/assembly.h> /* for LDREG/STREG defines */#include <asm/pgtable.h>#include <asm/signal.h>#include <asm/unistd.h>#include <asm/thread_info.h> #include <linux/linkage.h> #ifdef CONFIG_64BIT#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 .import pa_dbit_lock,data /* space_to_prot macro creates a prot id from a space id */ #if (SPACEID_SHIFT) == 0 .macro space_to_prot spc prot depd,z \spc,62,31,\prot .endm#else .macro space_to_prot spc prot extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot .endm#endif /* Switch to virtual mapping, trashing only %r1 */ .macro virt_map /* pcxt_ssm_bug */ rsm PSW_SM_I, %r0 /* barrier for "Relied upon Translation */ mtsp %r0, %sr4 mtsp %r0, %sr5 mfsp %sr7, %r1 or,= %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */ mtsp %r1, %sr3 tovirt_r1 %r29 load32 KERNEL_PSW, %r1 rsm PSW_SM_QUIET,%r0 /* second "heavy weight" ctl op */ mtsp %r0, %sr6 mtsp %r0, %sr7 mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ mtctl %r1, %ipsw load32 4f, %r1 mtctl %r1, %cr18 /* Set IIAOQ tail */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* Set IIAOQ head */ rfir nop4: .endm /* * The "get_stack" macros are responsible for determining the * kernel stack value. * * For Faults: * If sr7 == 0 * Already using a kernel stack, so call the * get_stack_use_r30 macro to push a pt_regs structure * on the stack, and store registers there. * else * Need to set up a kernel stack, so call the * get_stack_use_cr30 macro to set up a pointer * to the pt_regs structure contained within the * task pointer pointed to by cr30. Set the stack * pointer to point to the end of the task structure. * * For Interrupts: * If sr7 == 0 * Already using a kernel stack, check to see if r30 * is already pointing to the per processor interrupt * stack. If it is, call the get_stack_use_r30 macro * to push a pt_regs structure on the stack, and store * registers there. Otherwise, call get_stack_use_cr31 * to get a pointer to the base of the interrupt stack * and push a pt_regs structure on that stack. * else * Need to set up a kernel stack, so call the * get_stack_use_cr30 macro to set up a pointer * to the pt_regs structure contained within the * task pointer pointed to by cr30. Set the stack * pointer to point to the end of the task structure. * N.B: We don't use the interrupt stack for the * first interrupt from userland, because signals/ * resched's are processed when returning to userland, * and we can sleep in those cases. * * Note that we use shadowed registers for temps until * we can save %r26 and %r29. %r26 is used to preserve * %r8 (a shadowed register) which temporarily contained * either the fault type ("code") or the eirr. We need * to use a non-shadowed register to carry the value over * the rfir in virt_map. We use %r26 since this value winds * up being passed as the argument to either do_cpu_irq_mask * or handle_interruption. %r29 is used to hold a pointer * the register save area, and once again, it needs to * be a non-shadowed register so that it survives the rfir. * * N.B. TASK_SZ_ALGN and PT_SZ_ALGN include space for a stack frame. */ .macro get_stack_use_cr30 /* we save the registers in the task struct */ mfctl %cr30, %r1 tophys %r1,%r9 LDREG TI_TASK(%r9), %r1 /* thread_info -> task_struct */ tophys %r1,%r9 ldo TASK_REGS(%r9),%r9 STREG %r30, PT_GR30(%r9) STREG %r29,PT_GR29(%r9) STREG %r26,PT_GR26(%r9) copy %r9,%r29 mfctl %cr30, %r1 ldo THREAD_SZ_ALGN(%r1), %r30 .endm .macro get_stack_use_r30 /* we put a struct pt_regs on the stack and save the registers there */ tophys %r30,%r9 STREG %r30,PT_GR30(%r9) ldo PT_SZ_ALGN(%r30),%r30 STREG %r29,PT_GR29(%r9) STREG %r26,PT_GR26(%r9) copy %r9,%r29 .endm .macro rest_stack LDREG PT_GR1(%r29), %r1 LDREG PT_GR30(%r29),%r30 LDREG PT_GR29(%r29),%r29 .endm /* default interruption handler * (calls traps.c:handle_interruption) */ .macro def code b intr_save ldi \code, %r8 .align 32 .endm /* Interrupt interruption handler * (calls irq.c:do_cpu_irq_mask) */ .macro extint code b intr_extint mfsp %sr7,%r16 .align 32 .endm .import os_hpmc, code /* HPMC handler */ .macro hpmc code nop /* must be a NOP, will be patched later */ load32 PA(os_hpmc), %r3 bv,n 0(%r3) nop .word 0 /* checksum (will be patched) */ .word PA(os_hpmc) /* address of handler */ .word 0 /* length of handler */ .endm /* * Performance Note: Instructions will be moved up into * this part of the code later on, once we are sure * that the tlb miss handlers are close to final form. */ /* Register definitions for tlb miss handler macros */ va = r8 /* virtual address for which the trap occured */ spc = r24 /* space for which the trap occured */ #ifndef CONFIG_64BIT /* * itlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro itlb_11 code mfctl %pcsq, spc b itlb_miss_11 mfctl %pcoq, va .align 32 .endm#endif /* * itlb miss interruption handler (parisc 2.0) */ .macro itlb_20 code mfctl %pcsq, spc#ifdef CONFIG_64BIT b itlb_miss_20w#else b itlb_miss_20#endif mfctl %pcoq, va .align 32 .endm #ifndef CONFIG_64BIT /* * naitlb miss interruption handler (parisc 1.1 - 32 bit) * * Note: naitlb misses will be treated * as an ordinary itlb miss for now. * However, note that naitlb misses * have the faulting address in the * IOR/ISR. */ .macro naitlb_11 code mfctl %isr,spc b itlb_miss_11 mfctl %ior,va /* FIXME: If user causes a naitlb miss, the priv level may not be in * lower bits of va, where the itlb miss handler is expecting them */ .align 32 .endm#endif /* * naitlb miss interruption handler (parisc 2.0) * * Note: naitlb misses will be treated * as an ordinary itlb miss for now. * However, note that naitlb misses * have the faulting address in the * IOR/ISR. */ .macro naitlb_20 code mfctl %isr,spc#ifdef CONFIG_64BIT b itlb_miss_20w#else b itlb_miss_20#endif mfctl %ior,va /* FIXME: If user causes a naitlb miss, the priv level may not be in * lower bits of va, where the itlb miss handler is expecting them */ .align 32 .endm #ifndef CONFIG_64BIT /* * dtlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro dtlb_11 code mfctl %isr, spc b dtlb_miss_11 mfctl %ior, va .align 32 .endm#endif /* * dtlb miss interruption handler (parisc 2.0) */ .macro dtlb_20 code mfctl %isr, spc#ifdef CONFIG_64BIT b dtlb_miss_20w#else b dtlb_miss_20#endif mfctl %ior, va .align 32 .endm #ifndef CONFIG_64BIT /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro nadtlb_11 code mfctl %isr,spc b nadtlb_miss_11 mfctl %ior,va .align 32 .endm#endif /* nadtlb miss interruption handler (parisc 2.0) */ .macro nadtlb_20 code mfctl %isr,spc#ifdef CONFIG_64BIT b nadtlb_miss_20w#else b nadtlb_miss_20#endif mfctl %ior,va .align 32 .endm #ifndef CONFIG_64BIT /* * dirty bit trap interruption handler (parisc 1.1 - 32 bit) */ .macro dbit_11 code mfctl %isr,spc b dbit_trap_11 mfctl %ior,va .align 32 .endm#endif /* * dirty bit trap interruption handler (parisc 2.0) */ .macro dbit_20 code mfctl %isr,spc#ifdef CONFIG_64BIT b dbit_trap_20w#else b dbit_trap_20#endif mfctl %ior,va .align 32 .endm /* The following are simple 32 vs 64 bit instruction * abstractions for the macros */ .macro EXTR reg1,start,length,reg2#ifdef CONFIG_64BIT extrd,u \reg1,32+\start,\length,\reg2#else extrw,u \reg1,\start,\length,\reg2#endif .endm .macro DEP reg1,start,length,reg2#ifdef CONFIG_64BIT depd \reg1,32+\start,\length,\reg2#else depw \reg1,\start,\length,\reg2#endif .endm .macro DEPI val,start,length,reg#ifdef CONFIG_64BIT 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 CONFIG_64BIT 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 /* space_check(spc,tmp,fault) spc - The space we saw the fault with. tmp - The place to store the current space. fault - Function to call on failure. 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, since the short pointers * can address up to 1TB */ .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 bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */ copy \pmd,%r9 SHLREG %r9,PxD_VALUE_SHIFT,\pmd EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index 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 withLines 1–500 of 2403. Load more
/* * Linux/PA-RISC Project (http://www.parisc-linux.org/) * * kernel entry points (interruptions, system call wrappers) * Copyright (C) 1999,2000 Philipp Rumpf * Copyright (C) 1999 SuSE GmbH Nuernberg * Copyright (C) 2000 Hewlett-Packard (John Marvin) * Copyright (C) 1999 Hewlett-Packard (Frank Rowand) * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <asm/asm-offsets.h> /* we have the following possibilities to act on an interruption: * - handle in assembly and use shadowed registers only * - save registers to kernel stack and handle in assembly or C */ #include <asm/psw.h> #include <asm/cache.h> /* for L1_CACHE_SHIFT */ #include <asm/assembly.h> /* for LDREG/STREG defines */ #include <asm/pgtable.h> #include <asm/signal.h> #include <asm/unistd.h> #include <asm/thread_info.h> #include <linux/linkage.h> #ifdef CONFIG_64BIT #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 .import pa_dbit_lock,data /* space_to_prot macro creates a prot id from a space id */ #if (SPACEID_SHIFT) == 0 .macro space_to_prot spc prot depd,z \spc,62,31,\prot .endm #else .macro space_to_prot spc prot extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot .endm #endif /* Switch to virtual mapping, trashing only %r1 */ .macro virt_map /* pcxt_ssm_bug */ rsm PSW_SM_I, %r0 /* barrier for "Relied upon Translation */ mtsp %r0, %sr4 mtsp %r0, %sr5 mfsp %sr7, %r1 or,= %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */ mtsp %r1, %sr3 tovirt_r1 %r29 load32 KERNEL_PSW, %r1 rsm PSW_SM_QUIET,%r0 /* second "heavy weight" ctl op */ mtsp %r0, %sr6 mtsp %r0, %sr7 mtctl %r0, %cr17 /* Clear IIASQ tail */ mtctl %r0, %cr17 /* Clear IIASQ head */ mtctl %r1, %ipsw load32 4f, %r1 mtctl %r1, %cr18 /* Set IIAOQ tail */ ldo 4(%r1), %r1 mtctl %r1, %cr18 /* Set IIAOQ head */ rfir nop 4: .endm /* * The "get_stack" macros are responsible for determining the * kernel stack value. * * For Faults: * If sr7 == 0 * Already using a kernel stack, so call the * get_stack_use_r30 macro to push a pt_regs structure * on the stack, and store registers there. * else * Need to set up a kernel stack, so call the * get_stack_use_cr30 macro to set up a pointer * to the pt_regs structure contained within the * task pointer pointed to by cr30. Set the stack * pointer to point to the end of the task structure. * * For Interrupts: * If sr7 == 0 * Already using a kernel stack, check to see if r30 * is already pointing to the per processor interrupt * stack. If it is, call the get_stack_use_r30 macro * to push a pt_regs structure on the stack, and store * registers there. Otherwise, call get_stack_use_cr31 * to get a pointer to the base of the interrupt stack * and push a pt_regs structure on that stack. * else * Need to set up a kernel stack, so call the * get_stack_use_cr30 macro to set up a pointer * to the pt_regs structure contained within the * task pointer pointed to by cr30. Set the stack * pointer to point to the end of the task structure. * N.B: We don't use the interrupt stack for the * first interrupt from userland, because signals/ * resched's are processed when returning to userland, * and we can sleep in those cases. * * Note that we use shadowed registers for temps until * we can save %r26 and %r29. %r26 is used to preserve * %r8 (a shadowed register) which temporarily contained * either the fault type ("code") or the eirr. We need * to use a non-shadowed register to carry the value over * the rfir in virt_map. We use %r26 since this value winds * up being passed as the argument to either do_cpu_irq_mask * or handle_interruption. %r29 is used to hold a pointer * the register save area, and once again, it needs to * be a non-shadowed register so that it survives the rfir. * * N.B. TASK_SZ_ALGN and PT_SZ_ALGN include space for a stack frame. */ .macro get_stack_use_cr30 /* we save the registers in the task struct */ mfctl %cr30, %r1 tophys %r1,%r9 LDREG TI_TASK(%r9), %r1 /* thread_info -> task_struct */ tophys %r1,%r9 ldo TASK_REGS(%r9),%r9 STREG %r30, PT_GR30(%r9) STREG %r29,PT_GR29(%r9) STREG %r26,PT_GR26(%r9) copy %r9,%r29 mfctl %cr30, %r1 ldo THREAD_SZ_ALGN(%r1), %r30 .endm .macro get_stack_use_r30 /* we put a struct pt_regs on the stack and save the registers there */ tophys %r30,%r9 STREG %r30,PT_GR30(%r9) ldo PT_SZ_ALGN(%r30),%r30 STREG %r29,PT_GR29(%r9) STREG %r26,PT_GR26(%r9) copy %r9,%r29 .endm .macro rest_stack LDREG PT_GR1(%r29), %r1 LDREG PT_GR30(%r29),%r30 LDREG PT_GR29(%r29),%r29 .endm /* default interruption handler * (calls traps.c:handle_interruption) */ .macro def code b intr_save ldi \code, %r8 .align 32 .endm /* Interrupt interruption handler * (calls irq.c:do_cpu_irq_mask) */ .macro extint code b intr_extint mfsp %sr7,%r16 .align 32 .endm .import os_hpmc, code /* HPMC handler */ .macro hpmc code nop /* must be a NOP, will be patched later */ load32 PA(os_hpmc), %r3 bv,n 0(%r3) nop .word 0 /* checksum (will be patched) */ .word PA(os_hpmc) /* address of handler */ .word 0 /* length of handler */ .endm /* * Performance Note: Instructions will be moved up into * this part of the code later on, once we are sure * that the tlb miss handlers are close to final form. */ /* Register definitions for tlb miss handler macros */ va = r8 /* virtual address for which the trap occured */ spc = r24 /* space for which the trap occured */ #ifndef CONFIG_64BIT /* * itlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro itlb_11 code mfctl %pcsq, spc b itlb_miss_11 mfctl %pcoq, va .align 32 .endm #endif /* * itlb miss interruption handler (parisc 2.0) */ .macro itlb_20 code mfctl %pcsq, spc #ifdef CONFIG_64BIT b itlb_miss_20w #else b itlb_miss_20 #endif mfctl %pcoq, va .align 32 .endm #ifndef CONFIG_64BIT /* * naitlb miss interruption handler (parisc 1.1 - 32 bit) * * Note: naitlb misses will be treated * as an ordinary itlb miss for now. * However, note that naitlb misses * have the faulting address in the * IOR/ISR. */ .macro naitlb_11 code mfctl %isr,spc b itlb_miss_11 mfctl %ior,va /* FIXME: If user causes a naitlb miss, the priv level may not be in * lower bits of va, where the itlb miss handler is expecting them */ .align 32 .endm #endif /* * naitlb miss interruption handler (parisc 2.0) * * Note: naitlb misses will be treated * as an ordinary itlb miss for now. * However, note that naitlb misses * have the faulting address in the * IOR/ISR. */ .macro naitlb_20 code mfctl %isr,spc #ifdef CONFIG_64BIT b itlb_miss_20w #else b itlb_miss_20 #endif mfctl %ior,va /* FIXME: If user causes a naitlb miss, the priv level may not be in * lower bits of va, where the itlb miss handler is expecting them */ .align 32 .endm #ifndef CONFIG_64BIT /* * dtlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro dtlb_11 code mfctl %isr, spc b dtlb_miss_11 mfctl %ior, va .align 32 .endm #endif /* * dtlb miss interruption handler (parisc 2.0) */ .macro dtlb_20 code mfctl %isr, spc #ifdef CONFIG_64BIT b dtlb_miss_20w #else b dtlb_miss_20 #endif mfctl %ior, va .align 32 .endm #ifndef CONFIG_64BIT /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */ .macro nadtlb_11 code mfctl %isr,spc b nadtlb_miss_11 mfctl %ior,va .align 32 .endm #endif /* nadtlb miss interruption handler (parisc 2.0) */ .macro nadtlb_20 code mfctl %isr,spc #ifdef CONFIG_64BIT b nadtlb_miss_20w #else b nadtlb_miss_20 #endif mfctl %ior,va .align 32 .endm #ifndef CONFIG_64BIT /* * dirty bit trap interruption handler (parisc 1.1 - 32 bit) */ .macro dbit_11 code mfctl %isr,spc b dbit_trap_11 mfctl %ior,va .align 32 .endm #endif /* * dirty bit trap interruption handler (parisc 2.0) */ .macro dbit_20 code mfctl %isr,spc #ifdef CONFIG_64BIT b dbit_trap_20w #else b dbit_trap_20 #endif mfctl %ior,va .align 32 .endm /* The following are simple 32 vs 64 bit instruction * abstractions for the macros */ .macro EXTR reg1,start,length,reg2 #ifdef CONFIG_64BIT extrd,u \reg1,32+\start,\length,\reg2 #else extrw,u \reg1,\start,\length,\reg2 #endif .endm .macro DEP reg1,start,length,reg2 #ifdef CONFIG_64BIT depd \reg1,32+\start,\length,\reg2 #else depw \reg1,\start,\length,\reg2 #endif .endm .macro DEPI val,start,length,reg #ifdef CONFIG_64BIT 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 CONFIG_64BIT 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 /* space_check(spc,tmp,fault) spc - The space we saw the fault with. tmp - The place to store the current space. fault - Function to call on failure. 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, since the short pointers * can address up to 1TB */ .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 bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */ copy \pmd,%r9 SHLREG %r9,PxD_VALUE_SHIFT,\pmd EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index 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