diff options
Diffstat (limited to 'arch/parisc/kernel')
-rw-r--r-- | arch/parisc/kernel/cache.c | 221 | ||||
-rw-r--r-- | arch/parisc/kernel/entry.S | 60 | ||||
-rw-r--r-- | arch/parisc/kernel/hardware.c | 7 | ||||
-rw-r--r-- | arch/parisc/kernel/inventory.c | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/irq.c | 10 | ||||
-rw-r--r-- | arch/parisc/kernel/pacache.S | 335 | ||||
-rw-r--r-- | arch/parisc/kernel/parisc_ksyms.c | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/pdc_cons.c | 10 | ||||
-rw-r--r-- | arch/parisc/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/signal.c | 25 | ||||
-rw-r--r-- | arch/parisc/kernel/signal32.c | 142 | ||||
-rw-r--r-- | arch/parisc/kernel/signal32.h | 23 | ||||
-rw-r--r-- | arch/parisc/kernel/sys32.h | 12 | ||||
-rw-r--r-- | arch/parisc/kernel/sys_parisc.c | 16 | ||||
-rw-r--r-- | arch/parisc/kernel/sys_parisc32.c | 122 | ||||
-rw-r--r-- | arch/parisc/kernel/syscall.S | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/syscall_table.S | 35 | ||||
-rw-r--r-- | arch/parisc/kernel/traps.c | 2 |
18 files changed, 564 insertions, 470 deletions
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 48e16dc20102..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) @@ -329,17 +331,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 +364,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 +379,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); } @@ -419,6 +414,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) { @@ -458,8 +471,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 @@ -485,20 +556,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 } } @@ -511,3 +598,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 */ diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index bfb44247d7a7..f33201bf8977 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 @@ -1748,44 +1748,6 @@ ENTRY(sys_rt_sigreturn_wrapper) LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */ ENDPROC(sys_rt_sigreturn_wrapper) -ENTRY(sys_sigaltstack_wrapper) - /* Get the user stack pointer */ - LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 - ldo TASK_REGS(%r1),%r24 /* get pt regs */ - LDREG TASK_PT_GR30(%r24),%r24 - STREG %r2, -RP_OFFSET(%r30) -#ifdef CONFIG_64BIT - ldo FRAME_SIZE(%r30), %r30 - BL do_sigaltstack,%r2 - ldo -16(%r30),%r29 /* Reference param save area */ -#else - BL do_sigaltstack,%r2 - ldo FRAME_SIZE(%r30), %r30 -#endif - - ldo -FRAME_SIZE(%r30), %r30 - LDREG -RP_OFFSET(%r30), %r2 - bv %r0(%r2) - nop -ENDPROC(sys_sigaltstack_wrapper) - -#ifdef CONFIG_64BIT -ENTRY(sys32_sigaltstack_wrapper) - /* Get the user stack pointer */ - LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r24 - LDREG TASK_PT_GR30(%r24),%r24 - STREG %r2, -RP_OFFSET(%r30) - ldo FRAME_SIZE(%r30), %r30 - BL do_sigaltstack32,%r2 - ldo -16(%r30),%r29 /* Reference param save area */ - - ldo -FRAME_SIZE(%r30), %r30 - LDREG -RP_OFFSET(%r30), %r2 - bv %r0(%r2) - nop -ENDPROC(sys32_sigaltstack_wrapper) -#endif - ENTRY(syscall_exit) /* NOTE: HP-UX syscalls also come through here * after hpux_syscall_exit fixes up return @@ -1865,7 +1827,7 @@ syscall_restore: /* Are we being ptraced? */ ldw TASK_FLAGS(%r1),%r19 - ldi (_TIF_SINGLESTEP|_TIF_BLOCKSTEP),%r2 + ldi _TIF_SYSCALL_TRACE_MASK,%r2 and,COND(=) %r19,%r2,%r0 b,n syscall_restore_rfi @@ -1978,15 +1940,23 @@ syscall_restore_rfi: /* 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. */ - STREG %r2,TASK_PT_IAOQ0(%r1) + depi 3,31,2,%r2 /* ensure return to user mode. */ + STREG %r2,TASK_PT_IAOQ0(%r1) ldo 4(%r2),%r2 STREG %r2,TASK_PT_IAOQ1(%r1) + b intr_restore copy %r25,%r16 + +pt_regs_ok: + LDREG TASK_PT_IAOQ0(%r1),%r2 + depi 3,31,2,%r2 /* ensure return to user mode. */ + STREG %r2,TASK_PT_IAOQ0(%r1) + LDREG TASK_PT_IAOQ1(%r1),%r2 + depi 3,31,2,%r2 + STREG %r2,TASK_PT_IAOQ1(%r1) b intr_restore - nop + copy %r25,%r16 .import schedule,code syscall_do_resched: diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c index f48a640b55fb..f7752f6af29e 100644 --- a/arch/parisc/kernel/hardware.c +++ b/arch/parisc/kernel/hardware.c @@ -38,7 +38,7 @@ * so don't reference this table after starting the init process */ -static struct hp_hardware hp_hardware_list[] __devinitdata = { +static struct hp_hardware hp_hardware_list[] = { {HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"}, {HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"}, {HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"}, @@ -1230,7 +1230,7 @@ static struct hp_cpu_type_mask { unsigned short model; unsigned short mask; enum cpu_type cpu; -} hp_cpu_type_mask_list[] __devinitdata = { +} hp_cpu_type_mask_list[] = { { 0x0000, 0x0ff0, pcx }, /* 0x0000 - 0x000f */ { 0x0048, 0x0ff0, pcxl }, /* 0x0040 - 0x004f */ @@ -1327,8 +1327,7 @@ const char * const cpu_name_version[][2] = { [mako2] = { "PA8900 (Shortfin)", "2.0" } }; -const char * __devinit -parisc_hardware_description(struct parisc_device_id *id) +const char *parisc_hardware_description(struct parisc_device_id *id) { struct hp_hardware *listptr; 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; } diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index c0b1affc06a8..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 @@ -410,11 +410,13 @@ void __init init_IRQ(void) { local_irq_disable(); /* PARANOID - should already be disabled */ mtctl(~0UL, 23); /* EIRR : clear all pending external intr */ - claim_cpu_irqs(); #ifdef CONFIG_SMP - if (!cpu_eiem) + if (!cpu_eiem) { + claim_cpu_irqs(); cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ); + } #else + claim_cpu_irqs(); cpu_eiem = EIEM_MASK(TIMER_IRQ); #endif set_eiem(cpu_eiem); /* EIEM : enable all external intr */ 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 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); diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index efc5e7d30530..d5cae55195ec 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -138,23 +138,17 @@ static const struct tty_operations pdc_console_tty_ops = { static void pdc_console_poll(unsigned long unused) { int data, count = 0; - struct tty_struct *tty = tty_port_tty_get(&tty_port); - - if (!tty) - return; while (1) { data = pdc_console_poll_key(NULL); if (data == -1) break; - tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL); + tty_insert_flip_char(&tty_port, data & 0xFF, TTY_NORMAL); count ++; } if (count) - tty_flip_buffer_push(tty); - - tty_kref_put(tty); + tty_flip_buffer_push(&tty_port); if (pdc_cons.flags & CON_ENABLED) mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 857c2f545470..534abd4936e1 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -26,7 +26,7 @@ #include <asm/asm-offsets.h> /* PSW bits we allow the debugger to modify */ -#define USER_PSW_BITS (PSW_N | PSW_V | PSW_CB) +#define USER_PSW_BITS (PSW_N | PSW_B | PSW_V | PSW_CB) /* * Called by kernel/ptrace.c when detaching.. diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 537996955998..98e9e7126565 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -143,7 +143,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) goto give_sigsegv; DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", usp, &compat_frame->uc.uc_stack); - if (do_sigaltstack32(&compat_frame->uc.uc_stack, NULL, usp) == -EFAULT) + if (compat_restore_altstack(&compat_frame->uc.uc_stack)) goto give_sigsegv; } else #endif @@ -154,7 +154,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) goto give_sigsegv; DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", usp, &frame->uc.uc_stack); - if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) + if (restore_altstack(&frame->uc.uc_stack)) goto give_sigsegv; } @@ -190,8 +190,10 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n", (unsigned long)ka, sp, frame_size); + /* Align alternate stack and reserve 64 bytes for the signal + handler's frame marker. */ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) - sp = current->sas_ss_sp; /* Stacks grow up! */ + sp = (current->sas_ss_sp + 0x7f) & ~0x3f; /* Stacks grow up! */ DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp); return (void __user *) sp; /* Stacks grow up. Fun. */ @@ -260,15 +262,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (is_compat_task()) { DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); err |= copy_siginfo_to_user32(&compat_frame->info, info); - DBG(1,"SETUP_RT_FRAME: 1\n"); - compat_val = (compat_int_t)current->sas_ss_sp; - err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp); - DBG(1,"SETUP_RT_FRAME: 2\n"); - compat_val = (compat_int_t)current->sas_ss_size; - err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size); - DBG(1,"SETUP_RT_FRAME: 3\n"); - compat_val = sas_ss_flags(regs->gr[30]); - err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags); + err |= __compat_save_altstack( &compat_frame->uc.uc_stack, regs->gr[30]); DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc); DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext); err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, @@ -280,10 +274,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, { DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info); err |= copy_siginfo_to_user(&frame->info, info); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= __put_user(sas_ss_flags(regs->gr[30]), - &frame->uc.uc_stack.ss_flags); + err |= __save_altstack(&frame->uc.uc_stack, regs->gr[30]); DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc); DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall); @@ -310,7 +301,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); diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 5dede04f2f3e..33eca1b04926 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -60,129 +60,6 @@ sigset_64to32(compat_sigset_t *s32, sigset_t *s64) s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL; } -static int -put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) -{ - compat_sigset_t s; - - if (sz != sizeof *set) - return -EINVAL; - sigset_64to32(&s, set); - - return copy_to_user(up, &s, sizeof s); -} - -static int -get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) -{ - compat_sigset_t s; - int r; - - if (sz != sizeof *set) - return -EINVAL; - - if ((r = copy_from_user(&s, up, sz)) == 0) { - sigset_32to64(set, &s); - } - - return r; -} - -int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, - unsigned int sigsetsize) -{ - sigset_t old_set, new_set; - int ret; - - if (set && get_sigset32(set, &new_set, sigsetsize)) - return -EFAULT; - - KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? (sigset_t __user *)&new_set : NULL, - oset ? (sigset_t __user *)&old_set : NULL, sigsetsize); - - if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize)) - return -EFAULT; - - return ret; -} - - -int sys32_rt_sigpending(compat_sigset_t __user *uset, unsigned int sigsetsize) -{ - int ret; - sigset_t set; - - KERNEL_SYSCALL(ret, sys_rt_sigpending, (sigset_t __user *)&set, sigsetsize); - - if (!ret && put_sigset32(uset, &set, sigsetsize)) - return -EFAULT; - - return ret; -} - -long -sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact, - size_t sigsetsize) -{ - struct k_sigaction32 new_sa32, old_sa32; - struct k_sigaction new_sa, old_sa; - int ret = -EINVAL; - - if (act) { - if (copy_from_user(&new_sa32.sa, act, sizeof new_sa32.sa)) - return -EFAULT; - new_sa.sa.sa_handler = (__sighandler_t)(unsigned long)new_sa32.sa.sa_handler; - new_sa.sa.sa_flags = new_sa32.sa.sa_flags; - sigset_32to64(&new_sa.sa.sa_mask, &new_sa32.sa.sa_mask); - } - - ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); - - if (!ret && oact) { - sigset_64to32(&old_sa32.sa.sa_mask, &old_sa.sa.sa_mask); - old_sa32.sa.sa_flags = old_sa.sa.sa_flags; - old_sa32.sa.sa_handler = (__sighandler_t32)(unsigned long)old_sa.sa.sa_handler; - if (copy_to_user(oact, &old_sa32.sa, sizeof old_sa32.sa)) - return -EFAULT; - } - return ret; -} - -int -do_sigaltstack32 (const compat_stack_t __user *uss32, compat_stack_t __user *uoss32, unsigned long sp) -{ - compat_stack_t ss32, oss32; - stack_t ss, oss; - stack_t *ssp = NULL, *ossp = NULL; - int ret; - - if (uss32) { - if (copy_from_user(&ss32, uss32, sizeof ss32)) - return -EFAULT; - - ss.ss_sp = (void __user *)(unsigned long)ss32.ss_sp; - ss.ss_flags = ss32.ss_flags; - ss.ss_size = ss32.ss_size; - - ssp = &ss; - } - - if (uoss32) - ossp = &oss; - - KERNEL_SYSCALL(ret, do_sigaltstack, (const stack_t __user *)ssp, (stack_t __user *)ossp, sp); - - if (!ret && uoss32) { - oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp; - oss32.ss_flags = oss.ss_flags; - oss32.ss_size = oss.ss_size; - if (copy_to_user(uoss32, &oss32, sizeof *uoss32)) - return -EFAULT; - } - - return ret; -} - long restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, struct pt_regs *regs) @@ -499,22 +376,3 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) } return err; } - -asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, - struct compat_siginfo __user *uinfo) -{ - siginfo_t info; - - if (copy_siginfo_from_user32(&info, uinfo)) - return -EFAULT; - - /* Not even root can pretend to send signals from the kernel. - Nor can they impersonate a kill(), which adds source info. */ - if (info.si_code >= 0) - return -EPERM; - info.si_signo = sig; - - /* POSIX.1b doesn't mention process groups. */ - return kill_proc_info(sig, &info, pid); -} - diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h index 08a88b5349a2..72ab41a51f32 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h @@ -21,23 +21,6 @@ #include <linux/compat.h> -typedef compat_uptr_t compat_sighandler_t; - -typedef struct compat_sigaltstack { - compat_uptr_t ss_sp; - compat_int_t ss_flags; - compat_size_t ss_size; -} compat_stack_t; - -/* Most things should be clean enough to redefine this at will, if care - is taken to make libc match. */ - -struct compat_sigaction { - compat_sighandler_t sa_handler; - compat_uint_t sa_flags; - compat_sigset_t sa_mask; /* mask last for extensibility */ -}; - /* 32-bit ucontext as seen from an 64-bit kernel */ struct compat_ucontext { compat_uint_t uc_flags; @@ -51,10 +34,6 @@ struct compat_ucontext { /* ELF32 signal handling */ -struct k_sigaction32 { - struct compat_sigaction sa; -}; - int copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from); int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from); @@ -102,8 +81,6 @@ struct compat_rt_sigframe { void sigset_32to64(sigset_t *s64, compat_sigset_t *s32); void sigset_64to32(compat_sigset_t *s32, sigset_t *s64); -int do_sigaltstack32 (const compat_stack_t __user *uss32, - compat_stack_t __user *uoss32, unsigned long sp); long restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user *rf, struct pt_regs *regs); diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h index 06c2090cfaba..60dd470f39f8 100644 --- a/arch/parisc/kernel/sys32.h +++ b/arch/parisc/kernel/sys32.h @@ -33,16 +33,4 @@ set_fs (old_fs); \ } -#ifdef CONFIG_COMPAT - -typedef __u32 __sighandler_t32; - -struct sigaction32 { - __sighandler_t32 sa_handler; - unsigned int sa_flags; - compat_sigset_t sa_mask; /* mask last for extensibility */ -}; - -#endif - #endif diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index f76c10863c62..54d619d4cac6 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; @@ -212,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 9cfdaa19ab63..eca69bb8ef5f 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -21,7 +21,6 @@ #include <linux/time.h> #include <linux/smp.h> #include <linux/sem.h> -#include <linux/msg.h> #include <linux/shm.h> #include <linux/slab.h> #include <linux/uio.h> @@ -61,111 +60,23 @@ 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; -} - -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) +/* 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); } @@ -200,13 +111,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.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 diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 54d950b067b7..fc9cab1cc2df 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -247,15 +247,12 @@ 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) ENTRY_SAME(getresuid) /* 165 */ - ENTRY_DIFF(sigaltstack_wrapper) + ENTRY_COMP(sigaltstack) ENTRY_SAME(ni_syscall) /* query_module */ ENTRY_SAME(poll) /* structs contain pointers and an in_addr... */ @@ -265,9 +262,9 @@ ENTRY_SAME(prctl) /* signals need a careful review */ ENTRY_SAME(rt_sigreturn_wrapper) - ENTRY_DIFF(rt_sigaction) - ENTRY_DIFF(rt_sigprocmask) /* 175 */ - ENTRY_DIFF(rt_sigpending) + ENTRY_COMP(rt_sigaction) + ENTRY_COMP(rt_sigprocmask) /* 175 */ + ENTRY_COMP(rt_sigpending) ENTRY_COMP(rt_sigtimedwait) /* even though the struct siginfo_t is different, it appears like * all the paths use values which should be same wide and narrow. @@ -286,8 +283,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) @@ -307,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) @@ -327,12 +324,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) @@ -403,7 +400,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) @@ -428,6 +425,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 */ diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 45ba99f5080b..aeb8f8f2c07a 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -282,7 +282,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) show_regs(regs); dump_stack(); - add_taint(TAINT_DIE); + add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); if (in_interrupt()) panic("Fatal exception in interrupt"); |