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(&current->mm->mmap_sem);
116	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
117	up_write(&current->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