⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kspd.c

📁 linux 内核源代码
💻 C
字号:
/* * 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/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 = NULL;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 = 0;/* 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#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		0x8000extern 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 < (sizeof(open_flags_table) / sizeof(struct apsp_table));	     i++) {		if( (flags & open_flags_table[i].sp) ) {			ret |= open_flags_table[i].ap;		}	}	return ret;}static void sp_setfsuidgid( uid_t uid, gid_t gid){	current->fsuid = uid;	current->fsgid = gid;	key_fsuid_changed(current);	key_fsgid_changed(current);}/* * 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 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 priviledge of the user who loaded the	   SP program */	if (vpe_getuid(tclimit))		sp_setfsuidgid(vpe_getuid(tclimit), vpe_getgid(tclimit));	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 the 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))		sp_setfsuidgid( 0, 0);	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;		}	}}static int channel_open = 0;/* 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(&notify->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, &notify);	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");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -