diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 101 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal32.c | 5 | ||||
-rw-r--r-- | arch/sparc64/kernel/systbls.S | 2 | ||||
-rw-r--r-- | arch/sparc64/mm/init.c | 19 |
4 files changed, 75 insertions, 52 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 1722dc51b0d..5f080cf04b3 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -103,6 +103,55 @@ void ptrace_disable(struct task_struct *child) /* nothing to do */ } +/* To get the necessary page struct, access_process_vm() first calls + * get_user_pages(). This has done a flush_dcache_page() on the + * accessed page. Then our caller (copy_{to,from}_user_page()) did + * to memcpy to read/write the data from that page. + * + * Now, the only thing we have to do is: + * 1) flush the D-cache if it's possible than an illegal alias + * has been created + * 2) flush the I-cache if this is pre-cheetah and we did a write + */ +void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, + unsigned long uaddr, void *kaddr, + unsigned long len, int write) +{ + BUG_ON(len > PAGE_SIZE); + +#ifdef DCACHE_ALIASING_POSSIBLE + /* If bit 13 of the kernel address we used to access the + * user page is the same as the virtual address that page + * is mapped to in the user's address space, we can skip the + * D-cache flush. + */ + if ((uaddr ^ kaddr) & (1UL << 13)) { + unsigned long start = __pa(kaddr); + unsigned long end = start + len; + + if (tlb_type == spitfire) { + for (; start < end; start += 32) + spitfire_put_dcache_tag(va & 0x3fe0, 0x0); + } else { + for (; start < end; start += 32) + __asm__ __volatile__( + "stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (va), + "i" (ASI_DCACHE_INVALIDATE)); + } + } +#endif + if (write && tlb_type == spitfire) { + unsigned long start = (unsigned long) kaddr; + unsigned long end = start + len; + + for (; start < end; start += 32) + flushi(start); + } +} + asmlinkage void do_ptrace(struct pt_regs *regs) { int request = regs->u_regs[UREG_I0]; @@ -227,7 +276,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, -res); else pt_os_succ_return(regs, tmp64, (void __user *) data); - goto flush_and_out; + goto out_tsk; } case PTRACE_POKETEXT: /* write the word at location addr. */ @@ -253,7 +302,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, -res); else pt_succ_return(regs, res); - goto flush_and_out; + goto out_tsk; } case PTRACE_GETREGS: { @@ -485,12 +534,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) (char __user *)addr2, data); if (res == data) { pt_succ_return(regs, 0); - goto flush_and_out; + goto out_tsk; } if (res >= 0) res = -EIO; pt_error_return(regs, -res); - goto flush_and_out; + goto out_tsk; } case PTRACE_WRITETEXT: @@ -499,12 +548,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) addr, data); if (res == data) { pt_succ_return(regs, 0); - goto flush_and_out; + goto out_tsk; } if (res >= 0) res = -EIO; pt_error_return(regs, -res); - goto flush_and_out; + goto out_tsk; } case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ addr = 1; @@ -514,25 +563,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EIO); goto out_tsk; } - if (addr != 1) { - unsigned long pc_mask = ~0UL; - - if ((child->thread_info->flags & _TIF_32BIT) != 0) - pc_mask = 0xffffffff; - - if (addr & 3) { - pt_error_return(regs, EINVAL); - goto out_tsk; - } -#ifdef DEBUG_PTRACE - printk ("Original: %016lx %016lx\n", - child->thread_info->kregs->tpc, - child->thread_info->kregs->tnpc); - printk ("Continuing with %016lx %016lx\n", addr, addr+4); -#endif - child->thread_info->kregs->tpc = (addr & pc_mask); - child->thread_info->kregs->tnpc = ((addr + 4) & pc_mask); - } if (request == PTRACE_SYSCALL) { set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); @@ -590,27 +620,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out_tsk; } } -flush_and_out: - { - unsigned long va; - - if (tlb_type == cheetah || tlb_type == cheetah_plus) { - for (va = 0; va < (1 << 16); va += (1 << 5)) - spitfire_put_dcache_tag(va, 0x0); - /* No need to mess with I-cache on Cheetah. */ - } else { - for (va = 0; va < L1DCACHE_SIZE; va += 32) - spitfire_put_dcache_tag(va, 0x0); - if (request == PTRACE_PEEKTEXT || - request == PTRACE_POKETEXT || - request == PTRACE_READTEXT || - request == PTRACE_WRITETEXT) { - for (va = 0; va < (PAGE_SIZE << 1); va += 32) - spitfire_put_icache_tag(va, 0x0); - __asm__ __volatile__("flush %g6"); - } - } - } out_tsk: if (child) put_task_struct(child); diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 859255cf676..9a375e975cf 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -192,10 +192,13 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: - case __SI_POLL >> 16: err |= __put_user(from->si_trapno, &to->si_trapno); err |= __put_user((unsigned long)from->si_addr, &to->si_addr); break; + case __SI_POLL >> 16: + err |= __put_user(from->si_band, &to->si_band); + err |= __put_user(from->si_fd, &to->si_fd); + break; case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __put_user(from->si_pid, &to->si_pid); diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 48170f77fff..a4ccb65aece 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -75,7 +75,7 @@ sys_call_table32: /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink - .word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid + .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid /*280*/ .word sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl #endif /* CONFIG_COMPAT */ diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 89022ccaa75..db6fa77b4da 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -201,13 +201,24 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p void flush_dcache_page(struct page *page) { - struct address_space *mapping = page_mapping(page); - int dirty = test_bit(PG_dcache_dirty, &page->flags); - int dirty_cpu = dcache_dirty_cpu(page); - int this_cpu = get_cpu(); + struct address_space *mapping; + int this_cpu; + /* Do not bother with the expensive D-cache flush if it + * is merely the zero page. The 'bigcore' testcase in GDB + * causes this case to run millions of times. + */ + if (page == ZERO_PAGE(0)) + return; + + this_cpu = get_cpu(); + + mapping = page_mapping(page); if (mapping && !mapping_mapped(mapping)) { + int dirty = test_bit(PG_dcache_dirty, &page->flags); if (dirty) { + int dirty_cpu = dcache_dirty_cpu(page); + if (dirty_cpu == this_cpu) goto out; smp_flush_dcache_page_impl(page, dirty_cpu); |