diff options
Diffstat (limited to 'arch/mips/kernel/kspd.c')
| -rw-r--r-- | arch/mips/kernel/kspd.c | 423 | 
1 files changed, 0 insertions, 423 deletions
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c deleted file mode 100644 index 29811f04339..00000000000 --- a/arch/mips/kernel/kspd.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved. - * - *  This program is free software; you can distribute it and/or modify it - *  under the terms of the GNU General Public License (Version 2) as - *  published by the Free Software Foundation. - * - *  This program is distributed in the hope it will be useful, but WITHOUT - *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License - *  for more details. - * - *  You should have received a copy of the GNU General Public License along - *  with this program; if not, write to the Free Software Foundation, Inc., - *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/unistd.h> -#include <linux/file.h> -#include <linux/fdtable.h> -#include <linux/fs.h> -#include <linux/syscalls.h> -#include <linux/workqueue.h> -#include <linux/errno.h> -#include <linux/list.h> - -#include <asm/vpe.h> -#include <asm/rtlx.h> -#include <asm/kspd.h> - -static struct workqueue_struct *workqueue; -static struct work_struct work; - -extern unsigned long cpu_khz; - -struct mtsp_syscall { -	int cmd; -	unsigned char abi; -	unsigned char size; -}; - -struct mtsp_syscall_ret { -	int retval; -	int errno; -}; - -struct mtsp_syscall_generic { -	int arg0; -	int arg1; -	int arg2; -	int arg3; -	int arg4; -	int arg5; -	int arg6; -}; - -static struct list_head kspd_notifylist; -static int sp_stopping; - -/* these should match with those in the SDE kit */ -#define MTSP_SYSCALL_BASE	0 -#define MTSP_SYSCALL_EXIT	(MTSP_SYSCALL_BASE + 0) -#define MTSP_SYSCALL_OPEN	(MTSP_SYSCALL_BASE + 1) -#define MTSP_SYSCALL_READ	(MTSP_SYSCALL_BASE + 2) -#define MTSP_SYSCALL_WRITE	(MTSP_SYSCALL_BASE + 3) -#define MTSP_SYSCALL_CLOSE	(MTSP_SYSCALL_BASE + 4) -#define MTSP_SYSCALL_LSEEK32	(MTSP_SYSCALL_BASE + 5) -#define MTSP_SYSCALL_ISATTY	(MTSP_SYSCALL_BASE + 6) -#define MTSP_SYSCALL_GETTIME	(MTSP_SYSCALL_BASE + 7) -#define MTSP_SYSCALL_PIPEFREQ	(MTSP_SYSCALL_BASE + 8) -#define MTSP_SYSCALL_GETTOD	(MTSP_SYSCALL_BASE + 9) -#define MTSP_SYSCALL_IOCTL     (MTSP_SYSCALL_BASE + 10) - -#define MTSP_O_RDONLY		0x0000 -#define MTSP_O_WRONLY		0x0001 -#define MTSP_O_RDWR		0x0002 -#define MTSP_O_NONBLOCK		0x0004 -#define MTSP_O_APPEND		0x0008 -#define MTSP_O_SHLOCK		0x0010 -#define MTSP_O_EXLOCK		0x0020 -#define MTSP_O_ASYNC		0x0040 -/* XXX: check which of these is actually O_SYNC vs O_DSYNC */ -#define MTSP_O_FSYNC		O_SYNC -#define MTSP_O_NOFOLLOW		0x0100 -#define MTSP_O_SYNC		0x0080 -#define MTSP_O_CREAT		0x0200 -#define MTSP_O_TRUNC		0x0400 -#define MTSP_O_EXCL		0x0800 -#define MTSP_O_BINARY		0x8000 - -extern int tclimit; - -struct apsp_table  { -	int sp; -	int ap; -}; - -/* we might want to do the mode flags too */ -struct apsp_table open_flags_table[] = { -	{ MTSP_O_RDWR, O_RDWR }, -	{ MTSP_O_WRONLY, O_WRONLY }, -	{ MTSP_O_CREAT, O_CREAT }, -	{ MTSP_O_TRUNC, O_TRUNC }, -	{ MTSP_O_NONBLOCK, O_NONBLOCK }, -	{ MTSP_O_APPEND, O_APPEND }, -	{ MTSP_O_NOFOLLOW, O_NOFOLLOW } -}; - -struct apsp_table syscall_command_table[] = { -	{ MTSP_SYSCALL_OPEN, __NR_open }, -	{ MTSP_SYSCALL_CLOSE, __NR_close }, -	{ MTSP_SYSCALL_READ, __NR_read }, -	{ MTSP_SYSCALL_WRITE, __NR_write }, -	{ MTSP_SYSCALL_LSEEK32, __NR_lseek }, -	{ MTSP_SYSCALL_IOCTL, __NR_ioctl } -}; - -static int sp_syscall(int num, int arg0, int arg1, int arg2, int arg3) -{ -	register long int _num  __asm__("$2") = num; -	register long int _arg0  __asm__("$4") = arg0; -	register long int _arg1  __asm__("$5") = arg1; -	register long int _arg2  __asm__("$6") = arg2; -	register long int _arg3  __asm__("$7") = arg3; - -	mm_segment_t old_fs; - -	old_fs = get_fs(); - 	set_fs(KERNEL_DS); - -  	__asm__ __volatile__ ( - 	"	syscall					\n" - 	: "=r" (_num), "=r" (_arg3) - 	: "r" (_num), "r" (_arg0), "r" (_arg1), "r" (_arg2), "r" (_arg3)); - -	set_fs(old_fs); - -	/* $a3 is error flag */ -	if (_arg3) -		return -_num; - -	return _num; -} - -static int translate_syscall_command(int cmd) -{ -	int i; -	int ret = -1; - -	for (i = 0; i < ARRAY_SIZE(syscall_command_table); i++) { -		if ((cmd == syscall_command_table[i].sp)) -			return syscall_command_table[i].ap; -	} - -	return ret; -} - -static unsigned int translate_open_flags(int flags) -{ -	int i; -	unsigned int ret = 0; - -	for (i = 0; i < ARRAY_SIZE(open_flags_table); i++) { -		if( (flags & open_flags_table[i].sp) ) { -			ret |= open_flags_table[i].ap; -		} -	} - -	return ret; -} - - -static int sp_setfsuidgid(uid_t uid, gid_t gid) -{ -	struct cred *new; - -	new = prepare_creds(); -	if (!new) -		return -ENOMEM; - -	new->fsuid = uid; -	new->fsgid = gid; - -	commit_creds(new); - -	return 0; -} - -/* - * Expects a request to be on the sysio channel. Reads it.  Decides whether - * its a linux syscall and runs it, or whatever.  Puts the return code back - * into the request and sends the whole thing back. - */ -void sp_work_handle_request(void) -{ -	struct mtsp_syscall sc; -	struct mtsp_syscall_generic generic; -	struct mtsp_syscall_ret ret; -	struct kspd_notifications *n; -	unsigned long written; -	mm_segment_t old_fs; -	struct timeval tv; -	struct timezone tz; -	int err, cmd; - -	char *vcwd; -	int size; - -	ret.retval = -1; - -	old_fs = get_fs(); -	set_fs(KERNEL_DS); - -	if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall))) { -		set_fs(old_fs); -		printk(KERN_ERR "Expected request but nothing to read\n"); -		return; -	} - -	size = sc.size; - -	if (size) { -		if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size)) { -			set_fs(old_fs); -			printk(KERN_ERR "Expected request but nothing to read\n"); -			return; -		} -	} - -	/* Run the syscall at the privilege of the user who loaded the -	   SP program */ - -	if (vpe_getuid(tclimit)) { -		err = sp_setfsuidgid(vpe_getuid(tclimit), vpe_getgid(tclimit)); -		if (!err) -			pr_err("Change of creds failed\n"); -	} - -	switch (sc.cmd) { -	/* needs the flags argument translating from SDE kit to -	   linux */ - 	case MTSP_SYSCALL_PIPEFREQ: - 		ret.retval = cpu_khz * 1000; - 		ret.errno = 0; - 		break; - - 	case MTSP_SYSCALL_GETTOD: - 		memset(&tz, 0, sizeof(tz)); - 		if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv, -					     (int)&tz, 0, 0)) == 0) -			ret.retval = tv.tv_sec; -		break; - - 	case MTSP_SYSCALL_EXIT: -		list_for_each_entry(n, &kspd_notifylist, list) -			n->kspd_sp_exit(tclimit); -		sp_stopping = 1; - -		printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n", -		       generic.arg0); - 		break; - - 	case MTSP_SYSCALL_OPEN: - 		generic.arg1 = translate_open_flags(generic.arg1); - -		vcwd = vpe_getcwd(tclimit); - -		/* change to cwd of the process that loaded the SP program */ -		old_fs = get_fs(); -		set_fs(KERNEL_DS); -		sys_chdir(vcwd); -		set_fs(old_fs); - - 		sc.cmd = __NR_open; - -		/* fall through */ - -  	default: - 		if ((sc.cmd >= __NR_Linux) && -		    (sc.cmd <= (__NR_Linux +  __NR_Linux_syscalls)) ) -			cmd = sc.cmd; -		else -			cmd = translate_syscall_command(sc.cmd); - -		if (cmd >= 0) { -			ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1, -			                        generic.arg2, generic.arg3); -		} else - 			printk(KERN_WARNING -			       "KSPD: Unknown SP syscall number %d\n", sc.cmd); -		break; - 	} /* switch */ - -	if (vpe_getuid(tclimit)) { -		err = sp_setfsuidgid(0, 0); -		if (!err) -			pr_err("restoring old creds failed\n"); -	} - -	old_fs = get_fs(); -	set_fs(KERNEL_DS); -	written = rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(ret)); -	set_fs(old_fs); -	if (written < sizeof(ret)) -		printk("KSPD: sp_work_handle_request failed to send to SP\n"); -} - -static void sp_cleanup(void) -{ -	struct files_struct *files = current->files; -	int i, j; -	struct fdtable *fdt; - -	j = 0; - -	/* -	 * It is safe to dereference the fd table without RCU or -	 * ->file_lock -	 */ -	fdt = files_fdtable(files); -	for (;;) { -		unsigned long set; -		i = j * __NFDBITS; -		if (i >= fdt->max_fds) -			break; -		set = fdt->open_fds->fds_bits[j++]; -		while (set) { -			if (set & 1) { -				struct file * file = xchg(&fdt->fd[i], NULL); -				if (file) -					filp_close(file, files); -			} -			i++; -			set >>= 1; -		} -	} - -	/* Put daemon cwd back to root to avoid umount problems */ -	sys_chdir("/"); -} - -static int channel_open; - -/* the work handler */ -static void sp_work(struct work_struct *unused) -{ -	if (!channel_open) { -		if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0) { -			printk("KSPD: unable to open sp channel\n"); -			sp_stopping = 1; -		} else { -			channel_open++; -			printk(KERN_DEBUG "KSPD: SP channel opened\n"); -		} -	} else { -		/* wait for some data, allow it to sleep */ -		rtlx_read_poll(RTLX_CHANNEL_SYSIO, 1); - -		/* Check we haven't been woken because we are stopping */ -		if (!sp_stopping) -			sp_work_handle_request(); -	} - -	if (!sp_stopping) -		queue_work(workqueue, &work); -	else -		sp_cleanup(); -} - -static void startwork(int vpe) -{ -	sp_stopping = channel_open = 0; - -	if (workqueue == NULL) { -		if ((workqueue = create_singlethread_workqueue("kspd")) == NULL) { -			printk(KERN_ERR "unable to start kspd\n"); -			return; -		} - -		INIT_WORK(&work, sp_work); -	} - -	queue_work(workqueue, &work); -} - -static void stopwork(int vpe) -{ -	sp_stopping = 1; - -	printk(KERN_DEBUG "KSPD: SP stopping\n"); -} - -void kspd_notify(struct kspd_notifications *notify) -{ -	list_add(¬ify->list, &kspd_notifylist); -} - -static struct vpe_notifications notify; -static int kspd_module_init(void) -{ -	INIT_LIST_HEAD(&kspd_notifylist); - -	notify.start = startwork; -	notify.stop = stopwork; -	vpe_notify(tclimit, ¬ify); - -	return 0; -} - -static void kspd_module_exit(void) -{ - -} - -module_init(kspd_module_init); -module_exit(kspd_module_exit); - -MODULE_DESCRIPTION("MIPS KSPD"); -MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); -MODULE_LICENSE("GPL");  | 
