From 7139bc1579901b53db7e898789e916ee2fb52d78 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Mon, 14 Jan 2013 19:45:00 -0500 Subject: [PARISC] Purge existing TLB entries in set_pte_at and ptep_set_wrprotect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch goes a long way toward fixing the minifail bug, and it  significantly improves the stability of SMP machines such as the rp3440.  When write  protecting a page for COW, we need to purge the existing translation.  Otherwise, the COW break doesn't occur as expected because the TLB may still have a stale entry which allows writes. [jejb: fix up checkpatch errors] Signed-off-by: John David Anglin Cc: stable@vger.kernel.org Signed-off-by: James Bottomley --- arch/parisc/kernel/cache.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 48e16dc20102..b89a85ab945e 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -419,6 +419,24 @@ void kunmap_parisc(void *addr) EXPORT_SYMBOL(kunmap_parisc); #endif +void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) +{ + unsigned long flags; + + /* Note: purge_tlb_entries can be called at startup with + no context. */ + + /* Disable preemption while we play with %sr1. */ + preempt_disable(); + mtsp(mm->context, 1); + purge_tlb_start(flags); + pdtlb(addr); + pitlb(addr); + purge_tlb_end(flags); + preempt_enable(); +} +EXPORT_SYMBOL(purge_tlb_entries); + void __flush_tlb_range(unsigned long sid, unsigned long start, unsigned long end) { -- cgit v1.2.2 From 1c4c6597b67f9986a09b34deb337a8b14f4adf3a Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 13 Jan 2013 22:04:18 +0000 Subject: parisc: Fix comment describing setup of access rights in entry.S This comment describes incredibly subtle code, so it should be right! Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index eb7850b46c25..7c9648919c91 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -483,7 +483,7 @@ * B <-> _PAGE_DMB (memory break) * * Then incredible subtlety: The access rights are - * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ + * _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE * See 3-14 of the parisc 2.0 manual * * Finally, _PAGE_READ goes in the top bit of PL1 (so we @@ -493,7 +493,7 @@ /* 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 */ + * 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 -- cgit v1.2.2 From fbd48433e79a6439264448c8e85c4816f5b32694 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 2 Sep 2012 14:23:59 +0000 Subject: parisc: fix possible memory leak in pat_query_module() pa_pdc_cell has been allocated in this function and so should be freed before leaving from the error handling cases. spatch with a semantic match is used to found this problem. (http://coccinelle.lip6.fr/) Signed-off-by: Wei Yongjun Signed-off-by: Helge Deller --- arch/parisc/kernel/inventory.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c index 08324aac3544..3295ef4a185d 100644 --- a/arch/parisc/kernel/inventory.c +++ b/arch/parisc/kernel/inventory.c @@ -186,12 +186,14 @@ pat_query_module(ulong pcell_loc, ulong mod_index) if (status != PDC_OK) { /* no more cell modules or error */ + kfree(pa_pdc_cell); return status; } temp = pa_pdc_cell->cba; dev = alloc_pa_dev(PAT_GET_CBA(temp), &(pa_pdc_cell->mod_path)); if (!dev) { + kfree(pa_pdc_cell); return PDC_OK; } -- cgit v1.2.2 From 7633453978c54874849c5f40487ac9e14d43fc12 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 3 Feb 2013 22:59:09 +0000 Subject: parisc: fixes and cleanups in page cache flushing (1/4) This is the first patch in a series of 4, with which the page cache flushing of parisc will gets fixed and enhanced. This even fixes the nasty "minifail" bug (http://wiki.parisc-linux.org/TestCases?highlight=%28minifail%29) which prevented parisc to stay an official debian port. Basically the flush in copy_user_page together with the TLB patch from commit 7139bc1579901b53db7e898789e916ee2fb52d78 is what fixes the minifail bug. This patch still uses the TMPALIAS approach. The new copy_user_page implementation calls flush_dcache_page_asm to flush the user dcache page (crucial for minifail fix) via a kernel TMPALIAS mapping. After that, it just copies the page using the kernel mapping. It does a final flush if needed. Generally it is hard to avoid doing some cache flushes using the kernel mapping (e.g., copy_to_user_page and copy_from_user_page). This patch depends on a subsequent change to pacache.S implementing clear_page_asm and copy_page_asm. These are optimized routines to clear and copy a page. The calls in clear_user_page and copy_user_page could be replaced by calls to memset and memcpy, respectively. I tested prefetch optimizations in clear_page_asm and copy_page_asm but didn't see any significant performance improvement on rp3440. I'm not sure if these are routines are significantly faster than memset and/or memcpy, but they are there for further performance evaluation. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/cache.c | 49 +++++++++++++++++---------------------- arch/parisc/kernel/parisc_ksyms.c | 5 ++-- 2 files changed, 24 insertions(+), 30 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index b89a85ab945e..d9cbb4b22c9f 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -329,17 +329,6 @@ EXPORT_SYMBOL(flush_kernel_dcache_page_asm); EXPORT_SYMBOL(flush_data_cache_local); EXPORT_SYMBOL(flush_kernel_icache_range_asm); -void clear_user_page_asm(void *page, unsigned long vaddr) -{ - unsigned long flags; - /* This function is implemented in assembly in pacache.S */ - extern void __clear_user_page_asm(void *page, unsigned long vaddr); - - purge_tlb_start(flags); - __clear_user_page_asm(page, vaddr); - purge_tlb_end(flags); -} - #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD; @@ -373,20 +362,9 @@ void __init parisc_setup_cache_timing(void) printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); } -extern void purge_kernel_dcache_page(unsigned long); -extern void clear_user_page_asm(void *page, unsigned long vaddr); - -void clear_user_page(void *page, unsigned long vaddr, struct page *pg) -{ - unsigned long flags; - - purge_kernel_dcache_page((unsigned long)page); - purge_tlb_start(flags); - pdtlb_kernel(page); - purge_tlb_end(flags); - clear_user_page_asm(page, vaddr); -} -EXPORT_SYMBOL(clear_user_page); +extern void purge_kernel_dcache_page_asm(unsigned long); +extern void clear_user_page_asm(void *, unsigned long); +extern void copy_user_page_asm(void *, void *, unsigned long); void flush_kernel_dcache_page_addr(void *addr) { @@ -399,11 +377,26 @@ void flush_kernel_dcache_page_addr(void *addr) } EXPORT_SYMBOL(flush_kernel_dcache_page_addr); +void clear_user_page(void *vto, unsigned long vaddr, struct page *page) +{ + clear_page_asm(vto); + if (!parisc_requires_coherency()) + flush_kernel_dcache_page_asm(vto); +} +EXPORT_SYMBOL(clear_user_page); + void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, - struct page *pg) + struct page *pg) { - /* no coherency needed (all in kmap/kunmap) */ - copy_user_page_asm(vto, vfrom); + /* Copy using kernel mapping. No coherency is needed + (all in kmap/kunmap) on machines that don't support + non-equivalent aliasing. However, the `from' page + needs to be flushed before it can be accessed through + the kernel mapping. */ + preempt_disable(); + flush_dcache_page_asm(__pa(vfrom), vaddr); + preempt_enable(); + copy_page_asm(vto, vfrom); if (!parisc_requires_coherency()) flush_kernel_dcache_page_asm(vto); } diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index ceec85de6290..6795dc6c995f 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -157,5 +157,6 @@ extern void _mcount(void); EXPORT_SYMBOL(_mcount); #endif -/* from pacache.S -- needed for copy_page */ -EXPORT_SYMBOL(copy_user_page_asm); +/* from pacache.S -- needed for clear/copy_page */ +EXPORT_SYMBOL(clear_page_asm); +EXPORT_SYMBOL(copy_page_asm); -- cgit v1.2.2 From 6d2ddc2f9414d5ad0d3f014416020579ccce1baf Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 3 Feb 2013 23:00:54 +0000 Subject: parisc: fixes and cleanups in page cache flushing (2/4) Implement clear_page_asm and copy_page_asm. These are optimized routines to clear and copy a page. I tested prefetch optimizations in clear_page_asm and copy_page_asm but didn't see any significant performance improvement on rp3440. I'm not sure if these are routines are significantly faster than memset and/or memcpy, but they are there for further performance evaluation. TLB purge operations on PA 1.X SMP machines are now serialized with the help of the new tlb_lock() and tlb_unlock() macros, since on some PA-RISC machines, TLB purges need to be serialized in software. Obviously, lock isn't needed in UP kernels. On PA 2.0 machines, there is a local TLB instruction which is much less disruptive to the memory subsystem. No lock is needed for local purge. Loops are also unrolled in flush_instruction_cache_local and flush_data_cache_local. The implementation of what used to be copy_user_page (now copy_user_page_asm) is now fixed. Additionally 64-bit support is now added. Read the preceding comment which I didn't change. I left the comment but it is now inaccurate. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/pacache.S | 335 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 290 insertions(+), 45 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 5d7218ad885c..312b48422a56 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -199,7 +199,6 @@ ENTRY(flush_instruction_cache_local) .callinfo NO_CALLS .entry - mtsp %r0, %sr1 load32 cache_info, %r1 /* Flush Instruction Cache */ @@ -208,7 +207,8 @@ ENTRY(flush_instruction_cache_local) LDREG ICACHE_STRIDE(%r1), %arg1 LDREG ICACHE_COUNT(%r1), %arg2 LDREG ICACHE_LOOP(%r1), %arg3 - rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/ + rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/ + mtsp %r0, %sr1 addib,COND(=) -1, %arg3, fioneloop /* Preadjust and test */ movb,<,n %arg3, %r31, fisync /* If loop < 0, do sync */ @@ -220,7 +220,33 @@ fimanyloop: /* Loop if LOOP >= 2 */ addib,COND(<=),n -1, %arg2, fisync /* Outer loop decr */ fioneloop: /* Loop if LOOP = 1 */ - addib,COND(>) -1, %arg2, fioneloop /* Outer loop count decr */ + /* Some implementations may flush with a single fice instruction */ + cmpib,COND(>>=),n 15, %arg2, fioneloop2 + +fioneloop1: + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + addib,COND(>) -16, %arg2, fioneloop1 + fice,m %arg1(%sr1, %arg0) + + /* Check if done */ + cmpb,COND(=),n %arg2, %r0, fisync /* Predict branch taken */ + +fioneloop2: + addib,COND(>) -1, %arg2, fioneloop2 /* Outer loop count decr */ fice,m %arg1(%sr1, %arg0) /* Fice for one loop */ fisync: @@ -240,8 +266,7 @@ ENTRY(flush_data_cache_local) .callinfo NO_CALLS .entry - mtsp %r0, %sr1 - load32 cache_info, %r1 + load32 cache_info, %r1 /* Flush Data Cache */ @@ -249,7 +274,8 @@ ENTRY(flush_data_cache_local) LDREG DCACHE_STRIDE(%r1), %arg1 LDREG DCACHE_COUNT(%r1), %arg2 LDREG DCACHE_LOOP(%r1), %arg3 - rsm PSW_SM_I, %r22 + rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/ + mtsp %r0, %sr1 addib,COND(=) -1, %arg3, fdoneloop /* Preadjust and test */ movb,<,n %arg3, %r31, fdsync /* If loop < 0, do sync */ @@ -261,7 +287,33 @@ fdmanyloop: /* Loop if LOOP >= 2 */ addib,COND(<=),n -1, %arg2, fdsync /* Outer loop decr */ fdoneloop: /* Loop if LOOP = 1 */ - addib,COND(>) -1, %arg2, fdoneloop /* Outer loop count decr */ + /* Some implementations may flush with a single fdce instruction */ + cmpib,COND(>>=),n 15, %arg2, fdoneloop2 + +fdoneloop1: + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + addib,COND(>) -16, %arg2, fdoneloop1 + fdce,m %arg1(%sr1, %arg0) + + /* Check if done */ + cmpb,COND(=),n %arg2, %r0, fdsync /* Predict branch taken */ + +fdoneloop2: + addib,COND(>) -1, %arg2, fdoneloop2 /* Outer loop count decr */ fdce,m %arg1(%sr1, %arg0) /* Fdce for one loop */ fdsync: @@ -277,7 +329,104 @@ ENDPROC(flush_data_cache_local) .align 16 -ENTRY(copy_user_page_asm) +/* Macros to serialize TLB purge operations on SMP. */ + + .macro tlb_lock la,flags,tmp +#ifdef CONFIG_SMP + ldil L%pa_tlb_lock,%r1 + ldo R%pa_tlb_lock(%r1),\la + rsm PSW_SM_I,\flags +1: LDCW 0(\la),\tmp + cmpib,<>,n 0,\tmp,3f +2: ldw 0(\la),\tmp + cmpb,<> %r0,\tmp,1b + nop + b,n 2b +3: +#endif + .endm + + .macro tlb_unlock la,flags,tmp +#ifdef CONFIG_SMP + ldi 1,\tmp + stw \tmp,0(\la) + mtsm \flags +#endif + .endm + +/* Clear page using kernel mapping. */ + +ENTRY(clear_page_asm) + .proc + .callinfo NO_CALLS + .entry + +#ifdef CONFIG_64BIT + + /* Unroll the loop. */ + ldi (PAGE_SIZE / 128), %r1 + +1: + std %r0, 0(%r26) + std %r0, 8(%r26) + std %r0, 16(%r26) + std %r0, 24(%r26) + std %r0, 32(%r26) + std %r0, 40(%r26) + std %r0, 48(%r26) + std %r0, 56(%r26) + std %r0, 64(%r26) + std %r0, 72(%r26) + std %r0, 80(%r26) + std %r0, 88(%r26) + std %r0, 96(%r26) + std %r0, 104(%r26) + std %r0, 112(%r26) + std %r0, 120(%r26) + + /* Note reverse branch hint for addib is taken. */ + addib,COND(>),n -1, %r1, 1b + ldo 128(%r26), %r26 + +#else + + /* + * Note that until (if) we start saving the full 64-bit register + * values on interrupt, we can't use std on a 32 bit kernel. + */ + ldi (PAGE_SIZE / 64), %r1 + +1: + stw %r0, 0(%r26) + stw %r0, 4(%r26) + stw %r0, 8(%r26) + stw %r0, 12(%r26) + stw %r0, 16(%r26) + stw %r0, 20(%r26) + stw %r0, 24(%r26) + stw %r0, 28(%r26) + stw %r0, 32(%r26) + stw %r0, 36(%r26) + stw %r0, 40(%r26) + stw %r0, 44(%r26) + stw %r0, 48(%r26) + stw %r0, 52(%r26) + stw %r0, 56(%r26) + stw %r0, 60(%r26) + + addib,COND(>),n -1, %r1, 1b + ldo 64(%r26), %r26 +#endif + bv %r0(%r2) + nop + .exit + + .procend +ENDPROC(clear_page_asm) + +/* Copy page using kernel mapping. */ + +ENTRY(copy_page_asm) .proc .callinfo NO_CALLS .entry @@ -285,18 +434,14 @@ ENTRY(copy_user_page_asm) #ifdef CONFIG_64BIT /* PA8x00 CPUs can consume 2 loads or 1 store per cycle. * Unroll the loop by hand and arrange insn appropriately. - * GCC probably can do this just as well. + * Prefetch doesn't improve performance on rp3440. + * GCC probably can do this just as well... */ - ldd 0(%r25), %r19 ldi (PAGE_SIZE / 128), %r1 - ldw 64(%r25), %r0 /* prefetch 1 cacheline ahead */ - ldw 128(%r25), %r0 /* prefetch 2 */ - -1: ldd 8(%r25), %r20 - ldw 192(%r25), %r0 /* prefetch 3 */ - ldw 256(%r25), %r0 /* prefetch 4 */ +1: ldd 0(%r25), %r19 + ldd 8(%r25), %r20 ldd 16(%r25), %r21 ldd 24(%r25), %r22 @@ -330,20 +475,16 @@ ENTRY(copy_user_page_asm) ldd 112(%r25), %r21 ldd 120(%r25), %r22 + ldo 128(%r25), %r25 std %r19, 96(%r26) std %r20, 104(%r26) - ldo 128(%r25), %r25 std %r21, 112(%r26) std %r22, 120(%r26) - ldo 128(%r26), %r26 - /* conditional branches nullify on forward taken branch, and on - * non-taken backward branch. Note that .+4 is a backwards branch. - * The ldd should only get executed if the branch is taken. - */ - addib,COND(>),n -1, %r1, 1b /* bundle 10 */ - ldd 0(%r25), %r19 /* start next loads */ + /* Note reverse branch hint for addib is taken. */ + addib,COND(>),n -1, %r1, 1b + ldo 128(%r26), %r26 #else @@ -399,7 +540,7 @@ ENTRY(copy_user_page_asm) .exit .procend -ENDPROC(copy_user_page_asm) +ENDPROC(copy_page_asm) /* * NOTE: Code in clear_user_page has a hard coded dependency on the @@ -422,8 +563,6 @@ ENDPROC(copy_user_page_asm) * %r23 physical page (shifted for tlb insert) of "from" translation */ -#if 0 - /* * We can't do this since copy_user_page is used to bring in * file data that might have instructions. Since the data would @@ -435,6 +574,7 @@ ENDPROC(copy_user_page_asm) * use it if more information is passed into copy_user_page(). * Have to do some measurements to see if it is worthwhile to * lobby for such a change. + * */ ENTRY(copy_user_page_asm) @@ -442,16 +582,21 @@ ENTRY(copy_user_page_asm) .callinfo NO_CALLS .entry + /* Convert virtual `to' and `from' addresses to physical addresses. + Move `from' physical address to non shadowed register. */ ldil L%(__PAGE_OFFSET), %r1 sub %r26, %r1, %r26 - sub %r25, %r1, %r23 /* move physical addr into non shadowed reg */ + sub %r25, %r1, %r23 ldil L%(TMPALIAS_MAP_START), %r28 /* FIXME for different page sizes != 4k */ #ifdef CONFIG_64BIT - extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */ - extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */ - depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */ +#if (TMPALIAS_MAP_START >= 0x80000000) + depdi 0, 31,32, %r28 /* clear any sign extension */ +#endif + extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */ + extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */ + depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */ depdi 0, 63,12, %r28 /* Clear any offset bits */ copy %r28, %r29 depdi 1, 41,1, %r29 /* Form aliased virtual address 'from' */ @@ -466,10 +611,76 @@ ENTRY(copy_user_page_asm) /* Purge any old translations */ +#ifdef CONFIG_PA20 + pdtlb,l 0(%r28) + pdtlb,l 0(%r29) +#else + tlb_lock %r20,%r21,%r22 pdtlb 0(%r28) pdtlb 0(%r29) + tlb_unlock %r20,%r21,%r22 +#endif + +#ifdef CONFIG_64BIT + /* PA8x00 CPUs can consume 2 loads or 1 store per cycle. + * Unroll the loop by hand and arrange insn appropriately. + * GCC probably can do this just as well. + */ - ldi 64, %r1 + ldd 0(%r29), %r19 + ldi (PAGE_SIZE / 128), %r1 + +1: ldd 8(%r29), %r20 + + ldd 16(%r29), %r21 + ldd 24(%r29), %r22 + std %r19, 0(%r28) + std %r20, 8(%r28) + + ldd 32(%r29), %r19 + ldd 40(%r29), %r20 + std %r21, 16(%r28) + std %r22, 24(%r28) + + ldd 48(%r29), %r21 + ldd 56(%r29), %r22 + std %r19, 32(%r28) + std %r20, 40(%r28) + + ldd 64(%r29), %r19 + ldd 72(%r29), %r20 + std %r21, 48(%r28) + std %r22, 56(%r28) + + ldd 80(%r29), %r21 + ldd 88(%r29), %r22 + std %r19, 64(%r28) + std %r20, 72(%r28) + + ldd 96(%r29), %r19 + ldd 104(%r29), %r20 + std %r21, 80(%r28) + std %r22, 88(%r28) + + ldd 112(%r29), %r21 + ldd 120(%r29), %r22 + std %r19, 96(%r28) + std %r20, 104(%r28) + + ldo 128(%r29), %r29 + std %r21, 112(%r28) + std %r22, 120(%r28) + ldo 128(%r28), %r28 + + /* conditional branches nullify on forward taken branch, and on + * non-taken backward branch. Note that .+4 is a backwards branch. + * The ldd should only get executed if the branch is taken. + */ + addib,COND(>),n -1, %r1, 1b /* bundle 10 */ + ldd 0(%r29), %r19 /* start next loads */ + +#else + ldi (PAGE_SIZE / 64), %r1 /* * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw @@ -480,9 +691,7 @@ ENTRY(copy_user_page_asm) * use ldd/std on a 32 bit kernel. */ - -1: - ldw 0(%r29), %r19 +1: ldw 0(%r29), %r19 ldw 4(%r29), %r20 ldw 8(%r29), %r21 ldw 12(%r29), %r22 @@ -515,8 +724,10 @@ ENTRY(copy_user_page_asm) stw %r21, 56(%r28) stw %r22, 60(%r28) ldo 64(%r28), %r28 + addib,COND(>) -1, %r1,1b ldo 64(%r29), %r29 +#endif bv %r0(%r2) nop @@ -524,9 +735,8 @@ ENTRY(copy_user_page_asm) .procend ENDPROC(copy_user_page_asm) -#endif -ENTRY(__clear_user_page_asm) +ENTRY(clear_user_page_asm) .proc .callinfo NO_CALLS .entry @@ -550,7 +760,13 @@ ENTRY(__clear_user_page_asm) /* Purge any old translation */ +#ifdef CONFIG_PA20 + pdtlb,l 0(%r28) +#else + tlb_lock %r20,%r21,%r22 pdtlb 0(%r28) + tlb_unlock %r20,%r21,%r22 +#endif #ifdef CONFIG_64BIT ldi (PAGE_SIZE / 128), %r1 @@ -580,8 +796,7 @@ ENTRY(__clear_user_page_asm) #else /* ! CONFIG_64BIT */ ldi (PAGE_SIZE / 64), %r1 -1: - stw %r0, 0(%r28) +1: stw %r0, 0(%r28) stw %r0, 4(%r28) stw %r0, 8(%r28) stw %r0, 12(%r28) @@ -606,7 +821,7 @@ ENTRY(__clear_user_page_asm) .exit .procend -ENDPROC(__clear_user_page_asm) +ENDPROC(clear_user_page_asm) ENTRY(flush_dcache_page_asm) .proc @@ -630,7 +845,13 @@ ENTRY(flush_dcache_page_asm) /* Purge any old translation */ +#ifdef CONFIG_PA20 + pdtlb,l 0(%r28) +#else + tlb_lock %r20,%r21,%r22 pdtlb 0(%r28) + tlb_unlock %r20,%r21,%r22 +#endif ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r1 @@ -663,8 +884,17 @@ ENTRY(flush_dcache_page_asm) fdc,m %r1(%r28) sync + +#ifdef CONFIG_PA20 + pdtlb,l 0(%r25) +#else + tlb_lock %r20,%r21,%r22 + pdtlb 0(%r25) + tlb_unlock %r20,%r21,%r22 +#endif + bv %r0(%r2) - pdtlb (%r25) + nop .exit .procend @@ -692,7 +922,13 @@ ENTRY(flush_icache_page_asm) /* Purge any old translation */ - pitlb (%sr4,%r28) +#ifdef CONFIG_PA20 + pitlb,l %r0(%sr4,%r28) +#else + tlb_lock %r20,%r21,%r22 + pitlb (%sr4,%r28) + tlb_unlock %r20,%r21,%r22 +#endif ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r1 @@ -727,8 +963,17 @@ ENTRY(flush_icache_page_asm) fic,m %r1(%sr4,%r28) sync + +#ifdef CONFIG_PA20 + pitlb,l %r0(%sr4,%r25) +#else + tlb_lock %r20,%r21,%r22 + pitlb (%sr4,%r25) + tlb_unlock %r20,%r21,%r22 +#endif + bv %r0(%r2) - pitlb (%sr4,%r25) + nop .exit .procend @@ -777,7 +1022,7 @@ ENTRY(flush_kernel_dcache_page_asm) .procend ENDPROC(flush_kernel_dcache_page_asm) -ENTRY(purge_kernel_dcache_page) +ENTRY(purge_kernel_dcache_page_asm) .proc .callinfo NO_CALLS .entry @@ -817,7 +1062,7 @@ ENTRY(purge_kernel_dcache_page) .exit .procend -ENDPROC(purge_kernel_dcache_page) +ENDPROC(purge_kernel_dcache_page_asm) ENTRY(flush_user_dcache_range_asm) .proc -- cgit v1.2.2 From 6d2439d9558e259822fb487ec274cc9e362e6a81 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 3 Feb 2013 23:01:47 +0000 Subject: parisc: fixes and cleanups in page cache flushing (3/4) flush_cache_mm, for the non current case also uses flush_dcache_page_asm and flush_icache_page_asm which are TMPALIAS flushes. For the non current case, the algorithm used by get_ptep is derived from the vmalloc_to_page implementation in vmalloc.c. It is essentially a generic page table lookup. The other alternative was to duplicate the lookup in entry.S. The break point for switching to a full cache flush is somewhat arbitrary. The same approach is used in flush_cache_range for non current case. In a GCC build and check, many small programs are executed and this change provided a significant performance enhancement, e.g. GCC build time was cut almost in half on a rp3440 at j4. Previously, we always flushed the entire cache. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/cache.c | 88 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 7 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index d9cbb4b22c9f..ec63de95cbd9 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -469,8 +469,66 @@ void flush_cache_all(void) on_each_cpu(cacheflush_h_tmp_function, NULL, 1); } +static inline unsigned long mm_total_size(struct mm_struct *mm) +{ + struct vm_area_struct *vma; + unsigned long usize = 0; + + for (vma = mm->mmap; vma; vma = vma->vm_next) + usize += vma->vm_end - vma->vm_start; + return usize; +} + +static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr) +{ + pte_t *ptep = NULL; + + if (!pgd_none(*pgd)) { + pud_t *pud = pud_offset(pgd, addr); + if (!pud_none(*pud)) { + pmd_t *pmd = pmd_offset(pud, addr); + if (!pmd_none(*pmd)) + ptep = pte_offset_map(pmd, addr); + } + } + return ptep; +} + void flush_cache_mm(struct mm_struct *mm) { + /* Flushing the whole cache on each cpu takes forever on + rp3440, etc. So, avoid it if the mm isn't too big. */ + if (mm_total_size(mm) < parisc_cache_flush_threshold) { + struct vm_area_struct *vma; + + if (mm->context == mfsp(3)) { + for (vma = mm->mmap; vma; vma = vma->vm_next) { + flush_user_dcache_range_asm(vma->vm_start, + vma->vm_end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm( + vma->vm_start, vma->vm_end); + } + } else { + pgd_t *pgd = mm->pgd; + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long addr; + + for (addr = vma->vm_start; addr < vma->vm_end; + addr += PAGE_SIZE) { + pte_t *ptep = get_ptep(pgd, addr); + if (ptep != NULL) { + pte_t pte = *ptep; + __flush_cache_page(vma, addr, + page_to_phys(pte_page(pte))); + } + } + } + } + return; + } + #ifdef CONFIG_SMP flush_cache_all(); #else @@ -496,20 +554,36 @@ flush_user_icache_range(unsigned long start, unsigned long end) flush_instruction_cache(); } - void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - int sr3; - BUG_ON(!vma->vm_mm->context); - sr3 = mfsp(3); - if (vma->vm_mm->context == sr3) { - flush_user_dcache_range(start,end); - flush_user_icache_range(start,end); + if ((end - start) < parisc_cache_flush_threshold) { + if (vma->vm_mm->context == mfsp(3)) { + flush_user_dcache_range_asm(start, end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm(start, end); + } else { + unsigned long addr; + pgd_t *pgd = vma->vm_mm->pgd; + + for (addr = start & PAGE_MASK; addr < end; + addr += PAGE_SIZE) { + pte_t *ptep = get_ptep(pgd, addr); + if (ptep != NULL) { + pte_t pte = *ptep; + flush_cache_page(vma, + addr, pte_pfn(pte)); + } + } + } } else { +#ifdef CONFIG_SMP flush_cache_all(); +#else + flush_cache_all_local(); +#endif } } -- cgit v1.2.2 From cca8e9026041544c0103b3037d8f03c1d2f4ae02 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 3 Feb 2013 23:02:49 +0000 Subject: parisc: fixes and cleanups in page cache flushing (4/4) CONFIG_PARISC_TMPALIAS enables clear_user_highpage and copy_user_highpage. These are essentially alternative implementations of clear_user_page and copy_user_page. They don't have anything to do with x86 high pages, but they build on the infrastructure to save a few instructions. Read the comment in clear_user_highpage as it is very important to the implementation. For this reason, there isn't any gain in using the TMPALIAS/highpage approach. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/cache.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index ec63de95cbd9..1c61b8245650 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -596,3 +596,67 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn))); } + +#ifdef CONFIG_PARISC_TMPALIAS + +void clear_user_highpage(struct page *page, unsigned long vaddr) +{ + void *vto; + unsigned long flags; + + /* Clear using TMPALIAS region. The page doesn't need to + be flushed but the kernel mapping needs to be purged. */ + + vto = kmap_atomic(page, KM_USER0); + + /* The PA-RISC 2.0 Architecture book states on page F-6: + "Before a write-capable translation is enabled, *all* + non-equivalently-aliased translations must be removed + from the page table and purged from the TLB. (Note + that the caches are not required to be flushed at this + time.) Before any non-equivalent aliased translation + is re-enabled, the virtual address range for the writeable + page (the entire page) must be flushed from the cache, + and the write-capable translation removed from the page + table and purged from the TLB." */ + + purge_kernel_dcache_page_asm((unsigned long)vto); + purge_tlb_start(flags); + pdtlb_kernel(vto); + purge_tlb_end(flags); + preempt_disable(); + clear_user_page_asm(vto, vaddr); + preempt_enable(); + + pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */ +} + +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma) +{ + void *vfrom, *vto; + unsigned long flags; + + /* Copy using TMPALIAS region. This has the advantage + that the `from' page doesn't need to be flushed. However, + the `to' page must be flushed in copy_user_page_asm since + it can be used to bring in executable code. */ + + vfrom = kmap_atomic(from, KM_USER0); + vto = kmap_atomic(to, KM_USER1); + + purge_kernel_dcache_page_asm((unsigned long)vto); + purge_tlb_start(flags); + pdtlb_kernel(vto); + pdtlb_kernel(vfrom); + purge_tlb_end(flags); + preempt_disable(); + copy_user_page_asm(vto, vfrom, vaddr); + flush_dcache_page_asm(__pa(vto), vaddr); + preempt_enable(); + + pagefault_enable(); /* kunmap_atomic(addr, KM_USER1); */ + pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */ +} + +#endif /* CONFIG_PARISC_TMPALIAS */ -- cgit v1.2.2 From b54cb2332e387f29c65f19f3620e5c812c89a328 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 2 Mar 2009 10:45:53 +0100 Subject: parisc: remove IRQF_DISABLED People are playing odd games with IRQF_DISABLED, remove it. Its not reliable, since shared interrupt lines could disable it for you, and its possible and allowed for archs to disable IRQs to limit IRQ nesting. Therefore, simply mandate that _ALL_ IRQ handlers are run with IRQs disabled. [ This _should_ not break anything, since we've mandated that IRQ handlers _must_ be able to deal with this for a _long_ time ] IRQ handlers should be fast, no if buts and any other exceptions. We also have plenty instrumentation to find any offending IRQ latency sources. Signed-off-by: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Helge Deller --- arch/parisc/kernel/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 0299d63cd112..8094d3ed3b64 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -379,14 +379,14 @@ void do_cpu_irq_mask(struct pt_regs *regs) static struct irqaction timer_action = { .handler = timer_interrupt, .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL, }; #ifdef CONFIG_SMP static struct irqaction ipi_action = { .handler = ipi_interrupt, .name = "IPI", - .flags = IRQF_DISABLED | IRQF_PERCPU, + .flags = IRQF_PERCPU, }; #endif -- cgit v1.2.2 From 027f27c4eca00b4411fb1fe61c33060569ff73f6 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sat, 2 Feb 2013 23:41:24 +0000 Subject: parisc: disable preemption while flushing D- or I-caches through TMPALIAS region It is necessary to disable preemption during cache flushes done through the TMPALIAS region to ensure that the TLB setup is not clobbered by another flush. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/cache.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 1c61b8245650..4b12890642eb 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -267,9 +267,11 @@ static inline void __flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long physaddr) { + preempt_disable(); flush_dcache_page_asm(physaddr, vmaddr); if (vma->vm_flags & VM_EXEC) flush_icache_page_asm(physaddr, vmaddr); + preempt_enable(); } void flush_dcache_page(struct page *page) -- cgit v1.2.2 From 5ca8b91df88fa417aa7aac19494a8ae1602db2cb Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sat, 2 Feb 2013 23:44:59 +0000 Subject: parisc: ensure that mmapped shared pages are aligned at SHMLBA addresses Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/sys_parisc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index f76c10863c62..a047b3227e50 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -94,11 +94,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, { if (len > TASK_SIZE) return -ENOMEM; - /* Might want to check for cache aliasing issues for MAP_FIXED case - * like ARM or MIPS ??? --BenH. - */ - if (flags & MAP_FIXED) + if (flags & MAP_FIXED) { + if ((flags & MAP_SHARED) && + (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) + return -EINVAL; return addr; + } if (!addr) addr = TASK_UNMAPPED_BASE; -- cgit v1.2.2 From 52ab532ea76d30b7e7a7b98021e2e873e83029a5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Dec 2012 06:16:14 +0000 Subject: parisc: fix ptrace breakage 1) PTRACE_SYSCALL doesn't work for 64bit process on parisc64. Compat syscall table is used instead of 64bit one. IMO we should either refuse to allow PTRACE_SYSCALL for 64bit processes or duplicate the logics choosing the right syscall table into .Ltracesys. 2) if you have let the tracee run with PTRACE_SYSCALL and it had stopped, you can use PTRACE_POKEUSR to modify syscall number (r20) and arguments 1--4 (r26--r23). Modifications will have effect. However, modifying arguments 5 and 6 (r22 and r21 resp.) works only when process (32bit one) runs on 64bit host - on 32bit one it has no effect. AFAICS, the diff below should fix that one. Signed-off-by: Al Viro Tested-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/syscall.S | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 86742df0b194..5e055240f00b 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -309,10 +309,13 @@ tracesys_next: LDREG TASK_PT_GR25(%r1), %r25 LDREG TASK_PT_GR24(%r1), %r24 LDREG TASK_PT_GR23(%r1), %r23 -#ifdef CONFIG_64BIT LDREG TASK_PT_GR22(%r1), %r22 LDREG TASK_PT_GR21(%r1), %r21 +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ +#else + stw %r22, -52(%r30) /* 5th argument */ + stw %r21, -56(%r30) /* 6th argument */ #endif comiclr,>>= __NR_Linux_syscalls, %r20, %r0 -- cgit v1.2.2 From 45b6eff2a60c8bec1254412dfdb36acb0afe04a2 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sat, 2 Feb 2013 23:43:06 +0000 Subject: parisc: space register variables need to be in native length (unsigned long) Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index fd051705a407..52c85b2f502e 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -312,7 +312,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, #if DEBUG_SIG /* Assert that we're flushing in the correct space... */ { - int sid; + unsigned long sid; asm ("mfsp %%sr3,%0" : "=r" (sid)); DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n", sid, frame->tramp); -- cgit v1.2.2 From 24084747df3474bbdeb0880d26afe82c42161a6b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 8 Feb 2013 20:08:25 +0000 Subject: parisc: wire up process_vm_readv, process_vm_writev, kcmp and finit_module syscalls Signed-off-by: Helge Deller --- arch/parisc/kernel/syscall_table.S | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 54d950b067b7..cf7094c239f8 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -428,6 +428,10 @@ ENTRY_SAME(syncfs) ENTRY_SAME(setns) ENTRY_COMP(sendmmsg) + ENTRY_COMP(process_vm_readv) /* 330 */ + ENTRY_COMP(process_vm_writev) + ENTRY_SAME(kcmp) + ENTRY_SAME(finit_module) /* Nothing yet */ -- cgit v1.2.2 From fee707b459da56ba83fbb4ae89151571502ee724 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 11 Feb 2013 21:39:51 +0100 Subject: parisc: correctly wire up mq_* functions for CONFIG_COMPAT case Fix mq_open, mq_timedsend, mq_timedreceive, mq_notify and mq_getsetattr syscalls when running 32bit applications on 64bit kernel. Signed-off-by: Helge Deller --- arch/parisc/kernel/syscall_table.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index cf7094c239f8..e5fcd4c605e2 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -327,12 +327,12 @@ ENTRY_SAME(epoll_wait) ENTRY_SAME(remap_file_pages) ENTRY_SAME(semtimedop) - ENTRY_SAME(mq_open) + ENTRY_COMP(mq_open) ENTRY_SAME(mq_unlink) /* 230 */ - ENTRY_SAME(mq_timedsend) - ENTRY_SAME(mq_timedreceive) - ENTRY_SAME(mq_notify) - ENTRY_SAME(mq_getsetattr) + ENTRY_COMP(mq_timedsend) + ENTRY_COMP(mq_timedreceive) + ENTRY_COMP(mq_notify) + ENTRY_COMP(mq_getsetattr) ENTRY_COMP(waitid) /* 235 */ ENTRY_OURS(fadvise64_64) ENTRY_SAME(set_tid_address) -- cgit v1.2.2 From bf581e15a443fa3569d9def96b512315ba509d6f Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 19 Feb 2013 20:47:37 +0100 Subject: parisc: convert msgrcv and msgsnd syscalls to use compat layer Switch over to use the existing compat_* implementation for msgrcv() and msgsnd(). Existing code was even partly buggy since it returned on some paths different error codes than the standard. Signed-off-by: Helge Deller --- arch/parisc/kernel/sys_parisc32.c | 58 -------------------------------------- arch/parisc/kernel/syscall_table.S | 4 +-- 2 files changed, 2 insertions(+), 60 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 9cfdaa19ab63..cee60f77fc1f 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -73,63 +72,6 @@ asmlinkage long sys32_sched_rr_get_interval(pid_t pid, return ret; } -struct msgbuf32 { - int mtype; - char mtext[1]; -}; - -asmlinkage long sys32_msgsnd(int msqid, - struct msgbuf32 __user *umsgp32, - size_t msgsz, int msgflg) -{ - struct msgbuf *mb; - struct msgbuf32 mb32; - int err; - - if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL) - return -ENOMEM; - - err = get_user(mb32.mtype, &umsgp32->mtype); - mb->mtype = mb32.mtype; - err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz); - - if (err) - err = -EFAULT; - else - KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg); - - kfree(mb); - return err; -} - -asmlinkage long sys32_msgrcv(int msqid, - struct msgbuf32 __user *umsgp32, - size_t msgsz, long msgtyp, int msgflg) -{ - struct msgbuf *mb; - struct msgbuf32 mb32; - int err, len; - - if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL) - return -ENOMEM; - - KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg); - - if (err >= 0) { - len = err; - mb32.mtype = mb->mtype; - err = put_user(mb32.mtype, &umsgp32->mtype); - err |= copy_to_user(&umsgp32->mtext, mb->mtext, len); - if (err) - err = -EFAULT; - else - err = len; - } - - kfree(mb); - return err; -} - asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) { mm_segment_t old_fs = get_fs(); diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index e5fcd4c605e2..773b4ee1e1d3 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -286,8 +286,8 @@ ENTRY_SAME(semop) /* 185 */ ENTRY_SAME(semget) ENTRY_DIFF(semctl) - ENTRY_DIFF(msgsnd) - ENTRY_DIFF(msgrcv) + ENTRY_COMP(msgsnd) + ENTRY_COMP(msgrcv) ENTRY_SAME(msgget) /* 190 */ ENTRY_SAME(msgctl) ENTRY_SAME(shmat) -- cgit v1.2.2 From 2e800dff4f16a6e47adcbea7188fc586bfa5c30b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 19 Feb 2013 21:11:39 +0100 Subject: parisc: fix error return codes for rt_sigaction and rt_sigprocmask Signed-off-by: Helge Deller --- arch/parisc/kernel/signal32.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 5dede04f2f3e..2ddcabb616ce 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -65,7 +65,7 @@ put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) { compat_sigset_t s; - if (sz != sizeof *set) + if (sz != sizeof(compat_sigset_t)) return -EINVAL; sigset_64to32(&s, set); @@ -78,7 +78,7 @@ get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) compat_sigset_t s; int r; - if (sz != sizeof *set) + if (sz != sizeof(compat_sigset_t)) return -EINVAL; if ((r = copy_from_user(&s, up, sz)) == 0) { @@ -94,8 +94,11 @@ int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t _ sigset_t old_set, new_set; int ret; - if (set && get_sigset32(set, &new_set, sigsetsize)) - return -EFAULT; + if (set) { + ret = get_sigset32(set, &new_set, sigsetsize); + if (ret) + return ret; + } KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? (sigset_t __user *)&new_set : NULL, oset ? (sigset_t __user *)&old_set : NULL, sigsetsize); @@ -128,6 +131,10 @@ sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigacti struct k_sigaction new_sa, old_sa; int ret = -EINVAL; + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(compat_sigset_t)) + return -EINVAL; + if (act) { if (copy_from_user(&new_sa32.sa, act, sizeof new_sa32.sa)) return -EFAULT; -- cgit v1.2.2 From 4474a331cfccc5092b79e3839205aacf44f3a571 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 19 Feb 2013 21:23:59 +0100 Subject: parisc: fix fallocate syscall fallocate(off_t) gets redirected by glibc to fallocate64(loff_t) where the 64bit loff_t values get splitted into two 32bit (hi/lo) values. This patch fixes this syscall for the 32- and 64bit kernel. Signed-off-by: Helge Deller --- arch/parisc/kernel/sys_parisc.c | 7 +++++++ arch/parisc/kernel/sys_parisc32.c | 7 ------- arch/parisc/kernel/syscall_table.S | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index a047b3227e50..54d619d4cac6 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -213,6 +213,13 @@ asmlinkage long parisc_sync_file_range(int fd, (loff_t)hi_nbytes << 32 | lo_nbytes, flags); } +asmlinkage long parisc_fallocate(int fd, int mode, u32 offhi, u32 offlo, + u32 lenhi, u32 lenlo) +{ + return sys_fallocate(fd, mode, ((u64)offhi << 32) | offlo, + ((u64)lenhi << 32) | lenlo); +} + asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag) { return -ENOMEM; diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index cee60f77fc1f..986294425e86 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -142,13 +142,6 @@ long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf, buf, len); } -asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo, - u32 lenhi, u32 lenlo) -{ - return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo, - ((loff_t)lenhi << 32) | lenlo); -} - asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi, u32 mask_lo, int fd, const char __user *pathname) diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 773b4ee1e1d3..2a5f82985aa8 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -403,7 +403,7 @@ ENTRY_COMP(signalfd) ENTRY_SAME(ni_syscall) /* was timerfd */ ENTRY_SAME(eventfd) - ENTRY_COMP(fallocate) /* 305 */ + ENTRY_OURS(fallocate) /* 305 */ ENTRY_SAME(timerfd_create) ENTRY_COMP(timerfd_settime) ENTRY_COMP(timerfd_gettime) -- cgit v1.2.2 From e27da28a565e2a4d82a2d1adc9e0ba4aadd61e97 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 19 Feb 2013 21:42:45 +0100 Subject: parisc: switch to available compat_sched_rr_get_interval implementation Signed-off-by: Helge Deller --- arch/parisc/kernel/sys_parisc32.c | 12 ------------ arch/parisc/kernel/syscall_table.S | 5 +---- 2 files changed, 1 insertion(+), 16 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 986294425e86..0115eac76c39 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -60,18 +60,6 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23, return -ENOSYS; } -asmlinkage long sys32_sched_rr_get_interval(pid_t pid, - struct compat_timespec __user *interval) -{ - struct timespec t; - int ret; - - KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t); - if (put_compat_timespec(&t, interval)) - return -EFAULT; - return ret; -} - asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) { mm_segment_t old_fs = get_fs(); diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 2a5f82985aa8..9180719dad04 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -247,10 +247,7 @@ ENTRY_SAME(sched_yield) ENTRY_SAME(sched_get_priority_max) ENTRY_SAME(sched_get_priority_min) /* 160 */ - /* These 2 would've worked if someone had defined struct timespec - * carefully, like timeval for example (which is about the same). - * Unfortunately it contains a long :-( */ - ENTRY_DIFF(sched_rr_get_interval) + ENTRY_COMP(sched_rr_get_interval) ENTRY_COMP(nanosleep) ENTRY_SAME(mremap) ENTRY_SAME(setresuid) -- cgit v1.2.2 From f03d70a7fc952a7fd01c678ad409c932a925637b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 19 Feb 2013 22:55:17 +0100 Subject: parisc: sendfile and sendfile64 syscall cleanups Utilize the existing compat_sys_sendfile function for 64bit kernel and add wrappers for sendfile and sendfile64 to correctly handle the 32/64 bit sign extension. Signed-off-by: Helge Deller --- arch/parisc/kernel/sys_parisc32.c | 45 +++++++++++--------------------------- arch/parisc/kernel/syscall_table.S | 2 +- 2 files changed, 14 insertions(+), 33 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 0115eac76c39..eca69bb8ef5f 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -60,42 +60,23 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23, return -ENOSYS; } -asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) +/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, with the + * corresponding cast to a signed int to insure that the proper conversion + * (sign extension) between the register representation of a signed int (msr in + * 32-bit mode) and the register representation of a signed int (msr in 64-bit + * mode) is performed. + */ +asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, + compat_off_t __user *offset, compat_size_t count) { - mm_segment_t old_fs = get_fs(); - int ret; - off_t of; - - if (offset && get_user(of, offset)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count); - set_fs(old_fs); - - if (offset && put_user(of, offset)) - return -EFAULT; - - return ret; + return compat_sys_sendfile((int)out_fd, (int)in_fd, offset, count); } -asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count) +asmlinkage long sys32_sendfile64(u32 out_fd, u32 in_fd, + compat_loff_t __user *offset, compat_size_t count) { - mm_segment_t old_fs = get_fs(); - int ret; - loff_t lof; - - if (offset && get_user(lof, offset)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count); - set_fs(old_fs); - - if (offset && put_user(lof, offset)) - return -EFAULT; - - return ret; + return sys_sendfile64((int)out_fd, (int)in_fd, + (loff_t __user *)offset, count); } diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 9180719dad04..129fd472c471 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -304,7 +304,7 @@ ENTRY_SAME(gettid) ENTRY_OURS(readahead) ENTRY_SAME(tkill) - ENTRY_SAME(sendfile64) + ENTRY_DIFF(sendfile64) ENTRY_COMP(futex) /* 210 */ ENTRY_COMP(sched_setaffinity) ENTRY_COMP(sched_getaffinity) -- cgit v1.2.2