aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/kernel/ptrace.c101
-rw-r--r--arch/sparc64/kernel/signal32.c5
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c68
-rw-r--r--arch/sparc64/kernel/systbls.S14
-rw-r--r--arch/sparc64/mm/init.c19
5 files changed, 146 insertions, 61 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/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 567c91c77b2..1d3aa588df8 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -352,11 +352,11 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
err |= put_user(stat->size, &statbuf->st_size);
err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
- err |= put_user(0, &statbuf->__unused1);
+ err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
- err |= put_user(0, &statbuf->__unused2);
+ err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
- err |= put_user(0, &statbuf->__unused3);
+ err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
err |= put_user(stat->blksize, &statbuf->st_blksize);
err |= put_user(stat->blocks, &statbuf->st_blocks);
err |= put_user(0, &statbuf->__unused4[0]);
@@ -365,6 +365,68 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
return err;
}
+int cp_compat_stat64(struct kstat *stat, struct compat_stat64 __user *statbuf)
+{
+ int err;
+
+ err = put_user(huge_encode_dev(stat->dev), &statbuf->st_dev);
+ err |= put_user(stat->ino, &statbuf->st_ino);
+ err |= put_user(stat->mode, &statbuf->st_mode);
+ err |= put_user(stat->nlink, &statbuf->st_nlink);
+ err |= put_user(stat->uid, &statbuf->st_uid);
+ err |= put_user(stat->gid, &statbuf->st_gid);
+ err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
+ err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
+ err |= put_user(stat->size, &statbuf->st_size);
+ err |= put_user(stat->blksize, &statbuf->st_blksize);
+ err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[0]);
+ err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[4]);
+ err |= put_user(stat->blocks, &statbuf->st_blocks);
+ err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
+ err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
+ err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
+ err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
+ err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
+ err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
+ err |= put_user(0, &statbuf->__unused4);
+ err |= put_user(0, &statbuf->__unused5);
+
+ return err;
+}
+
+asmlinkage long compat_sys_stat64(char __user * filename,
+ struct compat_stat64 __user *statbuf)
+{
+ struct kstat stat;
+ int error = vfs_stat(filename, &stat);
+
+ if (!error)
+ error = cp_compat_stat64(&stat, statbuf);
+ return error;
+}
+
+asmlinkage long compat_sys_lstat64(char __user * filename,
+ struct compat_stat64 __user *statbuf)
+{
+ struct kstat stat;
+ int error = vfs_lstat(filename, &stat);
+
+ if (!error)
+ error = cp_compat_stat64(&stat, statbuf);
+ return error;
+}
+
+asmlinkage long compat_sys_fstat64(unsigned int fd,
+ struct compat_stat64 __user * statbuf)
+{
+ struct kstat stat;
+ int error = vfs_fstat(fd, &stat);
+
+ if (!error)
+ error = cp_compat_stat64(&stat, statbuf);
+ return error;
+}
+
asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
{
return sys_sysfs(option, arg1, arg2);
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 48170f77fff..a5e36a4c892 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -32,7 +32,7 @@ sys_call_table32:
.word sys32_umount, sys32_setgid16, sys32_getgid16, sys32_signal, sys32_geteuid16
/*50*/ .word sys32_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl
.word sys32_reboot, sys32_mmap2, sys_symlink, sys32_readlink, sys32_execve
-/*60*/ .word sys32_umask, sys_chroot, compat_sys_newfstat, sys_fstat64, sys_getpagesize
+/*60*/ .word sys32_umask, sys_chroot, compat_sys_newfstat, compat_sys_fstat64, sys_getpagesize
.word sys32_msync, sys_vfork, sys32_pread64, sys32_pwrite64, sys_geteuid
/*70*/ .word sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect
.word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys32_getgroups16
@@ -46,8 +46,8 @@ sys_call_table32:
.word sys32_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
/*120*/ .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
.word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate
-/*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys32_mkdir, sys_rmdir, sys32_utimes, sys_stat64
+/*130*/ .word sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_mkdir, sys_rmdir, sys32_utimes, compat_sys_stat64
/*140*/ .word sys32_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
.word compat_sys_setrlimit, sys_pivot_root, sys32_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
@@ -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 */
@@ -98,7 +98,7 @@ sys_call_table:
.word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl
.word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_stat64, sys_getpagesize
.word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall
/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys64_munmap, sys_mprotect
.word sys_madvise, sys_vhangup, sys_nis_syscall, sys_mincore, sys_getgroups
@@ -112,8 +112,8 @@ sys_call_table:
.word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd
/*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
.word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
- .word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
+/*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys_sendto, sys_shutdown
+ .word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
/*140*/ .word sys_sendfile64, sys_getpeername, sys_futex, sys_gettid, sys_getrlimit
.word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
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);