1/* 2 * linux/arch/parisc/kernel/sys_parisc.c 3 * 4 * this implements syscalls which are handled per-arch. 5 */ 6 7#include <asm/uaccess.h> 8#include <linux/file.h> 9#include <linux/fs.h> 10#include <linux/linkage.h> 11#include <linux/mm.h> 12#include <linux/mman.h> 13#include <linux/shm.h> 14#include <linux/smp_lock.h> 15 16int sys_pipe(int *fildes) 17{ 18 int fd[2]; 19 int error; 20 21 error = do_pipe(fd); 22 if (!error) { 23 if (copy_to_user(fildes, fd, 2*sizeof(int))) 24 error = -EFAULT; 25 } 26 return error; 27} 28 29int sys_pause(void) 30{ 31 current->state = TASK_INTERRUPTIBLE; 32 schedule(); 33 return -ERESTARTNOHAND; 34} 35 36static unsigned long get_unshared_area(unsigned long addr, unsigned long len) 37{ 38 struct vm_area_struct *vma; 39 40 if (!addr) 41 addr = TASK_UNMAPPED_BASE; 42 addr = PAGE_ALIGN(addr); 43 44 for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { 45 /* At this point: (!vma || addr < vma->vm_end). */ 46 if (TASK_SIZE - len < addr) 47 return -ENOMEM; 48 if (!vma || addr + len <= vma->vm_start) 49 return addr; 50 addr = vma->vm_end; 51 } 52} 53 54#define DCACHE_ALIGN(addr) (((addr) + (SHMLBA - 1)) &~ (SHMLBA - 1)) 55 56static unsigned long get_shared_area(struct inode *inode, unsigned long addr, 57 unsigned long len, unsigned long pgoff) 58{ 59 struct vm_area_struct *vma, *first_vma; 60 int offset; 61 62 first_vma = inode->i_mapping->i_mmap_shared; 63 offset = (first_vma->vm_start + ((pgoff - first_vma->vm_pgoff) << PAGE_SHIFT)) & (SHMLBA - 1); 64 65 if (!addr) 66 addr = TASK_UNMAPPED_BASE; 67 addr = DCACHE_ALIGN(addr - offset) + offset; 68 69 for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { 70 /* At this point: (!vma || addr < vma->vm_end). */ 71 if (TASK_SIZE - len < addr) 72 return -ENOMEM; 73 if (!vma || addr + len <= vma->vm_start) 74 return addr; 75 addr = DCACHE_ALIGN(vma->vm_end - offset) + offset; 76 if (addr < vma->vm_end) /* handle wraparound */ 77 return -ENOMEM; 78 } 79} 80 81unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, 82 unsigned long len, unsigned long pgoff, unsigned long flags) 83{ 84 struct inode *inode = NULL; 85 86 if (len > TASK_SIZE) 87 return -ENOMEM; 88 89 if (filp) { 90 inode = filp->f_dentry->d_inode; 91 } 92 93 if (inode && (flags & MAP_SHARED) && (inode->i_mapping->i_mmap_shared)) { 94 addr = get_shared_area(inode, addr, len, pgoff); 95 } else { 96 addr = get_unshared_area(addr, len); 97 } 98 return addr; 99} 100 101static unsigned long do_mmap2(unsigned long addr, unsigned long len, 102 unsigned long prot, unsigned long flags, unsigned long fd, 103 unsigned long pgoff) 104{ 105 struct file * file = NULL; 106 unsigned long error = -EBADF; 107 if (!(flags & MAP_ANONYMOUS)) { 108 file = fget(fd); 109 if (!file) 110 goto out; 111 } 112 113 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 114 115 down_write(¤t->mm->mmap_sem); 116 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 117 up_write(¤t->mm->mmap_sem); 118 119 if (file != NULL) 120 fput(file); 121out: 122 return error; 123} 124 125asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, 126 unsigned long prot, unsigned long flags, unsigned long fd, 127 unsigned long pgoff) 128{ 129 /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE 130 we have. */ 131 return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); 132} 133 134asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, 135 unsigned long prot, unsigned long flags, unsigned long fd, 136 unsigned long offset) 137{ 138 if (!(offset & ~PAGE_MASK)) { 139 return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); 140 } else { 141 return -EINVAL; 142 } 143} 144 145long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag) 146{ 147 unsigned long raddr; 148 int r; 149 150 r = sys_shmat(shmid, shmaddr, shmflag, &raddr); 151 if (r < 0) 152 return r; 153 return raddr; 154} 155 156 157#include <linux/msg.h> 158#include <linux/sem.h> 159#include <linux/shm.h> 160#include "sys32.h" 161 162struct broken_ipc_perm 163{ 164 key_t key; /* Key. */ 165 uid_t uid; /* Owner's user ID. */ 166 gid_t gid; /* Owner's group ID. */ 167 uid_t cuid; /* Creator's user ID. */ 168 gid_t cgid; /* Creator's group ID. */ 169 unsigned short int mode; /* Read/write permission. */ 170 unsigned short int __pad1; 171 unsigned short int seq; /* Sequence number. */ 172 unsigned short int __pad2; 173 unsigned long int __unused1; 174 unsigned long int __unused2; 175}; 176 177struct broken_shmid64_ds { 178 struct broken_ipc_perm shm_perm; /* operation perms */ 179 size_t shm_segsz; /* size of segment (bytes) */ 180#ifndef __LP64__ 181 unsigned int __pad1; 182#endif 183 __kernel_time_t shm_atime; /* last attach time */ 184#ifndef __LP64__ 185 unsigned int __pad2; 186#endif 187 __kernel_time_t shm_dtime; /* last detach time */ 188#ifndef __LP64__ 189 unsigned int __pad3; 190#endif 191 __kernel_time_t shm_ctime; /* last change time */ 192 __kernel_pid_t shm_cpid; /* pid of creator */ 193 __kernel_pid_t shm_lpid; /* pid of last operator */ 194 unsigned int shm_nattch; /* no. of current attaches */ 195 unsigned int __unused1; 196 unsigned int __unused2; 197}; 198 199static void convert_broken_perm (struct broken_ipc_perm *out, struct ipc64_perm *in) 200{ 201 out->key = in->key; 202 out->uid = in->uid; 203 out->gid = in->gid; 204 out->cuid = in->cuid; 205 out->cgid = in->cgid; 206 out->mode = in->mode; 207 out->seq = in->seq; 208} 209 210static int copyout_broken_shmid64(struct broken_shmid64_ds *buf, struct shmid64_ds *sbuf) 211{ 212 struct broken_shmid64_ds tbuf; 213 214 memset(&tbuf, 0, sizeof tbuf); 215 convert_broken_perm (&tbuf.shm_perm, &sbuf->shm_perm); 216 tbuf.shm_segsz = sbuf->shm_segsz; 217 tbuf.shm_atime = sbuf->shm_atime; 218 tbuf.shm_dtime = sbuf->shm_dtime; 219 tbuf.shm_ctime = sbuf->shm_ctime; 220 tbuf.shm_cpid = sbuf->shm_cpid; 221 tbuf.shm_lpid = sbuf->shm_lpid; 222 tbuf.shm_nattch = sbuf->shm_nattch; 223 return copy_to_user(buf, &tbuf, sizeof tbuf); 224} 225 226int sys_msgctl_broken(int msqid, int cmd, struct msqid_ds *buf) 227{ 228 return sys_msgctl (msqid, cmd & ~IPC_64, buf); 229} 230 231int sys_semctl_broken(int semid, int semnum, int cmd, union semun arg) 232{ 233 return sys_semctl (semid, semnum, cmd & ~IPC_64, arg); 234} 235 236int sys_shmctl_broken(int shmid, int cmd, struct shmid64_ds *buf) 237{ 238 struct shmid64_ds sbuf; 239 int err; 240 241 if (cmd & IPC_64) { 242 cmd &= ~IPC_64; 243 if (cmd == IPC_STAT || cmd == SHM_STAT) { 244 KERNEL_SYSCALL(err, sys_shmctl, shmid, cmd, (struct shmid_ds *)&sbuf); 245 if (err == 0) 246 err = copyout_broken_shmid64((struct broken_shmid64_ds *)buf, &sbuf); 247 return err; 248 } 249 } 250 return sys_shmctl (shmid, cmd, (struct shmid_ds *)buf); 251} 252 253