xref: /openbmc/linux/arch/sh/kernel/sys_sh.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * linux/arch/sh/kernel/sys_sh.c
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  * This file contains various random system calls that
5*1da177e4SLinus Torvalds  * have a non-standard calling sequence on the Linux/SuperH
6*1da177e4SLinus Torvalds  * platform.
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  * Taken from i386 version.
9*1da177e4SLinus Torvalds  */
10*1da177e4SLinus Torvalds 
11*1da177e4SLinus Torvalds #include <linux/errno.h>
12*1da177e4SLinus Torvalds #include <linux/sched.h>
13*1da177e4SLinus Torvalds #include <linux/mm.h>
14*1da177e4SLinus Torvalds #include <linux/smp.h>
15*1da177e4SLinus Torvalds #include <linux/smp_lock.h>
16*1da177e4SLinus Torvalds #include <linux/sem.h>
17*1da177e4SLinus Torvalds #include <linux/msg.h>
18*1da177e4SLinus Torvalds #include <linux/shm.h>
19*1da177e4SLinus Torvalds #include <linux/stat.h>
20*1da177e4SLinus Torvalds #include <linux/syscalls.h>
21*1da177e4SLinus Torvalds #include <linux/mman.h>
22*1da177e4SLinus Torvalds #include <linux/file.h>
23*1da177e4SLinus Torvalds #include <linux/utsname.h>
24*1da177e4SLinus Torvalds 
25*1da177e4SLinus Torvalds #include <asm/uaccess.h>
26*1da177e4SLinus Torvalds #include <asm/ipc.h>
27*1da177e4SLinus Torvalds 
28*1da177e4SLinus Torvalds /*
29*1da177e4SLinus Torvalds  * sys_pipe() is the normal C calling standard for creating
30*1da177e4SLinus Torvalds  * a pipe. It's not the way Unix traditionally does this, though.
31*1da177e4SLinus Torvalds  */
32*1da177e4SLinus Torvalds asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
33*1da177e4SLinus Torvalds 	unsigned long r6, unsigned long r7,
34*1da177e4SLinus Torvalds 	struct pt_regs regs)
35*1da177e4SLinus Torvalds {
36*1da177e4SLinus Torvalds 	int fd[2];
37*1da177e4SLinus Torvalds 	int error;
38*1da177e4SLinus Torvalds 
39*1da177e4SLinus Torvalds 	error = do_pipe(fd);
40*1da177e4SLinus Torvalds 	if (!error) {
41*1da177e4SLinus Torvalds 		regs.regs[1] = fd[1];
42*1da177e4SLinus Torvalds 		return fd[0];
43*1da177e4SLinus Torvalds 	}
44*1da177e4SLinus Torvalds 	return error;
45*1da177e4SLinus Torvalds }
46*1da177e4SLinus Torvalds 
47*1da177e4SLinus Torvalds #if defined(HAVE_ARCH_UNMAPPED_AREA)
48*1da177e4SLinus Torvalds /*
49*1da177e4SLinus Torvalds  * To avoid cache alias, we map the shard page with same color.
50*1da177e4SLinus Torvalds  */
51*1da177e4SLinus Torvalds #define COLOUR_ALIGN(addr)	(((addr)+SHMLBA-1)&~(SHMLBA-1))
52*1da177e4SLinus Torvalds 
53*1da177e4SLinus Torvalds unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
54*1da177e4SLinus Torvalds 	unsigned long len, unsigned long pgoff, unsigned long flags)
55*1da177e4SLinus Torvalds {
56*1da177e4SLinus Torvalds 	struct mm_struct *mm = current->mm;
57*1da177e4SLinus Torvalds 	struct vm_area_struct *vma;
58*1da177e4SLinus Torvalds 	unsigned long start_addr;
59*1da177e4SLinus Torvalds 
60*1da177e4SLinus Torvalds 	if (flags & MAP_FIXED) {
61*1da177e4SLinus Torvalds 		/* We do not accept a shared mapping if it would violate
62*1da177e4SLinus Torvalds 		 * cache aliasing constraints.
63*1da177e4SLinus Torvalds 		 */
64*1da177e4SLinus Torvalds 		if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
65*1da177e4SLinus Torvalds 			return -EINVAL;
66*1da177e4SLinus Torvalds 		return addr;
67*1da177e4SLinus Torvalds 	}
68*1da177e4SLinus Torvalds 
69*1da177e4SLinus Torvalds 	if (len > TASK_SIZE)
70*1da177e4SLinus Torvalds 		return -ENOMEM;
71*1da177e4SLinus Torvalds 
72*1da177e4SLinus Torvalds 	if (addr) {
73*1da177e4SLinus Torvalds 		if (flags & MAP_PRIVATE)
74*1da177e4SLinus Torvalds 			addr = PAGE_ALIGN(addr);
75*1da177e4SLinus Torvalds 		else
76*1da177e4SLinus Torvalds 			addr = COLOUR_ALIGN(addr);
77*1da177e4SLinus Torvalds 		vma = find_vma(mm, addr);
78*1da177e4SLinus Torvalds 		if (TASK_SIZE - len >= addr &&
79*1da177e4SLinus Torvalds 		    (!vma || addr + len <= vma->vm_start))
80*1da177e4SLinus Torvalds 			return addr;
81*1da177e4SLinus Torvalds 	}
82*1da177e4SLinus Torvalds 	if (flags & MAP_PRIVATE)
83*1da177e4SLinus Torvalds 		addr = PAGE_ALIGN(mm->free_area_cache);
84*1da177e4SLinus Torvalds 	else
85*1da177e4SLinus Torvalds 		addr = COLOUR_ALIGN(mm->free_area_cache);
86*1da177e4SLinus Torvalds 	start_addr = addr;
87*1da177e4SLinus Torvalds 
88*1da177e4SLinus Torvalds full_search:
89*1da177e4SLinus Torvalds 	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
90*1da177e4SLinus Torvalds 		/* At this point:  (!vma || addr < vma->vm_end). */
91*1da177e4SLinus Torvalds 		if (TASK_SIZE - len < addr) {
92*1da177e4SLinus Torvalds 			/*
93*1da177e4SLinus Torvalds 			 * Start a new search - just in case we missed
94*1da177e4SLinus Torvalds 			 * some holes.
95*1da177e4SLinus Torvalds 			 */
96*1da177e4SLinus Torvalds 			if (start_addr != TASK_UNMAPPED_BASE) {
97*1da177e4SLinus Torvalds 				start_addr = addr = TASK_UNMAPPED_BASE;
98*1da177e4SLinus Torvalds 				goto full_search;
99*1da177e4SLinus Torvalds 			}
100*1da177e4SLinus Torvalds 			return -ENOMEM;
101*1da177e4SLinus Torvalds 		}
102*1da177e4SLinus Torvalds 		if (!vma || addr + len <= vma->vm_start) {
103*1da177e4SLinus Torvalds 			/*
104*1da177e4SLinus Torvalds 			 * Remember the place where we stopped the search:
105*1da177e4SLinus Torvalds 			 */
106*1da177e4SLinus Torvalds 			mm->free_area_cache = addr + len;
107*1da177e4SLinus Torvalds 			return addr;
108*1da177e4SLinus Torvalds 		}
109*1da177e4SLinus Torvalds 		addr = vma->vm_end;
110*1da177e4SLinus Torvalds 		if (!(flags & MAP_PRIVATE))
111*1da177e4SLinus Torvalds 			addr = COLOUR_ALIGN(addr);
112*1da177e4SLinus Torvalds 	}
113*1da177e4SLinus Torvalds }
114*1da177e4SLinus Torvalds #endif
115*1da177e4SLinus Torvalds 
116*1da177e4SLinus Torvalds static inline long
117*1da177e4SLinus Torvalds do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
118*1da177e4SLinus Torvalds 	 unsigned long flags, int fd, unsigned long pgoff)
119*1da177e4SLinus Torvalds {
120*1da177e4SLinus Torvalds 	int error = -EBADF;
121*1da177e4SLinus Torvalds 	struct file *file = NULL;
122*1da177e4SLinus Torvalds 
123*1da177e4SLinus Torvalds 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
124*1da177e4SLinus Torvalds 	if (!(flags & MAP_ANONYMOUS)) {
125*1da177e4SLinus Torvalds 		file = fget(fd);
126*1da177e4SLinus Torvalds 		if (!file)
127*1da177e4SLinus Torvalds 			goto out;
128*1da177e4SLinus Torvalds 	}
129*1da177e4SLinus Torvalds 
130*1da177e4SLinus Torvalds 	down_write(&current->mm->mmap_sem);
131*1da177e4SLinus Torvalds 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
132*1da177e4SLinus Torvalds 	up_write(&current->mm->mmap_sem);
133*1da177e4SLinus Torvalds 
134*1da177e4SLinus Torvalds 	if (file)
135*1da177e4SLinus Torvalds 		fput(file);
136*1da177e4SLinus Torvalds out:
137*1da177e4SLinus Torvalds 	return error;
138*1da177e4SLinus Torvalds }
139*1da177e4SLinus Torvalds 
140*1da177e4SLinus Torvalds asmlinkage int old_mmap(unsigned long addr, unsigned long len,
141*1da177e4SLinus Torvalds 	unsigned long prot, unsigned long flags,
142*1da177e4SLinus Torvalds 	int fd, unsigned long off)
143*1da177e4SLinus Torvalds {
144*1da177e4SLinus Torvalds 	if (off & ~PAGE_MASK)
145*1da177e4SLinus Torvalds 		return -EINVAL;
146*1da177e4SLinus Torvalds 	return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
147*1da177e4SLinus Torvalds }
148*1da177e4SLinus Torvalds 
149*1da177e4SLinus Torvalds asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
150*1da177e4SLinus Torvalds 	unsigned long prot, unsigned long flags,
151*1da177e4SLinus Torvalds 	unsigned long fd, unsigned long pgoff)
152*1da177e4SLinus Torvalds {
153*1da177e4SLinus Torvalds 	return do_mmap2(addr, len, prot, flags, fd, pgoff);
154*1da177e4SLinus Torvalds }
155*1da177e4SLinus Torvalds 
156*1da177e4SLinus Torvalds /*
157*1da177e4SLinus Torvalds  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
158*1da177e4SLinus Torvalds  *
159*1da177e4SLinus Torvalds  * This is really horribly ugly.
160*1da177e4SLinus Torvalds  */
161*1da177e4SLinus Torvalds asmlinkage int sys_ipc(uint call, int first, int second,
162*1da177e4SLinus Torvalds 		       int third, void __user *ptr, long fifth)
163*1da177e4SLinus Torvalds {
164*1da177e4SLinus Torvalds 	int version, ret;
165*1da177e4SLinus Torvalds 
166*1da177e4SLinus Torvalds 	version = call >> 16; /* hack for backward compatibility */
167*1da177e4SLinus Torvalds 	call &= 0xffff;
168*1da177e4SLinus Torvalds 
169*1da177e4SLinus Torvalds 	if (call <= SEMCTL)
170*1da177e4SLinus Torvalds 		switch (call) {
171*1da177e4SLinus Torvalds 		case SEMOP:
172*1da177e4SLinus Torvalds 			return sys_semtimedop(first, (struct sembuf __user *)ptr,
173*1da177e4SLinus Torvalds 					      second, NULL);
174*1da177e4SLinus Torvalds 		case SEMTIMEDOP:
175*1da177e4SLinus Torvalds 			return sys_semtimedop(first, (struct sembuf __user *)ptr,
176*1da177e4SLinus Torvalds 					      second,
177*1da177e4SLinus Torvalds 					      (const struct timespec __user *)fifth);
178*1da177e4SLinus Torvalds 		case SEMGET:
179*1da177e4SLinus Torvalds 			return sys_semget (first, second, third);
180*1da177e4SLinus Torvalds 		case SEMCTL: {
181*1da177e4SLinus Torvalds 			union semun fourth;
182*1da177e4SLinus Torvalds 			if (!ptr)
183*1da177e4SLinus Torvalds 				return -EINVAL;
184*1da177e4SLinus Torvalds 			if (get_user(fourth.__pad, (void * __user *) ptr))
185*1da177e4SLinus Torvalds 				return -EFAULT;
186*1da177e4SLinus Torvalds 			return sys_semctl (first, second, third, fourth);
187*1da177e4SLinus Torvalds 			}
188*1da177e4SLinus Torvalds 		default:
189*1da177e4SLinus Torvalds 			return -EINVAL;
190*1da177e4SLinus Torvalds 		}
191*1da177e4SLinus Torvalds 
192*1da177e4SLinus Torvalds 	if (call <= MSGCTL)
193*1da177e4SLinus Torvalds 		switch (call) {
194*1da177e4SLinus Torvalds 		case MSGSND:
195*1da177e4SLinus Torvalds 			return sys_msgsnd (first, (struct msgbuf __user *) ptr,
196*1da177e4SLinus Torvalds 					  second, third);
197*1da177e4SLinus Torvalds 		case MSGRCV:
198*1da177e4SLinus Torvalds 			switch (version) {
199*1da177e4SLinus Torvalds 			case 0: {
200*1da177e4SLinus Torvalds 				struct ipc_kludge tmp;
201*1da177e4SLinus Torvalds 				if (!ptr)
202*1da177e4SLinus Torvalds 					return -EINVAL;
203*1da177e4SLinus Torvalds 
204*1da177e4SLinus Torvalds 				if (copy_from_user(&tmp,
205*1da177e4SLinus Torvalds 						   (struct ipc_kludge __user *) ptr,
206*1da177e4SLinus Torvalds 						   sizeof (tmp)))
207*1da177e4SLinus Torvalds 					return -EFAULT;
208*1da177e4SLinus Torvalds 				return sys_msgrcv (first, tmp.msgp, second,
209*1da177e4SLinus Torvalds 						   tmp.msgtyp, third);
210*1da177e4SLinus Torvalds 				}
211*1da177e4SLinus Torvalds 			default:
212*1da177e4SLinus Torvalds 				return sys_msgrcv (first,
213*1da177e4SLinus Torvalds 						   (struct msgbuf __user *) ptr,
214*1da177e4SLinus Torvalds 						   second, fifth, third);
215*1da177e4SLinus Torvalds 			}
216*1da177e4SLinus Torvalds 		case MSGGET:
217*1da177e4SLinus Torvalds 			return sys_msgget ((key_t) first, second);
218*1da177e4SLinus Torvalds 		case MSGCTL:
219*1da177e4SLinus Torvalds 			return sys_msgctl (first, second,
220*1da177e4SLinus Torvalds 					   (struct msqid_ds __user *) ptr);
221*1da177e4SLinus Torvalds 		default:
222*1da177e4SLinus Torvalds 			return -EINVAL;
223*1da177e4SLinus Torvalds 		}
224*1da177e4SLinus Torvalds 	if (call <= SHMCTL)
225*1da177e4SLinus Torvalds 		switch (call) {
226*1da177e4SLinus Torvalds 		case SHMAT:
227*1da177e4SLinus Torvalds 			switch (version) {
228*1da177e4SLinus Torvalds 			default: {
229*1da177e4SLinus Torvalds 				ulong raddr;
230*1da177e4SLinus Torvalds 				ret = do_shmat (first, (char __user *) ptr,
231*1da177e4SLinus Torvalds 						 second, &raddr);
232*1da177e4SLinus Torvalds 				if (ret)
233*1da177e4SLinus Torvalds 					return ret;
234*1da177e4SLinus Torvalds 				return put_user (raddr, (ulong __user *) third);
235*1da177e4SLinus Torvalds 			}
236*1da177e4SLinus Torvalds 			case 1:	/* iBCS2 emulator entry point */
237*1da177e4SLinus Torvalds 				if (!segment_eq(get_fs(), get_ds()))
238*1da177e4SLinus Torvalds 					return -EINVAL;
239*1da177e4SLinus Torvalds 				return do_shmat (first, (char __user *) ptr,
240*1da177e4SLinus Torvalds 						  second, (ulong *) third);
241*1da177e4SLinus Torvalds 			}
242*1da177e4SLinus Torvalds 		case SHMDT:
243*1da177e4SLinus Torvalds 			return sys_shmdt ((char __user *)ptr);
244*1da177e4SLinus Torvalds 		case SHMGET:
245*1da177e4SLinus Torvalds 			return sys_shmget (first, second, third);
246*1da177e4SLinus Torvalds 		case SHMCTL:
247*1da177e4SLinus Torvalds 			return sys_shmctl (first, second,
248*1da177e4SLinus Torvalds 					   (struct shmid_ds __user *) ptr);
249*1da177e4SLinus Torvalds 		default:
250*1da177e4SLinus Torvalds 			return -EINVAL;
251*1da177e4SLinus Torvalds 		}
252*1da177e4SLinus Torvalds 
253*1da177e4SLinus Torvalds 	return -EINVAL;
254*1da177e4SLinus Torvalds }
255*1da177e4SLinus Torvalds 
256*1da177e4SLinus Torvalds asmlinkage int sys_uname(struct old_utsname * name)
257*1da177e4SLinus Torvalds {
258*1da177e4SLinus Torvalds 	int err;
259*1da177e4SLinus Torvalds 	if (!name)
260*1da177e4SLinus Torvalds 		return -EFAULT;
261*1da177e4SLinus Torvalds 	down_read(&uts_sem);
262*1da177e4SLinus Torvalds 	err=copy_to_user(name, &system_utsname, sizeof (*name));
263*1da177e4SLinus Torvalds 	up_read(&uts_sem);
264*1da177e4SLinus Torvalds 	return err?-EFAULT:0;
265*1da177e4SLinus Torvalds }
266*1da177e4SLinus Torvalds 
267*1da177e4SLinus Torvalds asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
268*1da177e4SLinus Torvalds 			     size_t count, long dummy, loff_t pos)
269*1da177e4SLinus Torvalds {
270*1da177e4SLinus Torvalds 	return sys_pread64(fd, buf, count, pos);
271*1da177e4SLinus Torvalds }
272*1da177e4SLinus Torvalds 
273*1da177e4SLinus Torvalds asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
274*1da177e4SLinus Torvalds 			      size_t count, long dummy, loff_t pos)
275*1da177e4SLinus Torvalds {
276*1da177e4SLinus Torvalds 	return sys_pwrite64(fd, buf, count, pos);
277*1da177e4SLinus Torvalds }
278*1da177e4SLinus Torvalds 
279*1da177e4SLinus Torvalds asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
280*1da177e4SLinus Torvalds 				u32 len0, u32 len1, int advice)
281*1da177e4SLinus Torvalds {
282*1da177e4SLinus Torvalds #ifdef  __LITTLE_ENDIAN__
283*1da177e4SLinus Torvalds 	return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
284*1da177e4SLinus Torvalds 				(u64)len1 << 32 | len0,	advice);
285*1da177e4SLinus Torvalds #else
286*1da177e4SLinus Torvalds 	return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
287*1da177e4SLinus Torvalds 				(u64)len0 << 32 | len1,	advice);
288*1da177e4SLinus Torvalds #endif
289*1da177e4SLinus Torvalds }
290