• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
3   *
4   *  This program is free software; you can distribute it and/or modify it
5   *  under the terms of the GNU General Public License (Version 2) as
6   *  published by the Free Software Foundation.
7   *
8   *  This program is distributed in the hope it will be useful, but WITHOUT
9   *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10   *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11   *  for more details.
12   *
13   *  You should have received a copy of the GNU General Public License along
14   *  with this program; if not, write to the Free Software Foundation, Inc.,
15   *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16   */
17  
18  /*
19   * VPE support module
20   *
21   * Provides support for loading a MIPS SP program on VPE1.
22   * The SP enviroment is rather simple, no tlb's.  It needs to be relocatable
23   * (or partially linked). You should initialise your stack in the startup
24   * code. This loader looks for the symbol __start and sets up
25   * execution to resume from there. The MIPS SDE kit contains suitable examples.
26   *
27   * To load and run, simply cat a SP 'program file' to /dev/vpe1.
28   * i.e cat spapp >/dev/vpe1.
29   */
30  #include <linux/kernel.h>
31  #include <linux/device.h>
32  #include <linux/module.h>
33  #include <linux/fs.h>
34  #include <linux/init.h>
35  #include <asm/uaccess.h>
36  #include <linux/slab.h>
37  #include <linux/list.h>
38  #include <linux/vmalloc.h>
39  #include <linux/elf.h>
40  #include <linux/seq_file.h>
41  #include <linux/smp_lock.h>
42  #include <linux/syscalls.h>
43  #include <linux/moduleloader.h>
44  #include <linux/interrupt.h>
45  #include <linux/poll.h>
46  #include <linux/bootmem.h>
47  #include <asm/mipsregs.h>
48  #include <asm/mipsmtregs.h>
49  #include <asm/cacheflush.h>
50  #include <asm/atomic.h>
51  #include <asm/cpu.h>
52  #include <asm/mips_mt.h>
53  #include <asm/processor.h>
54  #include <asm/system.h>
55  #include <asm/vpe.h>
56  #include <asm/kspd.h>
57  
58  typedef void *vpe_handle;
59  
60  #ifndef ARCH_SHF_SMALL
61  #define ARCH_SHF_SMALL 0
62  #endif
63  
64  /* If this is set, the section belongs in the init part of the module */
65  #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
66  
67  /*
68   * The number of TCs and VPEs physically available on the core
69   */
70  static int hw_tcs, hw_vpes;
71  static char module_name[] = "vpe";
72  static int major;
73  static const int minor = 1;	/* fixed for now  */
74  
75  #ifdef CONFIG_MIPS_APSP_KSPD
76   static struct kspd_notifications kspd_events;
77  static int kspd_events_reqd = 0;
78  #endif
79  
80  /* grab the likely amount of memory we will need. */
81  #ifdef CONFIG_MIPS_VPE_LOADER_TOM
82  #define P_SIZE (2 * 1024 * 1024)
83  #else
84  /* add an overhead to the max kmalloc size for non-striped symbols/etc */
85  #define P_SIZE (256 * 1024)
86  #endif
87  
88  extern unsigned long physical_memsize;
89  
90  #define MAX_VPES 16
91  #define VPE_PATH_MAX 256
92  
93  enum vpe_state {
94  	VPE_STATE_UNUSED = 0,
95  	VPE_STATE_INUSE,
96  	VPE_STATE_RUNNING
97  };
98  
99  enum tc_state {
100  	TC_STATE_UNUSED = 0,
101  	TC_STATE_INUSE,
102  	TC_STATE_RUNNING,
103  	TC_STATE_DYNAMIC
104  };
105  
106  struct vpe {
107  	enum vpe_state state;
108  
109  	/* (device) minor associated with this vpe */
110  	int minor;
111  
112  	/* elfloader stuff */
113  	void *load_addr;
114  	unsigned long len;
115  	char *pbuffer;
116  	unsigned long plen;
117  	unsigned int uid, gid;
118  	char cwd[VPE_PATH_MAX];
119  
120  	unsigned long __start;
121  
122  	/* tc's associated with this vpe */
123  	struct list_head tc;
124  
125  	/* The list of vpe's */
126  	struct list_head list;
127  
128  	/* shared symbol address */
129  	void *shared_ptr;
130  
131  	/* the list of who wants to know when something major happens */
132  	struct list_head notify;
133  
134  	unsigned int ntcs;
135  };
136  
137  struct tc {
138  	enum tc_state state;
139  	int index;
140  
141  	struct vpe *pvpe;	/* parent VPE */
142  	struct list_head tc;	/* The list of TC's with this VPE */
143  	struct list_head list;	/* The global list of tc's */
144  };
145  
146  struct {
147  	/* Virtual processing elements */
148  	struct list_head vpe_list;
149  
150  	/* Thread contexts */
151  	struct list_head tc_list;
152  } vpecontrol = {
153  	.vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list),
154  	.tc_list = LIST_HEAD_INIT(vpecontrol.tc_list)
155  };
156  
157  static void release_progmem(void *ptr);
158  extern void save_gp_address(unsigned int secbase, unsigned int rel);
159  
160  /* get the vpe associated with this minor */
get_vpe(int minor)161  struct vpe *get_vpe(int minor)
162  {
163  	struct vpe *v;
164  
165  	if (!cpu_has_mipsmt)
166  		return NULL;
167  
168  	list_for_each_entry(v, &vpecontrol.vpe_list, list) {
169  		if (v->minor == minor)
170  			return v;
171  	}
172  
173  	return NULL;
174  }
175  
176  /* get the vpe associated with this minor */
get_tc(int index)177  struct tc *get_tc(int index)
178  {
179  	struct tc *t;
180  
181  	list_for_each_entry(t, &vpecontrol.tc_list, list) {
182  		if (t->index == index)
183  			return t;
184  	}
185  
186  	return NULL;
187  }
188  
get_tc_unused(void)189  struct tc *get_tc_unused(void)
190  {
191  	struct tc *t;
192  
193  	list_for_each_entry(t, &vpecontrol.tc_list, list) {
194  		if (t->state == TC_STATE_UNUSED)
195  			return t;
196  	}
197  
198  	return NULL;
199  }
200  
201  /* allocate a vpe and associate it with this minor (or index) */
alloc_vpe(int minor)202  struct vpe *alloc_vpe(int minor)
203  {
204  	struct vpe *v;
205  
206  	if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) {
207  		return NULL;
208  	}
209  
210  	INIT_LIST_HEAD(&v->tc);
211  	list_add_tail(&v->list, &vpecontrol.vpe_list);
212  
213  	INIT_LIST_HEAD(&v->notify);
214  	v->minor = minor;
215  	return v;
216  }
217  
218  /* allocate a tc. At startup only tc0 is running, all other can be halted. */
alloc_tc(int index)219  struct tc *alloc_tc(int index)
220  {
221  	struct tc *tc;
222  
223  	if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
224  		goto out;
225  
226  	INIT_LIST_HEAD(&tc->tc);
227  	tc->index = index;
228  	list_add_tail(&tc->list, &vpecontrol.tc_list);
229  
230  out:
231  	return tc;
232  }
233  
234  /* clean up and free everything */
release_vpe(struct vpe * v)235  void release_vpe(struct vpe *v)
236  {
237  	list_del(&v->list);
238  	if (v->load_addr)
239  		release_progmem(v);
240  	kfree(v);
241  }
242  
dump_mtregs(void)243  void dump_mtregs(void)
244  {
245  	unsigned long val;
246  
247  	val = read_c0_config3();
248  	printk("config3 0x%lx MT %ld\n", val,
249  	       (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
250  
251  	val = read_c0_mvpcontrol();
252  	printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
253  	       (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
254  	       (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
255  	       (val & MVPCONTROL_EVP));
256  
257  	val = read_c0_mvpconf0();
258  	printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
259  	       (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
260  	       val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
261  }
262  
263  /* Find some VPE program space  */
alloc_progmem(unsigned long len)264  static void *alloc_progmem(unsigned long len)
265  {
266  	void *addr;
267  
268  #ifdef CONFIG_MIPS_VPE_LOADER_TOM
269  	/*
270  	 * This means you must tell Linux to use less memory than you
271  	 * physically have, for example by passing a mem= boot argument.
272  	 */
273  	addr = pfn_to_kaddr(max_low_pfn);
274  	memset(addr, 0, len);
275  #else
276  	/* simple grab some mem for now */
277  	addr = kzalloc(len, GFP_KERNEL);
278  #endif
279  
280  	return addr;
281  }
282  
release_progmem(void * ptr)283  static void release_progmem(void *ptr)
284  {
285  #ifndef CONFIG_MIPS_VPE_LOADER_TOM
286  	kfree(ptr);
287  #endif
288  }
289  
290  /* Update size with this section: return offset. */
get_offset(unsigned long * size,Elf_Shdr * sechdr)291  static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
292  {
293  	long ret;
294  
295  	ret = ALIGN(*size, sechdr->sh_addralign ? : 1);
296  	*size = ret + sechdr->sh_size;
297  	return ret;
298  }
299  
300  /* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
301     might -- code, read-only data, read-write data, small data.  Tally
302     sizes, and place the offsets into sh_entsize fields: high bit means it
303     belongs in init. */
layout_sections(struct module * mod,const Elf_Ehdr * hdr,Elf_Shdr * sechdrs,const char * secstrings)304  static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
305  			    Elf_Shdr * sechdrs, const char *secstrings)
306  {
307  	static unsigned long const masks[][2] = {
308  		/* NOTE: all executable code must be the first section
309  		 * in this array; otherwise modify the text_size
310  		 * finder in the two loops below */
311  		{SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL},
312  		{SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL},
313  		{SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL},
314  		{ARCH_SHF_SMALL | SHF_ALLOC, 0}
315  	};
316  	unsigned int m, i;
317  
318  	for (i = 0; i < hdr->e_shnum; i++)
319  		sechdrs[i].sh_entsize = ~0UL;
320  
321  	for (m = 0; m < ARRAY_SIZE(masks); ++m) {
322  		for (i = 0; i < hdr->e_shnum; ++i) {
323  			Elf_Shdr *s = &sechdrs[i];
324  
325  			//  || strncmp(secstrings + s->sh_name, ".init", 5) == 0)
326  			if ((s->sh_flags & masks[m][0]) != masks[m][0]
327  			    || (s->sh_flags & masks[m][1])
328  			    || s->sh_entsize != ~0UL)
329  				continue;
330  			s->sh_entsize = get_offset(&mod->core_size, s);
331  		}
332  
333  		if (m == 0)
334  			mod->core_text_size = mod->core_size;
335  
336  	}
337  }
338  
339  
340  /* from module-elf32.c, but subverted a little */
341  
342  struct mips_hi16 {
343  	struct mips_hi16 *next;
344  	Elf32_Addr *addr;
345  	Elf32_Addr value;
346  };
347  
348  static struct mips_hi16 *mips_hi16_list;
349  static unsigned int gp_offs, gp_addr;
350  
apply_r_mips_none(struct module * me,uint32_t * location,Elf32_Addr v)351  static int apply_r_mips_none(struct module *me, uint32_t *location,
352  			     Elf32_Addr v)
353  {
354  	return 0;
355  }
356  
apply_r_mips_gprel16(struct module * me,uint32_t * location,Elf32_Addr v)357  static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
358  				Elf32_Addr v)
359  {
360  	int rel;
361  
362  	if( !(*location & 0xffff) ) {
363  		rel = (int)v - gp_addr;
364  	}
365  	else {
366  		/* .sbss + gp(relative) + offset */
367  		/* kludge! */
368  		rel =  (int)(short)((int)v + gp_offs +
369  				    (int)(short)(*location & 0xffff) - gp_addr);
370  	}
371  
372  	if( (rel > 32768) || (rel < -32768) ) {
373  		printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
374  		       "relative address 0x%x out of range of gp register\n",
375  		       rel);
376  		return -ENOEXEC;
377  	}
378  
379  	*location = (*location & 0xffff0000) | (rel & 0xffff);
380  
381  	return 0;
382  }
383  
apply_r_mips_pc16(struct module * me,uint32_t * location,Elf32_Addr v)384  static int apply_r_mips_pc16(struct module *me, uint32_t *location,
385  			     Elf32_Addr v)
386  {
387  	int rel;
388  	rel = (((unsigned int)v - (unsigned int)location));
389  	rel >>= 2;		// because the offset is in _instructions_ not bytes.
390  	rel -= 1;		// and one instruction less due to the branch delay slot.
391  
392  	if( (rel > 32768) || (rel < -32768) ) {
393  		printk(KERN_DEBUG "VPE loader: "
394   		       "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
395  		return -ENOEXEC;
396  	}
397  
398  	*location = (*location & 0xffff0000) | (rel & 0xffff);
399  
400  	return 0;
401  }
402  
apply_r_mips_32(struct module * me,uint32_t * location,Elf32_Addr v)403  static int apply_r_mips_32(struct module *me, uint32_t *location,
404  			   Elf32_Addr v)
405  {
406  	*location += v;
407  
408  	return 0;
409  }
410  
apply_r_mips_26(struct module * me,uint32_t * location,Elf32_Addr v)411  static int apply_r_mips_26(struct module *me, uint32_t *location,
412  			   Elf32_Addr v)
413  {
414  	if (v % 4) {
415  		printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
416  		       " unaligned relocation\n");
417  		return -ENOEXEC;
418  	}
419  
420  /*
421   * Not desperately convinced this is a good check of an overflow condition
422   * anyway. But it gets in the way of handling undefined weak symbols which
423   * we want to set to zero.
424   * if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
425   * printk(KERN_ERR
426   * "module %s: relocation overflow\n",
427   * me->name);
428   * return -ENOEXEC;
429   * }
430   */
431  
432  	*location = (*location & ~0x03ffffff) |
433  		((*location + (v >> 2)) & 0x03ffffff);
434  	return 0;
435  }
436  
apply_r_mips_hi16(struct module * me,uint32_t * location,Elf32_Addr v)437  static int apply_r_mips_hi16(struct module *me, uint32_t *location,
438  			     Elf32_Addr v)
439  {
440  	struct mips_hi16 *n;
441  
442  	/*
443  	 * We cannot relocate this one now because we don't know the value of
444  	 * the carry we need to add.  Save the information, and let LO16 do the
445  	 * actual relocation.
446  	 */
447  	n = kmalloc(sizeof *n, GFP_KERNEL);
448  	if (!n)
449  		return -ENOMEM;
450  
451  	n->addr = location;
452  	n->value = v;
453  	n->next = mips_hi16_list;
454  	mips_hi16_list = n;
455  
456  	return 0;
457  }
458  
apply_r_mips_lo16(struct module * me,uint32_t * location,Elf32_Addr v)459  static int apply_r_mips_lo16(struct module *me, uint32_t *location,
460  			     Elf32_Addr v)
461  {
462  	unsigned long insnlo = *location;
463  	Elf32_Addr val, vallo;
464  
465  	/* Sign extend the addend we extract from the lo insn.  */
466  	vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
467  
468  	if (mips_hi16_list != NULL) {
469  		struct mips_hi16 *l;
470  
471  		l = mips_hi16_list;
472  		while (l != NULL) {
473  			struct mips_hi16 *next;
474  			unsigned long insn;
475  
476  			/*
477  			 * The value for the HI16 had best be the same.
478  			 */
479   			if (v != l->value) {
480  				printk(KERN_DEBUG "VPE loader: "
481  				       "apply_r_mips_lo16/hi16: \t"
482  				       "inconsistent value information\n");
483  				return -ENOEXEC;
484  			}
485  
486  			/*
487  			 * Do the HI16 relocation.  Note that we actually don't
488  			 * need to know anything about the LO16 itself, except
489  			 * where to find the low 16 bits of the addend needed
490  			 * by the LO16.
491  			 */
492  			insn = *l->addr;
493  			val = ((insn & 0xffff) << 16) + vallo;
494  			val += v;
495  
496  			/*
497  			 * Account for the sign extension that will happen in
498  			 * the low bits.
499  			 */
500  			val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
501  
502  			insn = (insn & ~0xffff) | val;
503  			*l->addr = insn;
504  
505  			next = l->next;
506  			kfree(l);
507  			l = next;
508  		}
509  
510  		mips_hi16_list = NULL;
511  	}
512  
513  	/*
514  	 * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
515  	 */
516  	val = v + vallo;
517  	insnlo = (insnlo & ~0xffff) | (val & 0xffff);
518  	*location = insnlo;
519  
520  	return 0;
521  }
522  
523  static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
524  				Elf32_Addr v) = {
525  	[R_MIPS_NONE]	= apply_r_mips_none,
526  	[R_MIPS_32]	= apply_r_mips_32,
527  	[R_MIPS_26]	= apply_r_mips_26,
528  	[R_MIPS_HI16]	= apply_r_mips_hi16,
529  	[R_MIPS_LO16]	= apply_r_mips_lo16,
530  	[R_MIPS_GPREL16] = apply_r_mips_gprel16,
531  	[R_MIPS_PC16] = apply_r_mips_pc16
532  };
533  
534  static char *rstrs[] = {
535  	[R_MIPS_NONE]	= "MIPS_NONE",
536  	[R_MIPS_32]	= "MIPS_32",
537  	[R_MIPS_26]	= "MIPS_26",
538  	[R_MIPS_HI16]	= "MIPS_HI16",
539  	[R_MIPS_LO16]	= "MIPS_LO16",
540  	[R_MIPS_GPREL16] = "MIPS_GPREL16",
541  	[R_MIPS_PC16] = "MIPS_PC16"
542  };
543  
apply_relocations(Elf32_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)544  int apply_relocations(Elf32_Shdr *sechdrs,
545  		      const char *strtab,
546  		      unsigned int symindex,
547  		      unsigned int relsec,
548  		      struct module *me)
549  {
550  	Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
551  	Elf32_Sym *sym;
552  	uint32_t *location;
553  	unsigned int i;
554  	Elf32_Addr v;
555  	int res;
556  
557  	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
558  		Elf32_Word r_info = rel[i].r_info;
559  
560  		/* This is where to make the change */
561  		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
562  			+ rel[i].r_offset;
563  		/* This is the symbol it is referring to */
564  		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
565  			+ ELF32_R_SYM(r_info);
566  
567  		if (!sym->st_value) {
568  			printk(KERN_DEBUG "%s: undefined weak symbol %s\n",
569  			       me->name, strtab + sym->st_name);
570  			/* just print the warning, dont barf */
571  		}
572  
573  		v = sym->st_value;
574  
575  		res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
576  		if( res ) {
577  			char *r = rstrs[ELF32_R_TYPE(r_info)];
578  		    	printk(KERN_WARNING "VPE loader: .text+0x%x "
579  			       "relocation type %s for symbol \"%s\" failed\n",
580  			       rel[i].r_offset, r ? r : "UNKNOWN",
581  			       strtab + sym->st_name);
582  			return res;
583  		}
584  	}
585  
586  	return 0;
587  }
588  
save_gp_address(unsigned int secbase,unsigned int rel)589  void save_gp_address(unsigned int secbase, unsigned int rel)
590  {
591  	gp_addr = secbase + rel;
592  	gp_offs = gp_addr - (secbase & 0xffff0000);
593  }
594  /* end module-elf32.c */
595  
596  
597  
598  /* Change all symbols so that sh_value encodes the pointer directly. */
simplify_symbols(Elf_Shdr * sechdrs,unsigned int symindex,const char * strtab,const char * secstrings,unsigned int nsecs,struct module * mod)599  static void simplify_symbols(Elf_Shdr * sechdrs,
600  			    unsigned int symindex,
601  			    const char *strtab,
602  			    const char *secstrings,
603  			    unsigned int nsecs, struct module *mod)
604  {
605  	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
606  	unsigned long secbase, bssbase = 0;
607  	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
608  	int size;
609  
610  	/* find the .bss section for COMMON symbols */
611  	for (i = 0; i < nsecs; i++) {
612  		if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
613  			bssbase = sechdrs[i].sh_addr;
614  			break;
615  		}
616  	}
617  
618  	for (i = 1; i < n; i++) {
619  		switch (sym[i].st_shndx) {
620  		case SHN_COMMON:
621  			/* Allocate space for the symbol in the .bss section.
622  			   st_value is currently size.
623  			   We want it to have the address of the symbol. */
624  
625  			size = sym[i].st_value;
626  			sym[i].st_value = bssbase;
627  
628  			bssbase += size;
629  			break;
630  
631  		case SHN_ABS:
632  			/* Don't need to do anything */
633  			break;
634  
635  		case SHN_UNDEF:
636  			/* ret = -ENOENT; */
637  			break;
638  
639  		case SHN_MIPS_SCOMMON:
640  			printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON "
641  			       "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
642  			       sym[i].st_shndx);
643  			// .sbss section
644  			break;
645  
646  		default:
647  			secbase = sechdrs[sym[i].st_shndx].sh_addr;
648  
649  			if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) {
650  				save_gp_address(secbase, sym[i].st_value);
651  			}
652  
653  			sym[i].st_value += secbase;
654  			break;
655  		}
656  	}
657  }
658  
659  #ifdef DEBUG_ELFLOADER
dump_elfsymbols(Elf_Shdr * sechdrs,unsigned int symindex,const char * strtab,struct module * mod)660  static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
661  			    const char *strtab, struct module *mod)
662  {
663  	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
664  	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
665  
666  	printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n);
667  	for (i = 1; i < n; i++) {
668  		printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i,
669  		       strtab + sym[i].st_name, sym[i].st_value);
670  	}
671  }
672  #endif
673  
674  /* We are prepared so configure and start the VPE... */
vpe_run(struct vpe * v)675  static int vpe_run(struct vpe * v)
676  {
677  	unsigned long flags, val, dmt_flag;
678  	struct vpe_notifications *n;
679  	unsigned int vpeflags;
680  	struct tc *t;
681  
682  	/* check we are the Master VPE */
683  	local_irq_save(flags);
684  	val = read_c0_vpeconf0();
685  	if (!(val & VPECONF0_MVP)) {
686  		printk(KERN_WARNING
687  		       "VPE loader: only Master VPE's are allowed to configure MT\n");
688  		local_irq_restore(flags);
689  
690  		return -1;
691  	}
692  
693  	dmt_flag = dmt();
694  	vpeflags = dvpe();
695  
696  	if (!list_empty(&v->tc)) {
697  		if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
698  			evpe(vpeflags);
699  			emt(dmt_flag);
700  			local_irq_restore(flags);
701  
702  			printk(KERN_WARNING
703  			       "VPE loader: TC %d is already in use.\n",
704                                 t->index);
705  			return -ENOEXEC;
706  		}
707  	} else {
708  		evpe(vpeflags);
709  		emt(dmt_flag);
710  		local_irq_restore(flags);
711  
712  		printk(KERN_WARNING
713  		       "VPE loader: No TC's associated with VPE %d\n",
714  		       v->minor);
715  
716  		return -ENOEXEC;
717  	}
718  
719  	/* Put MVPE's into 'configuration state' */
720  	set_c0_mvpcontrol(MVPCONTROL_VPC);
721  
722  	settc(t->index);
723  
724  	/* should check it is halted, and not activated */
725  	if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
726  		evpe(vpeflags);
727  		emt(dmt_flag);
728  		local_irq_restore(flags);
729  
730  		printk(KERN_WARNING "VPE loader: TC %d is already active!\n",
731  		       t->index);
732  
733  		return -ENOEXEC;
734  	}
735  
736  	/* Write the address we want it to start running from in the TCPC register. */
737  	write_tc_c0_tcrestart((unsigned long)v->__start);
738  	write_tc_c0_tccontext((unsigned long)0);
739  
740  	/*
741  	 * Mark the TC as activated, not interrupt exempt and not dynamically
742  	 * allocatable
743  	 */
744  	val = read_tc_c0_tcstatus();
745  	val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
746  	write_tc_c0_tcstatus(val);
747  
748  	write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
749  
750  	/*
751  	 * The sde-kit passes 'memsize' to __start in $a3, so set something
752  	 * here...  Or set $a3 to zero and define DFLT_STACK_SIZE and
753  	 * DFLT_HEAP_SIZE when you compile your program
754  	 */
755  	mttgpr(6, v->ntcs);
756  	mttgpr(7, physical_memsize);
757  
758  	/* set up VPE1 */
759  	/*
760  	 * bind the TC to VPE 1 as late as possible so we only have the final
761  	 * VPE registers to set up, and so an EJTAG probe can trigger on it
762  	 */
763  	write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
764  
765  	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
766  
767  	back_to_back_c0_hazard();
768  
769  	/* Set up the XTC bit in vpeconf0 to point at our tc */
770  	write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
771  	                      | (t->index << VPECONF0_XTC_SHIFT));
772  
773  	back_to_back_c0_hazard();
774  
775  	/* enable this VPE */
776  	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
777  
778  	/* clear out any left overs from a previous program */
779  	write_vpe_c0_status(0);
780  	write_vpe_c0_cause(0);
781  
782  	/* take system out of configuration state */
783  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
784  
785  	/*
786  	 * SMTC/SMVP kernels manage VPE enable independently,
787  	 * but uniprocessor kernels need to turn it on, even
788  	 * if that wasn't the pre-dvpe() state.
789  	 */
790  #ifdef CONFIG_SMP
791  	evpe(vpeflags);
792  #else
793  	evpe(EVPE_ENABLE);
794  #endif
795  	emt(dmt_flag);
796  	local_irq_restore(flags);
797  
798  	list_for_each_entry(n, &v->notify, list)
799  		n->start(minor);
800  
801  	return 0;
802  }
803  
find_vpe_symbols(struct vpe * v,Elf_Shdr * sechdrs,unsigned int symindex,const char * strtab,struct module * mod)804  static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
805  				      unsigned int symindex, const char *strtab,
806  				      struct module *mod)
807  {
808  	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
809  	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
810  
811  	for (i = 1; i < n; i++) {
812  		if (strcmp(strtab + sym[i].st_name, "__start") == 0) {
813  			v->__start = sym[i].st_value;
814  		}
815  
816  		if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) {
817  			v->shared_ptr = (void *)sym[i].st_value;
818  		}
819  	}
820  
821  	if ( (v->__start == 0) || (v->shared_ptr == NULL))
822  		return -1;
823  
824  	return 0;
825  }
826  
827  /*
828   * Allocates a VPE with some program code space(the load address), copies the
829   * contents of the program (p)buffer performing relocatations/etc, free's it
830   * when finished.
831   */
vpe_elfload(struct vpe * v)832  static int vpe_elfload(struct vpe * v)
833  {
834  	Elf_Ehdr *hdr;
835  	Elf_Shdr *sechdrs;
836  	long err = 0;
837  	char *secstrings, *strtab = NULL;
838  	unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
839  	struct module mod;	// so we can re-use the relocations code
840  
841  	memset(&mod, 0, sizeof(struct module));
842  	strcpy(mod.name, "VPE loader");
843  
844  	hdr = (Elf_Ehdr *) v->pbuffer;
845  	len = v->plen;
846  
847  	/* Sanity checks against insmoding binaries or wrong arch,
848  	   weird elf version */
849  	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
850  	    || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
851  	    || !elf_check_arch(hdr)
852  	    || hdr->e_shentsize != sizeof(*sechdrs)) {
853  		printk(KERN_WARNING
854  		       "VPE loader: program wrong arch or weird elf version\n");
855  
856  		return -ENOEXEC;
857  	}
858  
859  	if (hdr->e_type == ET_REL)
860  		relocate = 1;
861  
862  	if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
863  		printk(KERN_ERR "VPE loader: program length %u truncated\n",
864  		       len);
865  
866  		return -ENOEXEC;
867  	}
868  
869  	/* Convenience variables */
870  	sechdrs = (void *)hdr + hdr->e_shoff;
871  	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
872  	sechdrs[0].sh_addr = 0;
873  
874  	/* And these should exist, but gcc whinges if we don't init them */
875  	symindex = strindex = 0;
876  
877  	if (relocate) {
878  		for (i = 1; i < hdr->e_shnum; i++) {
879  			if (sechdrs[i].sh_type != SHT_NOBITS
880  			    && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
881  				printk(KERN_ERR "VPE program length %u truncated\n",
882  				       len);
883  				return -ENOEXEC;
884  			}
885  
886  			/* Mark all sections sh_addr with their address in the
887  			   temporary image. */
888  			sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
889  
890  			/* Internal symbols and strings. */
891  			if (sechdrs[i].sh_type == SHT_SYMTAB) {
892  				symindex = i;
893  				strindex = sechdrs[i].sh_link;
894  				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
895  			}
896  		}
897  		layout_sections(&mod, hdr, sechdrs, secstrings);
898  	}
899  
900  	v->load_addr = alloc_progmem(mod.core_size);
901  	if (!v->load_addr)
902  		return -ENOMEM;
903  
904  	pr_info("VPE loader: loading to %p\n", v->load_addr);
905  
906  	if (relocate) {
907  		for (i = 0; i < hdr->e_shnum; i++) {
908  			void *dest;
909  
910  			if (!(sechdrs[i].sh_flags & SHF_ALLOC))
911  				continue;
912  
913  			dest = v->load_addr + sechdrs[i].sh_entsize;
914  
915  			if (sechdrs[i].sh_type != SHT_NOBITS)
916  				memcpy(dest, (void *)sechdrs[i].sh_addr,
917  				       sechdrs[i].sh_size);
918  			/* Update sh_addr to point to copy in image. */
919  			sechdrs[i].sh_addr = (unsigned long)dest;
920  
921  			printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n",
922  			       secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
923  		}
924  
925   		/* Fix up syms, so that st_value is a pointer to location. */
926   		simplify_symbols(sechdrs, symindex, strtab, secstrings,
927   				 hdr->e_shnum, &mod);
928  
929   		/* Now do relocations. */
930   		for (i = 1; i < hdr->e_shnum; i++) {
931   			const char *strtab = (char *)sechdrs[strindex].sh_addr;
932   			unsigned int info = sechdrs[i].sh_info;
933  
934   			/* Not a valid relocation section? */
935   			if (info >= hdr->e_shnum)
936   				continue;
937  
938   			/* Don't bother with non-allocated sections */
939   			if (!(sechdrs[info].sh_flags & SHF_ALLOC))
940   				continue;
941  
942   			if (sechdrs[i].sh_type == SHT_REL)
943   				err = apply_relocations(sechdrs, strtab, symindex, i,
944   							&mod);
945   			else if (sechdrs[i].sh_type == SHT_RELA)
946   				err = apply_relocate_add(sechdrs, strtab, symindex, i,
947   							 &mod);
948   			if (err < 0)
949   				return err;
950  
951    		}
952    	} else {
953  		struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff);
954  
955  		for (i = 0; i < hdr->e_phnum; i++) {
956  			if (phdr->p_type == PT_LOAD) {
957  				memcpy((void *)phdr->p_paddr,
958  				       (char *)hdr + phdr->p_offset,
959  				       phdr->p_filesz);
960  				memset((void *)phdr->p_paddr + phdr->p_filesz,
961  				       0, phdr->p_memsz - phdr->p_filesz);
962  		    }
963  		    phdr++;
964  		}
965  
966  		for (i = 0; i < hdr->e_shnum; i++) {
967   			/* Internal symbols and strings. */
968   			if (sechdrs[i].sh_type == SHT_SYMTAB) {
969   				symindex = i;
970   				strindex = sechdrs[i].sh_link;
971   				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
972  
973   				/* mark the symtab's address for when we try to find the
974   				   magic symbols */
975   				sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
976   			}
977  		}
978  	}
979  
980  	/* make sure it's physically written out */
981  	flush_icache_range((unsigned long)v->load_addr,
982  			   (unsigned long)v->load_addr + v->len);
983  
984  	if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
985  		if (v->__start == 0) {
986  			printk(KERN_WARNING "VPE loader: program does not contain "
987  			       "a __start symbol\n");
988  			return -ENOEXEC;
989  		}
990  
991  		if (v->shared_ptr == NULL)
992  			printk(KERN_WARNING "VPE loader: "
993  			       "program does not contain vpe_shared symbol.\n"
994  			       " Unable to use AMVP (AP/SP) facilities.\n");
995  	}
996  
997  	printk(" elf loaded\n");
998  	return 0;
999  }
1000  
cleanup_tc(struct tc * tc)1001  static void cleanup_tc(struct tc *tc)
1002  {
1003  	unsigned long flags;
1004  	unsigned int mtflags, vpflags;
1005  	int tmp;
1006  
1007  	local_irq_save(flags);
1008  	mtflags = dmt();
1009  	vpflags = dvpe();
1010  	/* Put MVPE's into 'configuration state' */
1011  	set_c0_mvpcontrol(MVPCONTROL_VPC);
1012  
1013  	settc(tc->index);
1014  	tmp = read_tc_c0_tcstatus();
1015  
1016  	/* mark not allocated and not dynamically allocatable */
1017  	tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1018  	tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
1019  	write_tc_c0_tcstatus(tmp);
1020  
1021  	write_tc_c0_tchalt(TCHALT_H);
1022  	mips_ihb();
1023  
1024  	/* bind it to anything other than VPE1 */
1025  //	write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
1026  
1027  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
1028  	evpe(vpflags);
1029  	emt(mtflags);
1030  	local_irq_restore(flags);
1031  }
1032  
getcwd(char * buff,int size)1033  static int getcwd(char *buff, int size)
1034  {
1035  	mm_segment_t old_fs;
1036  	int ret;
1037  
1038  	old_fs = get_fs();
1039  	set_fs(KERNEL_DS);
1040  
1041  	ret = sys_getcwd(buff, size);
1042  
1043  	set_fs(old_fs);
1044  
1045  	return ret;
1046  }
1047  
1048  /* checks VPE is unused and gets ready to load program  */
vpe_open(struct inode * inode,struct file * filp)1049  static int vpe_open(struct inode *inode, struct file *filp)
1050  {
1051  	enum vpe_state state;
1052  	struct vpe_notifications *not;
1053  	struct vpe *v;
1054  	int ret, err = 0;
1055  
1056  	lock_kernel();
1057  	if (minor != iminor(inode)) {
1058  		/* assume only 1 device at the moment. */
1059  		printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");
1060  		err = -ENODEV;
1061  		goto out;
1062  	}
1063  
1064  	if ((v = get_vpe(tclimit)) == NULL) {
1065  		printk(KERN_WARNING "VPE loader: unable to get vpe\n");
1066  		err = -ENODEV;
1067  		goto out;
1068  	}
1069  
1070  	state = xchg(&v->state, VPE_STATE_INUSE);
1071  	if (state != VPE_STATE_UNUSED) {
1072  		printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
1073  
1074  		list_for_each_entry(not, &v->notify, list) {
1075  			not->stop(tclimit);
1076  		}
1077  
1078  		release_progmem(v->load_addr);
1079  		cleanup_tc(get_tc(tclimit));
1080  	}
1081  
1082  	/* this of-course trashes what was there before... */
1083  	v->pbuffer = vmalloc(P_SIZE);
1084  	v->plen = P_SIZE;
1085  	v->load_addr = NULL;
1086  	v->len = 0;
1087  
1088  	v->uid = filp->f_cred->fsuid;
1089  	v->gid = filp->f_cred->fsgid;
1090  
1091  #ifdef CONFIG_MIPS_APSP_KSPD
1092  	/* get kspd to tell us when a syscall_exit happens */
1093  	if (!kspd_events_reqd) {
1094  		kspd_notify(&kspd_events);
1095  		kspd_events_reqd++;
1096  	}
1097  #endif
1098  
1099  	v->cwd[0] = 0;
1100  	ret = getcwd(v->cwd, VPE_PATH_MAX);
1101  	if (ret < 0)
1102  		printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);
1103  
1104  	v->shared_ptr = NULL;
1105  	v->__start = 0;
1106  
1107  out:
1108  	unlock_kernel();
1109  	return 0;
1110  }
1111  
vpe_release(struct inode * inode,struct file * filp)1112  static int vpe_release(struct inode *inode, struct file *filp)
1113  {
1114  	struct vpe *v;
1115  	Elf_Ehdr *hdr;
1116  	int ret = 0;
1117  
1118  	v = get_vpe(tclimit);
1119  	if (v == NULL)
1120  		return -ENODEV;
1121  
1122  	hdr = (Elf_Ehdr *) v->pbuffer;
1123  	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) {
1124  		if (vpe_elfload(v) >= 0) {
1125  			vpe_run(v);
1126  		} else {
1127   			printk(KERN_WARNING "VPE loader: ELF load failed.\n");
1128  			ret = -ENOEXEC;
1129  		}
1130  	} else {
1131   		printk(KERN_WARNING "VPE loader: only elf files are supported\n");
1132  		ret = -ENOEXEC;
1133  	}
1134  
1135  	/* It's good to be able to run the SP and if it chokes have a look at
1136  	   the /dev/rt?. But if we reset the pointer to the shared struct we
1137  	   lose what has happened. So perhaps if garbage is sent to the vpe
1138  	   device, use it as a trigger for the reset. Hopefully a nice
1139  	   executable will be along shortly. */
1140  	if (ret < 0)
1141  		v->shared_ptr = NULL;
1142  
1143  	// cleanup any temp buffers
1144  	if (v->pbuffer)
1145  		vfree(v->pbuffer);
1146  	v->plen = 0;
1147  	return ret;
1148  }
1149  
vpe_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)1150  static ssize_t vpe_write(struct file *file, const char __user * buffer,
1151  			 size_t count, loff_t * ppos)
1152  {
1153  	size_t ret = count;
1154  	struct vpe *v;
1155  
1156  	if (iminor(file->f_path.dentry->d_inode) != minor)
1157  		return -ENODEV;
1158  
1159  	v = get_vpe(tclimit);
1160  	if (v == NULL)
1161  		return -ENODEV;
1162  
1163  	if (v->pbuffer == NULL) {
1164  		printk(KERN_ERR "VPE loader: no buffer for program\n");
1165  		return -ENOMEM;
1166  	}
1167  
1168  	if ((count + v->len) > v->plen) {
1169  		printk(KERN_WARNING
1170  		       "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
1171  		return -ENOMEM;
1172  	}
1173  
1174  	count -= copy_from_user(v->pbuffer + v->len, buffer, count);
1175  	if (!count)
1176  		return -EFAULT;
1177  
1178  	v->len += count;
1179  	return ret;
1180  }
1181  
1182  static const struct file_operations vpe_fops = {
1183  	.owner = THIS_MODULE,
1184  	.open = vpe_open,
1185  	.release = vpe_release,
1186  	.write = vpe_write
1187  };
1188  
1189  /* module wrapper entry points */
1190  /* give me a vpe */
vpe_alloc(void)1191  vpe_handle vpe_alloc(void)
1192  {
1193  	int i;
1194  	struct vpe *v;
1195  
1196  	/* find a vpe */
1197  	for (i = 1; i < MAX_VPES; i++) {
1198  		if ((v = get_vpe(i)) != NULL) {
1199  			v->state = VPE_STATE_INUSE;
1200  			return v;
1201  		}
1202  	}
1203  	return NULL;
1204  }
1205  
1206  EXPORT_SYMBOL(vpe_alloc);
1207  
1208  /* start running from here */
vpe_start(vpe_handle vpe,unsigned long start)1209  int vpe_start(vpe_handle vpe, unsigned long start)
1210  {
1211  	struct vpe *v = vpe;
1212  
1213  	v->__start = start;
1214  	return vpe_run(v);
1215  }
1216  
1217  EXPORT_SYMBOL(vpe_start);
1218  
1219  /* halt it for now */
vpe_stop(vpe_handle vpe)1220  int vpe_stop(vpe_handle vpe)
1221  {
1222  	struct vpe *v = vpe;
1223  	struct tc *t;
1224  	unsigned int evpe_flags;
1225  
1226  	evpe_flags = dvpe();
1227  
1228  	if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {
1229  
1230  		settc(t->index);
1231  		write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1232  	}
1233  
1234  	evpe(evpe_flags);
1235  
1236  	return 0;
1237  }
1238  
1239  EXPORT_SYMBOL(vpe_stop);
1240  
1241  /* I've done with it thank you */
vpe_free(vpe_handle vpe)1242  int vpe_free(vpe_handle vpe)
1243  {
1244  	struct vpe *v = vpe;
1245  	struct tc *t;
1246  	unsigned int evpe_flags;
1247  
1248  	if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
1249  		return -ENOEXEC;
1250  	}
1251  
1252  	evpe_flags = dvpe();
1253  
1254  	/* Put MVPE's into 'configuration state' */
1255  	set_c0_mvpcontrol(MVPCONTROL_VPC);
1256  
1257  	settc(t->index);
1258  	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1259  
1260  	/* halt the TC */
1261  	write_tc_c0_tchalt(TCHALT_H);
1262  	mips_ihb();
1263  
1264  	/* mark the TC unallocated */
1265  	write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
1266  
1267  	v->state = VPE_STATE_UNUSED;
1268  
1269  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
1270  	evpe(evpe_flags);
1271  
1272  	return 0;
1273  }
1274  
1275  EXPORT_SYMBOL(vpe_free);
1276  
vpe_get_shared(int index)1277  void *vpe_get_shared(int index)
1278  {
1279  	struct vpe *v;
1280  
1281  	if ((v = get_vpe(index)) == NULL)
1282  		return NULL;
1283  
1284  	return v->shared_ptr;
1285  }
1286  
1287  EXPORT_SYMBOL(vpe_get_shared);
1288  
vpe_getuid(int index)1289  int vpe_getuid(int index)
1290  {
1291  	struct vpe *v;
1292  
1293  	if ((v = get_vpe(index)) == NULL)
1294  		return -1;
1295  
1296  	return v->uid;
1297  }
1298  
1299  EXPORT_SYMBOL(vpe_getuid);
1300  
vpe_getgid(int index)1301  int vpe_getgid(int index)
1302  {
1303  	struct vpe *v;
1304  
1305  	if ((v = get_vpe(index)) == NULL)
1306  		return -1;
1307  
1308  	return v->gid;
1309  }
1310  
1311  EXPORT_SYMBOL(vpe_getgid);
1312  
vpe_notify(int index,struct vpe_notifications * notify)1313  int vpe_notify(int index, struct vpe_notifications *notify)
1314  {
1315  	struct vpe *v;
1316  
1317  	if ((v = get_vpe(index)) == NULL)
1318  		return -1;
1319  
1320  	list_add(&notify->list, &v->notify);
1321  	return 0;
1322  }
1323  
1324  EXPORT_SYMBOL(vpe_notify);
1325  
vpe_getcwd(int index)1326  char *vpe_getcwd(int index)
1327  {
1328  	struct vpe *v;
1329  
1330  	if ((v = get_vpe(index)) == NULL)
1331  		return NULL;
1332  
1333  	return v->cwd;
1334  }
1335  
1336  EXPORT_SYMBOL(vpe_getcwd);
1337  
1338  #ifdef CONFIG_MIPS_APSP_KSPD
kspd_sp_exit(int sp_id)1339  static void kspd_sp_exit( int sp_id)
1340  {
1341  	cleanup_tc(get_tc(sp_id));
1342  }
1343  #endif
1344  
store_kill(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)1345  static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
1346  			  const char *buf, size_t len)
1347  {
1348  	struct vpe *vpe = get_vpe(tclimit);
1349  	struct vpe_notifications *not;
1350  
1351  	list_for_each_entry(not, &vpe->notify, list) {
1352  		not->stop(tclimit);
1353  	}
1354  
1355  	release_progmem(vpe->load_addr);
1356  	cleanup_tc(get_tc(tclimit));
1357  	vpe_stop(vpe);
1358  	vpe_free(vpe);
1359  
1360  	return len;
1361  }
1362  
show_ntcs(struct device * cd,struct device_attribute * attr,char * buf)1363  static ssize_t show_ntcs(struct device *cd, struct device_attribute *attr,
1364  			 char *buf)
1365  {
1366  	struct vpe *vpe = get_vpe(tclimit);
1367  
1368  	return sprintf(buf, "%d\n", vpe->ntcs);
1369  }
1370  
store_ntcs(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)1371  static ssize_t store_ntcs(struct device *dev, struct device_attribute *attr,
1372  			  const char *buf, size_t len)
1373  {
1374  	struct vpe *vpe = get_vpe(tclimit);
1375  	unsigned long new;
1376  	char *endp;
1377  
1378  	new = simple_strtoul(buf, &endp, 0);
1379  	if (endp == buf)
1380  		goto out_einval;
1381  
1382  	if (new == 0 || new > (hw_tcs - tclimit))
1383  		goto out_einval;
1384  
1385  	vpe->ntcs = new;
1386  
1387  	return len;
1388  
1389  out_einval:
1390  	return -EINVAL;;
1391  }
1392  
1393  static struct device_attribute vpe_class_attributes[] = {
1394  	__ATTR(kill, S_IWUSR, NULL, store_kill),
1395  	__ATTR(ntcs, S_IRUGO | S_IWUSR, show_ntcs, store_ntcs),
1396  	{}
1397  };
1398  
vpe_device_release(struct device * cd)1399  static void vpe_device_release(struct device *cd)
1400  {
1401  	kfree(cd);
1402  }
1403  
1404  struct class vpe_class = {
1405  	.name = "vpe",
1406  	.owner = THIS_MODULE,
1407  	.dev_release = vpe_device_release,
1408  	.dev_attrs = vpe_class_attributes,
1409  };
1410  
1411  struct device vpe_device;
1412  
vpe_module_init(void)1413  static int __init vpe_module_init(void)
1414  {
1415  	unsigned int mtflags, vpflags;
1416  	unsigned long flags, val;
1417  	struct vpe *v = NULL;
1418  	struct tc *t;
1419  	int tc, err;
1420  
1421  	if (!cpu_has_mipsmt) {
1422  		printk("VPE loader: not a MIPS MT capable processor\n");
1423  		return -ENODEV;
1424  	}
1425  
1426  	if (vpelimit == 0) {
1427  		printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
1428  		       "initializing VPE loader.\nPass maxvpes=<n> argument as "
1429  		       "kernel argument\n");
1430  
1431  		return -ENODEV;
1432  	}
1433  
1434  	if (tclimit == 0) {
1435  		printk(KERN_WARNING "No TCs reserved for AP/SP, not "
1436  		       "initializing VPE loader.\nPass maxtcs=<n> argument as "
1437  		       "kernel argument\n");
1438  
1439  		return -ENODEV;
1440  	}
1441  
1442  	major = register_chrdev(0, module_name, &vpe_fops);
1443  	if (major < 0) {
1444  		printk("VPE loader: unable to register character device\n");
1445  		return major;
1446  	}
1447  
1448  	err = class_register(&vpe_class);
1449  	if (err) {
1450  		printk(KERN_ERR "vpe_class registration failed\n");
1451  		goto out_chrdev;
1452  	}
1453  
1454  	device_initialize(&vpe_device);
1455  	vpe_device.class	= &vpe_class,
1456  	vpe_device.parent	= NULL,
1457  	dev_set_name(&vpe_device, "vpe1");
1458  	vpe_device.devt = MKDEV(major, minor);
1459  	err = device_add(&vpe_device);
1460  	if (err) {
1461  		printk(KERN_ERR "Adding vpe_device failed\n");
1462  		goto out_class;
1463  	}
1464  
1465  	local_irq_save(flags);
1466  	mtflags = dmt();
1467  	vpflags = dvpe();
1468  
1469  	/* Put MVPE's into 'configuration state' */
1470  	set_c0_mvpcontrol(MVPCONTROL_VPC);
1471  
1472  	/* dump_mtregs(); */
1473  
1474  	val = read_c0_mvpconf0();
1475  	hw_tcs = (val & MVPCONF0_PTC) + 1;
1476  	hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
1477  
1478  	for (tc = tclimit; tc < hw_tcs; tc++) {
1479  		/*
1480  		 * Must re-enable multithreading temporarily or in case we
1481  		 * reschedule send IPIs or similar we might hang.
1482  		 */
1483  		clear_c0_mvpcontrol(MVPCONTROL_VPC);
1484  		evpe(vpflags);
1485  		emt(mtflags);
1486  		local_irq_restore(flags);
1487  		t = alloc_tc(tc);
1488  		if (!t) {
1489  			err = -ENOMEM;
1490  			goto out;
1491  		}
1492  
1493  		local_irq_save(flags);
1494  		mtflags = dmt();
1495  		vpflags = dvpe();
1496  		set_c0_mvpcontrol(MVPCONTROL_VPC);
1497  
1498  		/* VPE's */
1499  		if (tc < hw_tcs) {
1500  			settc(tc);
1501  
1502  			if ((v = alloc_vpe(tc)) == NULL) {
1503  				printk(KERN_WARNING "VPE: unable to allocate VPE\n");
1504  
1505  				goto out_reenable;
1506  			}
1507  
1508  			v->ntcs = hw_tcs - tclimit;
1509  
1510  			/* add the tc to the list of this vpe's tc's. */
1511  			list_add(&t->tc, &v->tc);
1512  
1513  			/* deactivate all but vpe0 */
1514  			if (tc >= tclimit) {
1515  				unsigned long tmp = read_vpe_c0_vpeconf0();
1516  
1517  				tmp &= ~VPECONF0_VPA;
1518  
1519  				/* master VPE */
1520  				tmp |= VPECONF0_MVP;
1521  				write_vpe_c0_vpeconf0(tmp);
1522  			}
1523  
1524  			/* disable multi-threading with TC's */
1525  			write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
1526  
1527  			if (tc >= vpelimit) {
1528  				/*
1529  				 * Set config to be the same as vpe0,
1530  				 * particularly kseg0 coherency alg
1531  				 */
1532  				write_vpe_c0_config(read_c0_config());
1533  			}
1534  		}
1535  
1536  		/* TC's */
1537  		t->pvpe = v;	/* set the parent vpe */
1538  
1539  		if (tc >= tclimit) {
1540  			unsigned long tmp;
1541  
1542  			settc(tc);
1543  
1544  			/* Any TC that is bound to VPE0 gets left as is - in case
1545  			   we are running SMTC on VPE0. A TC that is bound to any
1546  			   other VPE gets bound to VPE0, ideally I'd like to make
1547  			   it homeless but it doesn't appear to let me bind a TC
1548  			   to a non-existent VPE. Which is perfectly reasonable.
1549  
1550  			   The (un)bound state is visible to an EJTAG probe so may
1551  			   notify GDB...
1552  			*/
1553  
1554  			if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
1555  				/* tc is bound >vpe0 */
1556  				write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
1557  
1558  				t->pvpe = get_vpe(0);	/* set the parent vpe */
1559  			}
1560  
1561  			/* halt the TC */
1562  			write_tc_c0_tchalt(TCHALT_H);
1563  			mips_ihb();
1564  
1565  			tmp = read_tc_c0_tcstatus();
1566  
1567  			/* mark not activated and not dynamically allocatable */
1568  			tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1569  			tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
1570  			write_tc_c0_tcstatus(tmp);
1571  		}
1572  	}
1573  
1574  out_reenable:
1575  	/* release config state */
1576  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
1577  
1578  	evpe(vpflags);
1579  	emt(mtflags);
1580  	local_irq_restore(flags);
1581  
1582  #ifdef CONFIG_MIPS_APSP_KSPD
1583  	kspd_events.kspd_sp_exit = kspd_sp_exit;
1584  #endif
1585  	return 0;
1586  
1587  out_class:
1588  	class_unregister(&vpe_class);
1589  out_chrdev:
1590  	unregister_chrdev(major, module_name);
1591  
1592  out:
1593  	return err;
1594  }
1595  
vpe_module_exit(void)1596  static void __exit vpe_module_exit(void)
1597  {
1598  	struct vpe *v, *n;
1599  
1600  	list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
1601  		if (v->state != VPE_STATE_UNUSED) {
1602  			release_vpe(v);
1603  		}
1604  	}
1605  
1606  	device_del(&vpe_device);
1607  	unregister_chrdev(major, module_name);
1608  }
1609  
1610  module_init(vpe_module_init);
1611  module_exit(vpe_module_exit);
1612  MODULE_DESCRIPTION("MIPS VPE Loader");
1613  MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
1614  MODULE_LICENSE("GPL");
1615