sys_sh.c 6.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * linux/arch/sh/kernel/sys_sh.c
 *
 * This file contains various random system calls that
 * have a non-standard calling sequence on the Linux/SuperH
 * platform.
 *
 * Taken from i386 version.
 */
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/syscalls.h>
#include <linux/mman.h>
#include <linux/file.h>
#include <linux/utsname.h>
22
#include <linux/module.h>
23
#include <linux/fs.h>
A
Adrian Bunk 已提交
24
#include <linux/ipc.h>
25
#include <asm/cacheflush.h>
L
Linus Torvalds 已提交
26
#include <asm/uaccess.h>
27
#include <asm/unistd.h>
L
Linus Torvalds 已提交
28

29 30 31
unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
EXPORT_SYMBOL(shm_align_mask);

P
Paul Mundt 已提交
32
#ifdef CONFIG_MMU
L
Linus Torvalds 已提交
33
/*
34
 * To avoid cache aliases, we map the shared page with same color.
L
Linus Torvalds 已提交
35
 */
36 37 38
#define COLOUR_ALIGN(addr, pgoff)				\
	((((addr) + shm_align_mask) & ~shm_align_mask) +	\
	 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
L
Linus Torvalds 已提交
39 40 41 42 43 44 45

unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
	unsigned long len, unsigned long pgoff, unsigned long flags)
{
	struct mm_struct *mm = current->mm;
	struct vm_area_struct *vma;
	unsigned long start_addr;
46
	int do_colour_align;
L
Linus Torvalds 已提交
47 48 49 50 51

	if (flags & MAP_FIXED) {
		/* We do not accept a shared mapping if it would violate
		 * cache aliasing constraints.
		 */
52
		if ((flags & MAP_SHARED) && (addr & shm_align_mask))
L
Linus Torvalds 已提交
53 54 55 56
			return -EINVAL;
		return addr;
	}

57
	if (unlikely(len > TASK_SIZE))
L
Linus Torvalds 已提交
58 59
		return -ENOMEM;

60 61 62 63
	do_colour_align = 0;
	if (filp || (flags & MAP_SHARED))
		do_colour_align = 1;

L
Linus Torvalds 已提交
64
	if (addr) {
65 66
		if (do_colour_align)
			addr = COLOUR_ALIGN(addr, pgoff);
L
Linus Torvalds 已提交
67
		else
68 69
			addr = PAGE_ALIGN(addr);

L
Linus Torvalds 已提交
70 71 72 73 74
		vma = find_vma(mm, addr);
		if (TASK_SIZE - len >= addr &&
		    (!vma || addr + len <= vma->vm_start))
			return addr;
	}
75 76 77 78

	if (len > mm->cached_hole_size) {
		start_addr = addr = mm->free_area_cache;
	} else {
79
	        mm->cached_hole_size = 0;
80
		start_addr = addr = TASK_UNMAPPED_BASE;
81
	}
L
Linus Torvalds 已提交
82 83

full_search:
84 85 86 87 88
	if (do_colour_align)
		addr = COLOUR_ALIGN(addr, pgoff);
	else
		addr = PAGE_ALIGN(mm->free_area_cache);

L
Linus Torvalds 已提交
89 90
	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
		/* At this point:  (!vma || addr < vma->vm_end). */
91
		if (unlikely(TASK_SIZE - len < addr)) {
L
Linus Torvalds 已提交
92 93 94 95 96 97
			/*
			 * Start a new search - just in case we missed
			 * some holes.
			 */
			if (start_addr != TASK_UNMAPPED_BASE) {
				start_addr = addr = TASK_UNMAPPED_BASE;
98
				mm->cached_hole_size = 0;
L
Linus Torvalds 已提交
99 100 101 102
				goto full_search;
			}
			return -ENOMEM;
		}
103
		if (likely(!vma || addr + len <= vma->vm_start)) {
L
Linus Torvalds 已提交
104 105 106 107 108 109
			/*
			 * Remember the place where we stopped the search:
			 */
			mm->free_area_cache = addr + len;
			return addr;
		}
110 111 112
		if (addr + mm->cached_hole_size < vma->vm_start)
		        mm->cached_hole_size = vma->vm_start - addr;

L
Linus Torvalds 已提交
113
		addr = vma->vm_end;
114 115
		if (do_colour_align)
			addr = COLOUR_ALIGN(addr, pgoff);
L
Linus Torvalds 已提交
116 117
	}
}
P
Paul Mundt 已提交
118
#endif /* CONFIG_MMU */
L
Linus Torvalds 已提交
119 120

static inline long
121
do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
L
Linus Torvalds 已提交
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	 unsigned long flags, int fd, unsigned long pgoff)
{
	int error = -EBADF;
	struct file *file = NULL;

	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
	if (!(flags & MAP_ANONYMOUS)) {
		file = fget(fd);
		if (!file)
			goto out;
	}

	down_write(&current->mm->mmap_sem);
	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
	up_write(&current->mm->mmap_sem);

	if (file)
		fput(file);
out:
	return error;
}

asmlinkage int old_mmap(unsigned long addr, unsigned long len,
	unsigned long prot, unsigned long flags,
	int fd, unsigned long off)
{
	if (off & ~PAGE_MASK)
		return -EINVAL;
	return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
}

asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
	unsigned long prot, unsigned long flags,
	unsigned long fd, unsigned long pgoff)
{
	return do_mmap2(addr, len, prot, flags, fd, pgoff);
}

/*
 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
 *
 * This is really horribly ugly.
 */
asmlinkage int sys_ipc(uint call, int first, int second,
		       int third, void __user *ptr, long fifth)
{
	int version, ret;

	version = call >> 16; /* hack for backward compatibility */
	call &= 0xffff;

Y
Yoshihiro Shimoda 已提交
173
	if (call <= SEMTIMEDOP)
L
Linus Torvalds 已提交
174 175
		switch (call) {
		case SEMOP:
176 177
			return sys_semtimedop(first,
					      (struct sembuf __user *)ptr,
L
Linus Torvalds 已提交
178 179
					      second, NULL);
		case SEMTIMEDOP:
180 181 182
			return sys_semtimedop(first,
				(struct sembuf __user *)ptr, second,
			        (const struct timespec __user *)fifth);
L
Linus Torvalds 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196
		case SEMGET:
			return sys_semget (first, second, third);
		case SEMCTL: {
			union semun fourth;
			if (!ptr)
				return -EINVAL;
			if (get_user(fourth.__pad, (void * __user *) ptr))
				return -EFAULT;
			return sys_semctl (first, second, third, fourth);
			}
		default:
			return -EINVAL;
		}

197
	if (call <= MSGCTL)
L
Linus Torvalds 已提交
198 199
		switch (call) {
		case MSGSND:
200
			return sys_msgsnd (first, (struct msgbuf __user *) ptr,
L
Linus Torvalds 已提交
201 202 203
					  second, third);
		case MSGRCV:
			switch (version) {
204 205
			case 0:
			{
L
Linus Torvalds 已提交
206
				struct ipc_kludge tmp;
207

L
Linus Torvalds 已提交
208 209
				if (!ptr)
					return -EINVAL;
210

L
Linus Torvalds 已提交
211
				if (copy_from_user(&tmp,
212
					(struct ipc_kludge __user *) ptr,
L
Linus Torvalds 已提交
213 214
						   sizeof (tmp)))
					return -EFAULT;
215

L
Linus Torvalds 已提交
216 217
				return sys_msgrcv (first, tmp.msgp, second,
						   tmp.msgtyp, third);
218
			}
L
Linus Torvalds 已提交
219 220 221 222 223 224 225 226 227 228 229 230 231
			default:
				return sys_msgrcv (first,
						   (struct msgbuf __user *) ptr,
						   second, fifth, third);
			}
		case MSGGET:
			return sys_msgget ((key_t) first, second);
		case MSGCTL:
			return sys_msgctl (first, second,
					   (struct msqid_ds __user *) ptr);
		default:
			return -EINVAL;
		}
232
	if (call <= SHMCTL)
L
Linus Torvalds 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
		switch (call) {
		case SHMAT:
			switch (version) {
			default: {
				ulong raddr;
				ret = do_shmat (first, (char __user *) ptr,
						 second, &raddr);
				if (ret)
					return ret;
				return put_user (raddr, (ulong __user *) third);
			}
			case 1:	/* iBCS2 emulator entry point */
				if (!segment_eq(get_fs(), get_ds()))
					return -EINVAL;
				return do_shmat (first, (char __user *) ptr,
						  second, (ulong *) third);
			}
250
		case SHMDT:
L
Linus Torvalds 已提交
251 252 253 254 255 256 257 258 259
			return sys_shmdt ((char __user *)ptr);
		case SHMGET:
			return sys_shmget (first, second, third);
		case SHMCTL:
			return sys_shmctl (first, second,
					   (struct shmid_ds __user *) ptr);
		default:
			return -EINVAL;
		}
260

L
Linus Torvalds 已提交
261 262 263 264 265 266 267 268 269
	return -EINVAL;
}

asmlinkage int sys_uname(struct old_utsname * name)
{
	int err;
	if (!name)
		return -EFAULT;
	down_read(&uts_sem);
270
	err = copy_to_user(name, utsname(), sizeof (*name));
L
Linus Torvalds 已提交
271 272 273
	up_read(&uts_sem);
	return err?-EFAULT:0;
}