diff options
Diffstat (limited to 'arch/microblaze/kernel/sys_microblaze.c')
| -rw-r--r-- | arch/microblaze/kernel/sys_microblaze.c | 225 | 
1 files changed, 225 insertions, 0 deletions
| diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c new file mode 100644 index 000000000000..31905ff590b7 --- /dev/null +++ b/arch/microblaze/kernel/sys_microblaze.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2007-2009 PetaLogix + * Copyright (C) 2007 John Williams <john.williams@petalogix.com> + * + * Copyright (C) 2006 Atmark Techno, Inc. + *	Yasushi SHOJI <yashi@atmark-techno.com> + *	Tetsuya OHKAWA <tetsuya@atmark-techno.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/syscalls.h> +#include <linux/sem.h> +#include <linux/msg.h> +#include <linux/shm.h> +#include <linux/stat.h> +#include <linux/mman.h> +#include <linux/sys.h> +#include <linux/ipc.h> +#include <linux/utsname.h> +#include <linux/file.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/fs.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/unistd.h> + +#include <asm/syscalls.h> +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. This will be remove with new toolchain. + */ +asmlinkage int +sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth) +{ +	int version, ret; + +	version = call >> 16; /* hack for backward compatibility */ +	call &= 0xffff; + +	ret = -EINVAL; +	switch (call) { +	case SEMOP: +		ret = sys_semop(first, (struct sembuf *)ptr, second); +		break; +	case SEMGET: +		ret = sys_semget(first, second, third); +		break; +	case SEMCTL: +	{ +		union semun fourth; + +		if (!ptr) +			break; +		ret = (access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT) +				|| (get_user(fourth.__pad, (void **)ptr)) ; +		if (ret) +			break; +		ret = sys_semctl(first, second, third, fourth); +		break; +	} +	case MSGSND: +		ret = sys_msgsnd(first, (struct msgbuf *) ptr, second, third); +		break; +	case MSGRCV: +		switch (version) { +		case 0: { +			struct ipc_kludge tmp; + +			if (!ptr) +				break; +			ret = (access_ok(VERIFY_READ, ptr, sizeof(tmp)) +				? 0 : -EFAULT) || copy_from_user(&tmp, +				(struct ipc_kludge *) ptr, sizeof(tmp)); +			if (ret) +				break; +			ret = sys_msgrcv(first, tmp.msgp, second, tmp.msgtyp, +					third); +			break; +			} +		default: +			ret = sys_msgrcv(first, (struct msgbuf *) ptr, +					second, fifth, third); +			break; +		} +		break; +	case MSGGET: +		ret = sys_msgget((key_t) first, second); +		break; +	case MSGCTL: +		ret = sys_msgctl(first, second, (struct msqid_ds *) ptr); +		break; +	case SHMAT: +		switch (version) { +		default: { +			ulong raddr; +			ret = access_ok(VERIFY_WRITE, (ulong *) third, +					sizeof(ulong)) ? 0 : -EFAULT; +			if (ret) +				break; +			ret = do_shmat(first, (char *) ptr, second, &raddr); +			if (ret) +				break; +			ret = put_user(raddr, (ulong *) third); +			break; +			} +		case 1:	/* iBCS2 emulator entry point */ +			if (!segment_eq(get_fs(), get_ds())) +				break; +			ret = do_shmat(first, (char *) ptr, second, +					(ulong *) third); +			break; +		} +		break; +	case SHMDT: +		ret = sys_shmdt((char *)ptr); +		break; +	case SHMGET: +		ret = sys_shmget(first, second, third); +		break; +	case SHMCTL: +		ret = sys_shmctl(first, second, (struct shmid_ds *) ptr); +		break; +	} +	return ret; +} + +asmlinkage int sys_vfork(struct pt_regs *regs) +{ +	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r1, +						regs, 0, NULL, NULL); +} + +asmlinkage int sys_clone(int flags, unsigned long stack, struct pt_regs *regs) +{ +	if (!stack) +		stack = regs->r1; +	return do_fork(flags, stack, regs, 0, NULL, NULL); +} + +asmlinkage int sys_execve(char __user *filenamei, char __user *__user *argv, +			char __user *__user *envp, struct pt_regs *regs) +{ +	int error; +	char *filename; + +	filename = getname(filenamei); +	error = PTR_ERR(filename); +	if (IS_ERR(filename)) +		goto out; +	error = do_execve(filename, argv, envp, regs); +	putname(filename); +out: +	return error; +} + +asmlinkage unsigned long +sys_mmap2(unsigned long addr, size_t len, +	unsigned long prot, unsigned long flags, +	unsigned long fd, unsigned long pgoff) +{ +	struct file *file = NULL; +	int ret = -EBADF; + +	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +	if (!(flags & MAP_ANONYMOUS)) { +		file = fget(fd); +		if (!file) { +			printk(KERN_INFO "no fd in mmap\r\n"); +			goto out; +		} +	} + +	down_write(¤t->mm->mmap_sem); +	ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +	up_write(¤t->mm->mmap_sem); +	if (file) +		fput(file); +out: +	return ret; +} + +asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, +			unsigned long prot, unsigned long flags, +			unsigned long fd, off_t offset) +{ +	int err = -EINVAL; + +	if (offset & ~PAGE_MASK) { +		printk(KERN_INFO "no pagemask in mmap\r\n"); +		goto out; +	} + +	err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +out: +	return err; +} + +/* + * Do a system call from kernel instead of calling sys_execve so we + * end up with proper pt_regs. + */ +int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +{ +	register const char *__a __asm__("r5") = filename; +	register const void *__b __asm__("r6") = argv; +	register const void *__c __asm__("r7") = envp; +	register unsigned long __syscall __asm__("r12") = __NR_execve; +	register unsigned long __ret __asm__("r3"); +	__asm__ __volatile__ ("brki r14, 0x8" +			: "=r" (__ret), "=r" (__syscall) +			: "1" (__syscall), "r" (__a), "r" (__b), "r" (__c) +			: "r4", "r8", "r9", +			"r10", "r11", "r14", "cc", "memory"); +	return __ret; +} | 
