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

📄 vpe.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {		if (v->__start == 0) {			printk(KERN_WARNING "VPE loader: program does not contain "			       "a __start symbol\n");			return -ENOEXEC;		}		if (v->shared_ptr == NULL)			printk(KERN_WARNING "VPE loader: "			       "program does not contain vpe_shared symbol.\n"			       " Unable to use AMVP (AP/SP) facilities.\n");	}	printk(" elf loaded\n");	return 0;}__attribute_used__ void dump_vpe(struct vpe * v){	struct tc *t;	settc(v->minor);	printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol());	printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0());	list_for_each_entry(t, &vpecontrol.tc_list, list)		dump_tc(t);}static void cleanup_tc(struct tc *tc){	int tmp;	/* Put MVPE's into 'configuration state' */	set_c0_mvpcontrol(MVPCONTROL_VPC);	settc(tc->index);	tmp = read_tc_c0_tcstatus();	/* mark not allocated and not dynamically allocatable */	tmp &= ~(TCSTATUS_A | TCSTATUS_DA);	tmp |= TCSTATUS_IXMT;	/* interrupt exempt */	write_tc_c0_tcstatus(tmp);	write_tc_c0_tchalt(TCHALT_H);	/* bind it to anything other than VPE1 */	write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE	clear_c0_mvpcontrol(MVPCONTROL_VPC);}static int getcwd(char *buff, int size){	mm_segment_t old_fs;	int ret;	old_fs = get_fs();	set_fs(KERNEL_DS);	ret = sys_getcwd(buff,size);	set_fs(old_fs);	return ret;}/* checks VPE is unused and gets ready to load program  */static int vpe_open(struct inode *inode, struct file *filp){	int minor, ret;	struct vpe *v;	struct vpe_notifications *not;	/* assume only 1 device at the mo. */	if ((minor = iminor(inode)) != 1) {		printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");		return -ENODEV;	}	if ((v = get_vpe(minor)) == NULL) {		printk(KERN_WARNING "VPE loader: unable to get vpe\n");		return -ENODEV;	}	if (v->state != VPE_STATE_UNUSED) {		dvpe();		printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");		dump_tc(get_tc(minor));		list_for_each_entry(not, &v->notify, list) {			not->stop(minor);		}		release_progmem(v->load_addr);		cleanup_tc(get_tc(minor));	}	// allocate it so when we get write ops we know it's expected.	v->state = VPE_STATE_INUSE;	/* this of-course trashes what was there before... */	v->pbuffer = vmalloc(P_SIZE);	v->plen = P_SIZE;	v->load_addr = NULL;	v->len = 0;	v->uid = filp->f_uid;	v->gid = filp->f_gid;#ifdef CONFIG_MIPS_APSP_KSPD	/* get kspd to tell us when a syscall_exit happens */	if (!kspd_events_reqd) {		kspd_notify(&kspd_events);		kspd_events_reqd++;	}#endif	v->cwd[0] = 0;	ret = getcwd(v->cwd, VPE_PATH_MAX);	if (ret < 0)		printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);	v->shared_ptr = NULL;	v->__start = 0;	return 0;}static int vpe_release(struct inode *inode, struct file *filp){	int minor, ret = 0;	struct vpe *v;	Elf_Ehdr *hdr;	minor = iminor(inode);	if ((v = get_vpe(minor)) == NULL)		return -ENODEV;	// simple case of fire and forget, so tell the VPE to run...	hdr = (Elf_Ehdr *) v->pbuffer;	if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) {		if (vpe_elfload(v) >= 0)			vpe_run(v);		else { 			printk(KERN_WARNING "VPE loader: ELF load failed.\n");			ret = -ENOEXEC;		}	} else { 		printk(KERN_WARNING "VPE loader: only elf files are supported\n");		ret = -ENOEXEC;	}	/* It's good to be able to run the SP and if it chokes have a look at	   the /dev/rt?. But if we reset the pointer to the shared struct we	   loose what has happened. So perhaps if garbage is sent to the vpe	   device, use it as a trigger for the reset. Hopefully a nice	   executable will be along shortly. */	if (ret < 0)		v->shared_ptr = NULL;	// cleanup any temp buffers	if (v->pbuffer)		vfree(v->pbuffer);	v->plen = 0;	return ret;}static ssize_t vpe_write(struct file *file, const char __user * buffer,			 size_t count, loff_t * ppos){	int minor;	size_t ret = count;	struct vpe *v;	minor = iminor(file->f_dentry->d_inode);	if ((v = get_vpe(minor)) == NULL)		return -ENODEV;	if (v->pbuffer == NULL) {		printk(KERN_ERR "VPE loader: no buffer for program\n");		return -ENOMEM;	}	if ((count + v->len) > v->plen) {		printk(KERN_WARNING		       "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");		return -ENOMEM;	}	count -= copy_from_user(v->pbuffer + v->len, buffer, count);	if (!count)		return -EFAULT;	v->len += count;	return ret;}static struct file_operations vpe_fops = {	.owner = THIS_MODULE,	.open = vpe_open,	.release = vpe_release,	.write = vpe_write};/* module wrapper entry points *//* give me a vpe */vpe_handle vpe_alloc(void){	int i;	struct vpe *v;	/* find a vpe */	for (i = 1; i < MAX_VPES; i++) {		if ((v = get_vpe(i)) != NULL) {			v->state = VPE_STATE_INUSE;			return v;		}	}	return NULL;}EXPORT_SYMBOL(vpe_alloc);/* start running from here */int vpe_start(vpe_handle vpe, unsigned long start){	struct vpe *v = vpe;	v->__start = start;	return vpe_run(v);}EXPORT_SYMBOL(vpe_start);/* halt it for now */int vpe_stop(vpe_handle vpe){	struct vpe *v = vpe;	struct tc *t;	unsigned int evpe_flags;	evpe_flags = dvpe();	if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {		settc(t->index);		write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);	}	evpe(evpe_flags);	return 0;}EXPORT_SYMBOL(vpe_stop);/* I've done with it thank you */int vpe_free(vpe_handle vpe){	struct vpe *v = vpe;	struct tc *t;	unsigned int evpe_flags;	if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {		return -ENOEXEC;	}	evpe_flags = dvpe();	/* Put MVPE's into 'configuration state' */	set_c0_mvpcontrol(MVPCONTROL_VPC);	settc(t->index);	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);	/* mark the TC unallocated and halt'ed */	write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);	write_tc_c0_tchalt(TCHALT_H);	v->state = VPE_STATE_UNUSED;	clear_c0_mvpcontrol(MVPCONTROL_VPC);	evpe(evpe_flags);	return 0;}EXPORT_SYMBOL(vpe_free);void *vpe_get_shared(int index){	struct vpe *v;	if ((v = get_vpe(index)) == NULL)		return NULL;	return v->shared_ptr;}EXPORT_SYMBOL(vpe_get_shared);int vpe_getuid(int index){	struct vpe *v;	if ((v = get_vpe(index)) == NULL)		return -1;	return v->uid;}EXPORT_SYMBOL(vpe_getuid);int vpe_getgid(int index){	struct vpe *v;	if ((v = get_vpe(index)) == NULL)		return -1;	return v->gid;}EXPORT_SYMBOL(vpe_getgid);int vpe_notify(int index, struct vpe_notifications *notify){	struct vpe *v;	if ((v = get_vpe(index)) == NULL)		return -1;	list_add(&notify->list, &v->notify);	return 0;}EXPORT_SYMBOL(vpe_notify);char *vpe_getcwd(int index){	struct vpe *v;	if ((v = get_vpe(index)) == NULL)		return NULL;	return v->cwd;}EXPORT_SYMBOL(vpe_getcwd);#ifdef CONFIG_MIPS_APSP_KSPDstatic void kspd_sp_exit( int sp_id){	cleanup_tc(get_tc(sp_id));}#endifstatic int __init vpe_module_init(void){	struct vpe *v = NULL;	struct tc *t;	unsigned long val;	int i;	if (!cpu_has_mipsmt) {		printk("VPE loader: not a MIPS MT capable processor\n");		return -ENODEV;	}	major = register_chrdev(0, module_name, &vpe_fops);	if (major < 0) {		printk("VPE loader: unable to register character device\n");		return major;	}	dmt();	dvpe();	/* Put MVPE's into 'configuration state' */	set_c0_mvpcontrol(MVPCONTROL_VPC);	/* dump_mtregs(); */	INIT_LIST_HEAD(&vpecontrol.vpe_list);	INIT_LIST_HEAD(&vpecontrol.tc_list);	val = read_c0_mvpconf0();	for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) {		t = alloc_tc(i);		/* VPE's */		if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) {			settc(i);			if ((v = alloc_vpe(i)) == NULL) {				printk(KERN_WARNING "VPE: unable to allocate VPE\n");				return -ENODEV;			}			/* add the tc to the list of this vpe's tc's. */			list_add(&t->tc, &v->tc);			/* deactivate all but vpe0 */			if (i != 0) {				unsigned long tmp = read_vpe_c0_vpeconf0();				tmp &= ~VPECONF0_VPA;				/* master VPE */				tmp |= VPECONF0_MVP;				write_vpe_c0_vpeconf0(tmp);			}			/* disable multi-threading with TC's */			write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);			if (i != 0) {				write_vpe_c0_status((read_c0_status() &						     ~(ST0_IM | ST0_IE | ST0_KSU))						    | ST0_CU0);				/*				 * Set config to be the same as vpe0,				 * particularly kseg0 coherency alg				 */				write_vpe_c0_config(read_c0_config());			}		}		/* TC's */		t->pvpe = v;	/* set the parent vpe */		if (i != 0) {			unsigned long tmp;			settc(i);			/* Any TC that is bound to VPE0 gets left as is - in case			   we are running SMTC on VPE0. A TC that is bound to any			   other VPE gets bound to VPE0, ideally I'd like to make			   it homeless but it doesn't appear to let me bind a TC			   to a non-existent VPE. Which is perfectly reasonable.			   The (un)bound state is visible to an EJTAG probe so may			   notify GDB...			*/			if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {				/* tc is bound >vpe0 */				write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);				t->pvpe = get_vpe(0);	/* set the parent vpe */			}			tmp = read_tc_c0_tcstatus();			/* mark not activated and not dynamically allocatable */			tmp &= ~(TCSTATUS_A | TCSTATUS_DA);			tmp |= TCSTATUS_IXMT;	/* interrupt exempt */			write_tc_c0_tcstatus(tmp);			write_tc_c0_tchalt(TCHALT_H);		}	}	/* release config state */	clear_c0_mvpcontrol(MVPCONTROL_VPC);#ifdef CONFIG_MIPS_APSP_KSPD	kspd_events.kspd_sp_exit = kspd_sp_exit;#endif	return 0;}static void __exit vpe_module_exit(void){	struct vpe *v, *n;	list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {		if (v->state != VPE_STATE_UNUSED) {			release_vpe(v);		}	}	unregister_chrdev(major, module_name);}module_init(vpe_module_init);module_exit(vpe_module_exit);MODULE_DESCRIPTION("MIPS VPE Loader");MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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