X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fparisc%2Fkernel%2Fentry.S;h=b1dd08b03552b178a4485e5c3d6d566b9483dd42;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=9c284947db7c93ac99720fe23b96e0f07243e1d9;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 9c284947d..b1dd08b03 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -440,8 +440,17 @@ mfctl %cr25,\reg .endm - /* Only allow faults on different spaces from the - * currently active one if we're the kernel */ + /* + 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 @@ -455,20 +464,28 @@ /* 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 */ + * 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 */ + 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 +#ifdef __LP64__ + shld %r9,PxD_VALUE_SHIFT,\pmd +#else + shlw %r9,PxD_VALUE_SHIFT,\pmd +#endif 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 */ + 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 @@ -489,10 +506,14 @@ copy %r0,\pte extrd,u,*= \va,31,32,%r0 ldw,s \index(\pgd),\pgd + extrd,u,*= \va,31,32,%r0 + bb,>=,n \pgd,_PxD_PRESENT_BIT,\fault + extrd,u,*= \va,31,32,%r0 + shld \pgd,PxD_VALUE_SHIFT,\index + extrd,u,*= \va,31,32,%r0 + copy \index,\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 @@ -507,7 +528,7 @@ /* 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 + .macro update_dirty ptep,pte,tmp ldi _PAGE_ACCESSED|_PAGE_DIRTY,\tmp or \tmp,\pte,\pte STREG \pte,0(\ptep) @@ -762,7 +783,7 @@ __kernel_thread: #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #endif - bl do_fork, %r2 + BL do_fork, %r2 copy %r1, %r24 /* pt_regs */ /* Parent Returns here */ @@ -783,7 +804,7 @@ __kernel_thread: ret_from_kernel_thread: /* Call schedule_tail first though */ - bl schedule_tail, %r2 + BL schedule_tail, %r2 nop LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1 @@ -815,7 +836,7 @@ __execve: #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #endif - bl sys_execve, %r2 + BL sys_execve, %r2 copy %r16, %r26 cmpib,=,n 0,%r28,intr_return /* forward */ @@ -927,6 +948,7 @@ syscall_exit_rfi: STREG %r19,PT_SR7(%r16) intr_return: + /* NOTE: Need to enable interrupts incase we schedule. */ ssm PSW_SM_I, %r0 /* Check for software interrupts */ @@ -970,6 +992,8 @@ intr_restore: ldo PT_FR31(%r29),%r1 rest_fp %r1 rest_general %r29 + + /* Create a "relied upon translation" PA 2.0 Arch. F-5 */ ssm 0,%r0 nop nop @@ -980,8 +1004,15 @@ intr_restore: nop tophys_r1 %r29 rsm (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0 + + /* Restore space id's and special cr's from PT_REGS + * structure pointed to by r29 */ rest_specials %r29 + + /* Important: Note that rest_stack restores r29 + * last (we are using it)! It also restores r1 and r30. */ rest_stack + rfi nop nop @@ -1024,7 +1055,14 @@ intr_do_resched: .import do_signal,code intr_do_signal: - /* Only do signals if we are returning to user space */ + /* + This check is critical to having LWS + working. The IASQ is zero on the gateway + page and we cannot deliver any signals until + we get off the gateway page. + + Only do signals if we are returning to user space + */ LDREG PT_IASQ0(%r16), %r20 CMPIB= 0,%r20,intr_restore /* backward */ nop @@ -1038,7 +1076,7 @@ intr_do_signal: ldo -16(%r30),%r29 /* Reference param save area */ #endif - bl do_signal,%r2 + BL do_signal,%r2 copy %r0, %r26 /* sigset_t *oldset = NULL */ b intr_restore @@ -1431,24 +1469,29 @@ nadtlb_emulate: * of the instruction. Since we don't insert a translation * we can get a lot of faults during a flush loop, so it makes * sense to try to do it here with minimum overhead. We only - * emulate fdc,fic & pdc instructions whose base and index - * registers are not shadowed. We defer everything else to the - * "slow" path. + * emulate fdc,fic,pdc,probew,prober instructions whose base + * and index registers are not shadowed. We defer everything + * else to the "slow" path. */ mfctl %cr19,%r9 /* Get iir */ + + /* PA 2.0 Arch Ref. Book pg 382 has a good description of the insn bits. + Checks for fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw */ + + /* Checks for fdc,fdce,pdc,"fic,4f" only */ ldi 0x280,%r16 and %r9,%r16,%r17 - cmpb,<>,n %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */ + cmpb,<>,n %r16,%r17,nadtlb_probe_check bb,>=,n %r9,26,nadtlb_nullify /* m bit not set, just nullify */ - b,l get_register,%r25 + BL get_register,%r25 extrw,u %r9,15,5,%r8 /* Get index register # */ CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */ copy %r1,%r24 - b,l get_register,%r25 + BL get_register,%r25 extrw,u %r9,10,5,%r8 /* Get base register # */ CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */ - b,l set_register,%r25 + BL set_register,%r25 add,l %r1,%r24,%r1 /* doesn't affect c/b bits */ nadtlb_nullify: @@ -1460,6 +1503,32 @@ nadtlb_nullify: rfir nop + /* + When there is no translation for the probe address then we + must nullify the insn and return zero in the target regsiter. + This will indicate to the calling code that it does not have + write/read privileges to this address. + + This should technically work for prober and probew in PA 1.1, + and also probe,r and probe,w in PA 2.0 + + WARNING: USE ONLY NON-SHADOW REGISTERS WITH PROBE INSN! + THE SLOW-PATH EMULATION HAS NOT BEEN WRITTEN YET. + + */ +nadtlb_probe_check: + ldi 0x80,%r16 + and %r9,%r16,%r17 + cmpb,<>,n %r16,%r17,nadtlb_fault /* Must be probe,[rw]*/ + BL get_register,%r25 /* Find the target register */ + extrw,u %r9,31,5,%r8 /* Get target register */ + CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */ + BL set_register,%r25 + copy %r0,%r1 /* Write zero to target register */ + b nadtlb_nullify /* Nullify return insn */ + nop + + #ifdef __LP64__ itlb_miss_20w: @@ -1548,7 +1617,7 @@ dbit_spin_20w: dbit_nolock_20w: #endif - update_dirty ptp,pte,t0,t1 + update_dirty ptp,pte,t1 make_insert_tlb spc,pte,prot @@ -1585,7 +1654,7 @@ dbit_spin_11: dbit_nolock_11: #endif - update_dirty ptp,pte,t0,t1 + update_dirty ptp,pte,t1 make_insert_tlb_11 spc,pte,prot @@ -1626,11 +1695,11 @@ dbit_spin_20: dbit_nolock_20: #endif - update_dirty ptp,pte,t0,t1 + update_dirty ptp,pte,t1 make_insert_tlb spc,pte,prot - f_extend pte,t0 + f_extend pte,t1 idtlbt pte,prot @@ -1750,7 +1819,7 @@ sys_fork_wrapper: LDREG PT_GR30(%r1),%r25 copy %r1,%r24 - bl sys_clone,%r2 + BL sys_clone,%r2 ldi SIGCHLD,%r26 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 @@ -1770,7 +1839,7 @@ wrapper_exit: /* Set the return value for the child */ child_return: - bl schedule_tail, %r2 + BL schedule_tail, %r2 nop LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1 @@ -1795,7 +1864,7 @@ sys_clone_wrapper: STREG %r2,PT_GR19(%r1) /* save for child */ STREG %r30,PT_GR21(%r1) - bl sys_clone,%r2 + BL sys_clone,%r2 copy %r1,%r24 b wrapper_exit @@ -1818,7 +1887,7 @@ sys_vfork_wrapper: STREG %r2,PT_GR19(%r1) /* save for child */ STREG %r30,PT_GR21(%r1) - bl sys_vfork,%r2 + BL sys_vfork,%r2 copy %r1,%r26 b wrapper_exit @@ -1881,10 +1950,10 @@ sys_rt_sigreturn_wrapper: STREG %r2, -RP_OFFSET(%r30) #ifdef __LP64__ ldo FRAME_SIZE(%r30), %r30 - bl sys_rt_sigreturn,%r2 + BL sys_rt_sigreturn,%r2 ldo -16(%r30),%r29 /* Reference param save area */ #else - bl sys_rt_sigreturn,%r2 + BL sys_rt_sigreturn,%r2 ldo FRAME_SIZE(%r30), %r30 #endif @@ -1912,7 +1981,7 @@ sys_sigaltstack_wrapper: STREG %r2, -RP_OFFSET(%r30) #ifdef __LP64__ ldo FRAME_SIZE(%r30), %r30 - bl do_sigaltstack,%r2 + b,l do_sigaltstack,%r2 ldo -16(%r30),%r29 /* Reference param save area */ #else bl do_sigaltstack,%r2 @@ -1932,7 +2001,7 @@ sys32_sigaltstack_wrapper: LDREG TASK_PT_GR30(%r24),%r24 STREG %r2, -RP_OFFSET(%r30) ldo FRAME_SIZE(%r30), %r30 - bl do_sigaltstack32,%r2 + b,l do_sigaltstack32,%r2 ldo -16(%r30),%r29 /* Reference param save area */ ldo -FRAME_SIZE(%r30), %r30 @@ -1950,7 +2019,7 @@ sys_rt_sigsuspend_wrapper: STREG %r2, -RP_OFFSET(%r30) #ifdef __LP64__ ldo FRAME_SIZE(%r30), %r30 - bl sys_rt_sigsuspend,%r2 + b,l sys_rt_sigsuspend,%r2 ldo -16(%r30),%r29 /* Reference param save area */ #else bl sys_rt_sigsuspend,%r2 @@ -1969,9 +2038,11 @@ sys_rt_sigsuspend_wrapper: .export syscall_exit syscall_exit: + /* NOTE: HP-UX syscalls also come through here - after hpux_syscall_exit fixes up return - values. */ + * after hpux_syscall_exit fixes up return + * values. */ + /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit * via syscall_exit_rfi if the signal was received while the process * was running. @@ -2070,11 +2141,15 @@ syscall_restore: LDREG TASK_PT_GR29(%r1),%r29 LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */ + /* NOTE: We use rsm/ssm pair to make this operation atomic */ rsm PSW_SM_I, %r0 LDREG TASK_PT_GR30(%r1),%r30 /* restore user sp */ mfsp %sr3,%r1 /* Get users space id */ mtsp %r1,%sr7 /* Restore sr7 */ ssm PSW_SM_I, %r0 + + /* Set sr2 to zero for userspace syscalls to work. */ + mtsp %r0,%sr2 mtsp %r1,%sr4 /* Restore sr4 */ mtsp %r1,%sr5 /* Restore sr5 */ mtsp %r1,%sr6 /* Restore sr6 */ @@ -2142,12 +2217,18 @@ syscall_restore_rfi: bb,< %r2,30,pt_regs_ok /* Branch if D set */ ldo TASK_REGS(%r1),%r25 reg_save %r25 /* Save r3 to r18 */ + + /* Save the current sr */ mfsp %sr0,%r2 STREG %r2,TASK_PT_SR0(%r1) + + /* Save the scratch sr */ mfsp %sr1,%r2 STREG %r2,TASK_PT_SR1(%r1) - mfsp %sr2,%r2 - STREG %r2,TASK_PT_SR2(%r1) + + /* sr2 should be set to zero for userspace syscalls */ + STREG %r0,TASK_PT_SR2(%r1) + pt_regs_ok: LDREG TASK_PT_GR31(%r1),%r2 depi 3,31,2,%r2 /* ensure return to user mode. */ @@ -2162,12 +2243,15 @@ pt_regs_ok: syscall_do_softirq: bl do_softirq,%r2 nop + /* NOTE: We enable I-bit incase we schedule later, + * and we might be going back to userspace if we were + * traced. */ b syscall_check_resched ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */ .import schedule,code syscall_do_resched: - bl schedule,%r2 + BL schedule,%r2 #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #else @@ -2191,7 +2275,7 @@ syscall_do_signal: #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #endif - bl do_signal,%r2 + BL do_signal,%r2 copy %r0, %r26 /* sigset_t *oldset = NULL */ LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1