]> err.no Git - linux-2.6/blob - arch/mips/kernel/vpe.c
6bf42ba08f0957fcb4025e66482fca18d58dc3c1
[linux-2.6] / arch / mips / kernel / vpe.c
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 /*
20  * VPE support module
21  *
22  * Provides support for loading a MIPS SP program on VPE1.
23  * The SP enviroment is rather simple, no tlb's.  It needs to be relocatable
24  * (or partially linked). You should initialise your stack in the startup
25  * code. This loader looks for the symbol __start and sets up
26  * execution to resume from there. The MIPS SDE kit contains suitable examples.
27  *
28  * To load and run, simply cat a SP 'program file' to /dev/vpe1.
29  * i.e cat spapp >/dev/vpe1.
30  *
31  * You'll need to have the following device files.
32  * mknod /dev/vpe0 c 63 0
33  * mknod /dev/vpe1 c 63 1
34  */
35
36 #include <linux/kernel.h>
37 #include <linux/module.h>
38 #include <linux/fs.h>
39 #include <linux/init.h>
40 #include <asm/uaccess.h>
41 #include <linux/slab.h>
42 #include <linux/list.h>
43 #include <linux/vmalloc.h>
44 #include <linux/elf.h>
45 #include <linux/seq_file.h>
46 #include <linux/syscalls.h>
47 #include <linux/moduleloader.h>
48 #include <linux/interrupt.h>
49 #include <linux/poll.h>
50 #include <linux/bootmem.h>
51 #include <asm/mipsregs.h>
52 #include <asm/cacheflush.h>
53 #include <asm/atomic.h>
54 #include <asm/cpu.h>
55 #include <asm/processor.h>
56 #include <asm/system.h>
57
58 typedef void *vpe_handle;
59
60 // defined here because the kernel module loader doesn't have
61 // anything to do with it.
62 #define SHN_MIPS_SCOMMON 0xff03
63
64 #ifndef ARCH_SHF_SMALL
65 #define ARCH_SHF_SMALL 0
66 #endif
67
68 /* If this is set, the section belongs in the init part of the module */
69 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
70
71 // temp number,
72 #define VPE_MAJOR 63
73
74 static char module_name[] = "vpe";
75 static int major = 0;
76
77 /* grab the likely amount of memory we will need. */
78 #ifdef CONFIG_MIPS_VPE_LOADER_TOM
79 #define P_SIZE (2 * 1024 * 1024)
80 #else
81 /* add an overhead to the max kmalloc size for non-striped symbols/etc */
82 #define P_SIZE (256 * 1024)
83 #endif
84
85 #define MAX_VPES 16
86
87 enum vpe_state {
88         VPE_STATE_UNUSED = 0,
89         VPE_STATE_INUSE,
90         VPE_STATE_RUNNING
91 };
92
93 enum tc_state {
94         TC_STATE_UNUSED = 0,
95         TC_STATE_INUSE,
96         TC_STATE_RUNNING,
97         TC_STATE_DYNAMIC
98 };
99
100 struct vpe;
101 typedef struct tc {
102         enum tc_state state;
103         int index;
104
105         /* parent VPE */
106         struct vpe *pvpe;
107
108         /* The list of TC's with this VPE */
109         struct list_head tc;
110
111         /* The global list of tc's */
112         struct list_head list;
113 } tc_t;
114
115 typedef struct vpe {
116         enum vpe_state state;
117
118         /* (device) minor associated with this vpe */
119         int minor;
120
121         /* elfloader stuff */
122         void *load_addr;
123         u32 len;
124         char *pbuffer;
125         u32 plen;
126
127         unsigned long __start;
128
129         /* tc's associated with this vpe */
130         struct list_head tc;
131
132         /* The list of vpe's */
133         struct list_head list;
134
135         /* shared symbol address */
136         void *shared_ptr;
137 } vpe_t;
138
139 struct vpecontrol_ {
140         /* Virtual processing elements */
141         struct list_head vpe_list;
142
143         /* Thread contexts */
144         struct list_head tc_list;
145 } vpecontrol;
146
147 static void release_progmem(void *ptr);
148 static void dump_vpe(vpe_t * v);
149 extern void save_gp_address(unsigned int secbase, unsigned int rel);
150
151 /* get the vpe associated with this minor */
152 struct vpe *get_vpe(int minor)
153 {
154         struct vpe *v;
155
156         list_for_each_entry(v, &vpecontrol.vpe_list, list) {
157                 if (v->minor == minor)
158                         return v;
159         }
160
161         printk(KERN_DEBUG "VPE: get_vpe minor %d not found\n", minor);
162         return NULL;
163 }
164
165 /* get the vpe associated with this minor */
166 struct tc *get_tc(int index)
167 {
168         struct tc *t;
169
170         list_for_each_entry(t, &vpecontrol.tc_list, list) {
171                 if (t->index == index)
172                         return t;
173         }
174
175         printk(KERN_DEBUG "VPE: get_tc index %d not found\n", index);
176
177         return NULL;
178 }
179
180 struct tc *get_tc_unused(void)
181 {
182         struct tc *t;
183
184         list_for_each_entry(t, &vpecontrol.tc_list, list) {
185                 if (t->state == TC_STATE_UNUSED)
186                         return t;
187         }
188
189         printk(KERN_DEBUG "VPE: All TC's are in use\n");
190
191         return NULL;
192 }
193
194 /* allocate a vpe and associate it with this minor (or index) */
195 struct vpe *alloc_vpe(int minor)
196 {
197         struct vpe *v;
198
199         if ((v = kmalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) {
200                 printk(KERN_WARNING "VPE: alloc_vpe no mem\n");
201                 return NULL;
202         }
203
204         memset(v, 0, sizeof(struct vpe));
205
206         INIT_LIST_HEAD(&v->tc);
207         list_add_tail(&v->list, &vpecontrol.vpe_list);
208
209         v->minor = minor;
210         return v;
211 }
212
213 /* allocate a tc. At startup only tc0 is running, all other can be halted. */
214 struct tc *alloc_tc(int index)
215 {
216         struct tc *t;
217
218         if ((t = kmalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) {
219                 printk(KERN_WARNING "VPE: alloc_tc no mem\n");
220                 return NULL;
221         }
222
223         memset(t, 0, sizeof(struct tc));
224
225         INIT_LIST_HEAD(&t->tc);
226         list_add_tail(&t->list, &vpecontrol.tc_list);
227
228         t->index = index;
229
230         return t;
231 }
232
233 /* clean up and free everything */
234 void release_vpe(struct vpe *v)
235 {
236         list_del(&v->list);
237         if (v->load_addr)
238                 release_progmem(v);
239         kfree(v);
240 }
241
242 void dump_mtregs(void)
243 {
244         unsigned long val;
245
246         val = read_c0_config3();
247         printk("config3 0x%lx MT %ld\n", val,
248                (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
249
250         val = read_c0_mvpconf0();
251         printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
252                (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
253                val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
254
255         val = read_c0_mvpcontrol();
256         printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
257                (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
258                (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
259                (val & MVPCONTROL_EVP));
260
261         val = read_c0_vpeconf0();
262         printk("VPEConf0 0x%lx MVP %ld\n", val,
263                (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT);
264 }
265
266 /* Find some VPE program space  */
267 static void *alloc_progmem(u32 len)
268 {
269 #ifdef CONFIG_MIPS_VPE_LOADER_TOM
270         /* this means you must tell linux to use less memory than you physically have */
271         return (void *)((max_pfn * PAGE_SIZE) + KSEG0);
272 #else
273         // simple grab some mem for now
274         return kmalloc(len, GFP_KERNEL);
275 #endif
276 }
277
278 static void release_progmem(void *ptr)
279 {
280 #ifndef CONFIG_MIPS_VPE_LOADER_TOM
281         kfree(ptr);
282 #endif
283 }
284
285 /* Update size with this section: return offset. */
286 static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
287 {
288         long ret;
289
290         ret = ALIGN(*size, sechdr->sh_addralign ? : 1);
291         *size = ret + sechdr->sh_size;
292         return ret;
293 }
294
295 /* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
296    might -- code, read-only data, read-write data, small data.  Tally
297    sizes, and place the offsets into sh_entsize fields: high bit means it
298    belongs in init. */
299 static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
300                             Elf_Shdr * sechdrs, const char *secstrings)
301 {
302         static unsigned long const masks[][2] = {
303                 /* NOTE: all executable code must be the first section
304                  * in this array; otherwise modify the text_size
305                  * finder in the two loops below */
306                 {SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL},
307                 {SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL},
308                 {SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL},
309                 {ARCH_SHF_SMALL | SHF_ALLOC, 0}
310         };
311         unsigned int m, i;
312
313         for (i = 0; i < hdr->e_shnum; i++)
314                 sechdrs[i].sh_entsize = ~0UL;
315
316         for (m = 0; m < ARRAY_SIZE(masks); ++m) {
317                 for (i = 0; i < hdr->e_shnum; ++i) {
318                         Elf_Shdr *s = &sechdrs[i];
319
320                         //  || strncmp(secstrings + s->sh_name, ".init", 5) == 0)
321                         if ((s->sh_flags & masks[m][0]) != masks[m][0]
322                             || (s->sh_flags & masks[m][1])
323                             || s->sh_entsize != ~0UL)
324                                 continue;
325                         s->sh_entsize = get_offset(&mod->core_size, s);
326                 }
327
328                 if (m == 0)
329                         mod->core_text_size = mod->core_size;
330
331         }
332 }
333
334
335 /* from module-elf32.c, but subverted a little */
336
337 struct mips_hi16 {
338         struct mips_hi16 *next;
339         Elf32_Addr *addr;
340         Elf32_Addr value;
341 };
342
343 static struct mips_hi16 *mips_hi16_list;
344 static unsigned int gp_offs, gp_addr;
345
346 static int apply_r_mips_none(struct module *me, uint32_t *location,
347                              Elf32_Addr v)
348 {
349         return 0;
350 }
351
352 static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
353                                 Elf32_Addr v)
354 {
355         int rel;
356
357         if( !(*location & 0xffff) ) {
358                 rel = (int)v - gp_addr;
359         }
360         else {
361                 /* .sbss + gp(relative) + offset */
362                 /* kludge! */
363                 rel =  (int)(short)((int)v + gp_offs +
364                                     (int)(short)(*location & 0xffff) - gp_addr);
365         }
366
367         if( (rel > 32768) || (rel < -32768) ) {
368                 printk(KERN_ERR
369                        "apply_r_mips_gprel16: relative address out of range 0x%x %d\n",
370                        rel, rel);
371                 return -ENOEXEC;
372         }
373
374         *location = (*location & 0xffff0000) | (rel & 0xffff);
375
376         return 0;
377 }
378
379 static int apply_r_mips_pc16(struct module *me, uint32_t *location,
380                              Elf32_Addr v)
381 {
382         int rel;
383         rel = (((unsigned int)v - (unsigned int)location));
384         rel >>= 2;              // because the offset is in _instructions_ not bytes.
385         rel -= 1;               // and one instruction less due to the branch delay slot.
386
387         if( (rel > 32768) || (rel < -32768) ) {
388                 printk(KERN_ERR
389                        "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
390                 return -ENOEXEC;
391         }
392
393         *location = (*location & 0xffff0000) | (rel & 0xffff);
394
395         return 0;
396 }
397
398 static int apply_r_mips_32(struct module *me, uint32_t *location,
399                            Elf32_Addr v)
400 {
401         *location += v;
402
403         return 0;
404 }
405
406 static int apply_r_mips_26(struct module *me, uint32_t *location,
407                            Elf32_Addr v)
408 {
409         if (v % 4) {
410                 printk(KERN_ERR "module %s: dangerous relocation mod4\n", me->name);
411                 return -ENOEXEC;
412         }
413
414 /* Not desperately convinced this is a good check of an overflow condition
415    anyway. But it gets in the way of handling undefined weak symbols which
416    we want to set to zero.
417    if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
418    printk(KERN_ERR
419    "module %s: relocation overflow\n",
420    me->name);
421    return -ENOEXEC;
422    }
423 */
424
425         *location = (*location & ~0x03ffffff) |
426                 ((*location + (v >> 2)) & 0x03ffffff);
427         return 0;
428 }
429
430 static int apply_r_mips_hi16(struct module *me, uint32_t *location,
431                              Elf32_Addr v)
432 {
433         struct mips_hi16 *n;
434
435         /*
436          * We cannot relocate this one now because we don't know the value of
437          * the carry we need to add.  Save the information, and let LO16 do the
438          * actual relocation.
439          */
440         n = kmalloc(sizeof *n, GFP_KERNEL);
441         if (!n)
442                 return -ENOMEM;
443
444         n->addr = location;
445         n->value = v;
446         n->next = mips_hi16_list;
447         mips_hi16_list = n;
448
449         return 0;
450 }
451
452 static int apply_r_mips_lo16(struct module *me, uint32_t *location,
453                              Elf32_Addr v)
454 {
455         unsigned long insnlo = *location;
456         Elf32_Addr val, vallo;
457
458         /* Sign extend the addend we extract from the lo insn.  */
459         vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
460
461         if (mips_hi16_list != NULL) {
462                 struct mips_hi16 *l;
463
464                 l = mips_hi16_list;
465                 while (l != NULL) {
466                         struct mips_hi16 *next;
467                         unsigned long insn;
468
469                         /*
470                          * The value for the HI16 had best be the same.
471                          */
472                         if (v != l->value) {
473                                 printk("%d != %d\n", v, l->value);
474                                 goto out_danger;
475                         }
476
477
478                         /*
479                          * Do the HI16 relocation.  Note that we actually don't
480                          * need to know anything about the LO16 itself, except
481                          * where to find the low 16 bits of the addend needed
482                          * by the LO16.
483                          */
484                         insn = *l->addr;
485                         val = ((insn & 0xffff) << 16) + vallo;
486                         val += v;
487
488                         /*
489                          * Account for the sign extension that will happen in
490                          * the low bits.
491                          */
492                         val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
493
494                         insn = (insn & ~0xffff) | val;
495                         *l->addr = insn;
496
497                         next = l->next;
498                         kfree(l);
499                         l = next;
500                 }
501
502                 mips_hi16_list = NULL;
503         }
504
505         /*
506          * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
507          */
508         val = v + vallo;
509         insnlo = (insnlo & ~0xffff) | (val & 0xffff);
510         *location = insnlo;
511
512         return 0;
513
514 out_danger:
515         printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name);
516
517         return -ENOEXEC;
518 }
519
520 static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
521                                 Elf32_Addr v) = {
522         [R_MIPS_NONE]   = apply_r_mips_none,
523         [R_MIPS_32]     = apply_r_mips_32,
524         [R_MIPS_26]     = apply_r_mips_26,
525         [R_MIPS_HI16]   = apply_r_mips_hi16,
526         [R_MIPS_LO16]   = apply_r_mips_lo16,
527         [R_MIPS_GPREL16] = apply_r_mips_gprel16,
528         [R_MIPS_PC16] = apply_r_mips_pc16
529 };
530
531
532 int apply_relocations(Elf32_Shdr *sechdrs,
533                       const char *strtab,
534                       unsigned int symindex,
535                       unsigned int relsec,
536                       struct module *me)
537 {
538         Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
539         Elf32_Sym *sym;
540         uint32_t *location;
541         unsigned int i;
542         Elf32_Addr v;
543         int res;
544
545         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
546                 Elf32_Word r_info = rel[i].r_info;
547
548                 /* This is where to make the change */
549                 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
550                         + rel[i].r_offset;
551                 /* This is the symbol it is referring to */
552                 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
553                         + ELF32_R_SYM(r_info);
554
555                 if (!sym->st_value) {
556                         printk(KERN_DEBUG "%s: undefined weak symbol %s\n",
557                                me->name, strtab + sym->st_name);
558                         /* just print the warning, dont barf */
559                 }
560
561                 v = sym->st_value;
562
563                 res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
564                 if( res ) {
565                         printk(KERN_DEBUG
566                                "relocation error 0x%x sym refer <%s> value 0x%x "
567                                "type 0x%x r_info 0x%x\n",
568                                (unsigned int)location, strtab + sym->st_name, v,
569                                r_info, ELF32_R_TYPE(r_info));
570                 }
571
572                 if (res)
573                         return res;
574         }
575
576         return 0;
577 }
578
579 void save_gp_address(unsigned int secbase, unsigned int rel)
580 {
581         gp_addr = secbase + rel;
582         gp_offs = gp_addr - (secbase & 0xffff0000);
583 }
584 /* end module-elf32.c */
585
586
587
588 /* Change all symbols so that sh_value encodes the pointer directly. */
589 static int simplify_symbols(Elf_Shdr * sechdrs,
590                             unsigned int symindex,
591                             const char *strtab,
592                             const char *secstrings,
593                             unsigned int nsecs, struct module *mod)
594 {
595         Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
596         unsigned long secbase, bssbase = 0;
597         unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
598         int ret = 0, size;
599
600         /* find the .bss section for COMMON symbols */
601         for (i = 0; i < nsecs; i++) {
602                 if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0)
603                         bssbase = sechdrs[i].sh_addr;
604         }
605
606         for (i = 1; i < n; i++) {
607                 switch (sym[i].st_shndx) {
608                 case SHN_COMMON:
609                         /* Allocate space for the symbol in the .bss section. st_value is currently size.
610                            We want it to have the address of the symbol. */
611
612                         size = sym[i].st_value;
613                         sym[i].st_value = bssbase;
614
615                         bssbase += size;
616                         break;
617
618                 case SHN_ABS:
619                         /* Don't need to do anything */
620                         break;
621
622                 case SHN_UNDEF:
623                         /* ret = -ENOENT; */
624                         break;
625
626                 case SHN_MIPS_SCOMMON:
627
628                         printk(KERN_DEBUG
629                                "simplify_symbols: ignoring SHN_MIPS_SCOMMON symbol <%s> st_shndx %d\n",
630                                strtab + sym[i].st_name, sym[i].st_shndx);
631
632                         // .sbss section
633                         break;
634
635                 default:
636                         secbase = sechdrs[sym[i].st_shndx].sh_addr;
637
638                         if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) {
639                                 save_gp_address(secbase, sym[i].st_value);
640                         }
641
642                         sym[i].st_value += secbase;
643                         break;
644                 }
645
646         }
647
648         return ret;
649 }
650
651 #ifdef DEBUG_ELFLOADER
652 static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
653                             const char *strtab, struct module *mod)
654 {
655         Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
656         unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
657
658         printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n);
659         for (i = 1; i < n; i++) {
660                 printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i,
661                        strtab + sym[i].st_name, sym[i].st_value);
662         }
663 }
664 #endif
665
666 static void dump_tc(struct tc *t)
667 {
668         printk(KERN_WARNING "VPE: TC index %d TCStatus 0x%lx halt 0x%lx\n",
669                t->index, read_tc_c0_tcstatus(), read_tc_c0_tchalt());
670         printk(KERN_WARNING "VPE: tcrestart 0x%lx\n", read_tc_c0_tcrestart());
671 }
672
673 static void dump_tclist(void)
674 {
675         struct tc *t;
676
677         list_for_each_entry(t, &vpecontrol.tc_list, list) {
678                 dump_tc(t);
679         }
680 }
681
682 /* We are prepared so configure and start the VPE... */
683 int vpe_run(vpe_t * v)
684 {
685         unsigned long val;
686         struct tc *t;
687
688         /* check we are the Master VPE */
689         val = read_c0_vpeconf0();
690         if (!(val & VPECONF0_MVP)) {
691                 printk(KERN_WARNING
692                        "VPE: only Master VPE's are allowed to configure MT\n");
693                 return -1;
694         }
695
696         /* disable MT (using dvpe) */
697         dvpe();
698
699         /* Put MVPE's into 'configuration state' */
700         write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC);
701
702         if (!list_empty(&v->tc)) {
703                 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
704                         printk(KERN_WARNING "VPE: TC %d is already in use.\n",
705                                t->index);
706                         return -ENOEXEC;
707                 }
708         } else {
709                 printk(KERN_WARNING "VPE: No TC's associated with VPE %d\n",
710                        v->minor);
711                 return -ENOEXEC;
712         }
713
714         settc(t->index);
715
716         val = read_vpe_c0_vpeconf0();
717
718         /* should check it is halted, and not activated */
719         if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
720                 printk(KERN_WARNING "VPE: TC %d is already doing something!\n",
721                        t->index);
722
723                 dump_tclist();
724                 return -ENOEXEC;
725         }
726
727         /* Write the address we want it to start running from in the TCPC register. */
728         write_tc_c0_tcrestart((unsigned long)v->__start);
729
730         /* write the sivc_info address to tccontext */
731         write_tc_c0_tccontext((unsigned long)0);
732
733         /* Set up the XTC bit in vpeconf0 to point at our tc */
734         write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (t->index << VPECONF0_XTC_SHIFT));
735
736         /* mark the TC as activated, not interrupt exempt and not dynamically allocatable */
737         val = read_tc_c0_tcstatus();
738         val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
739         write_tc_c0_tcstatus(val);
740
741         write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
742
743         /* set up VPE1 */
744         write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);     // no multiple TC's
745         write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);   // enable this VPE
746
747         /*
748          * The sde-kit passes 'memsize' to __start in $a3, so set something
749          * here...
750          * Or set $a3 (register 7) to zero and define DFLT_STACK_SIZE and
751          * DFLT_HEAP_SIZE when you compile your program
752          */
753
754         mttgpr(7, 0);
755
756         /* set config to be the same as vpe0, particularly kseg0 coherency alg */
757         write_vpe_c0_config(read_c0_config());
758
759         /* clear out any left overs from a previous program */
760         write_vpe_c0_cause(0);
761
762         /* take system out of configuration state */
763         write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC);
764
765         /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */
766         write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL));
767
768         /* set it running */
769         evpe(EVPE_ENABLE);
770
771         return 0;
772 }
773
774 static unsigned long find_vpe_symbols(vpe_t * v, Elf_Shdr * sechdrs,
775                                       unsigned int symindex, const char *strtab,
776                                       struct module *mod)
777 {
778         Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
779         unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
780
781         for (i = 1; i < n; i++) {
782                 if (strcmp(strtab + sym[i].st_name, "__start") == 0) {
783                         v->__start = sym[i].st_value;
784                 }
785
786                 if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) {
787                         v->shared_ptr = (void *)sym[i].st_value;
788                 }
789         }
790
791         return 0;
792 }
793
794 /* Allocates a VPE with some program code space(the load address), copies the contents
795    of the program (p)buffer performing relocatations/etc, free's it when finished.
796 */
797 int vpe_elfload(vpe_t * v)
798 {
799         Elf_Ehdr *hdr;
800         Elf_Shdr *sechdrs;
801         long err = 0;
802         char *secstrings, *strtab = NULL;
803         unsigned int len, i, symindex = 0, strindex = 0;
804
805         struct module mod;      // so we can re-use the relocations code
806
807         memset(&mod, 0, sizeof(struct module));
808         strcpy(mod.name, "VPE dummy prog module");
809
810         hdr = (Elf_Ehdr *) v->pbuffer;
811         len = v->plen;
812
813         /* Sanity checks against insmoding binaries or wrong arch,
814            weird elf version */
815         if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
816             || hdr->e_type != ET_REL || !elf_check_arch(hdr)
817             || hdr->e_shentsize != sizeof(*sechdrs)) {
818                 printk(KERN_WARNING
819                        "VPE program, wrong arch or weird elf version\n");
820
821                 return -ENOEXEC;
822         }
823
824         if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
825                 printk(KERN_ERR "VPE program length %u truncated\n", len);
826                 return -ENOEXEC;
827         }
828
829         /* Convenience variables */
830         sechdrs = (void *)hdr + hdr->e_shoff;
831         secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
832         sechdrs[0].sh_addr = 0;
833
834         /* And these should exist, but gcc whinges if we don't init them */
835         symindex = strindex = 0;
836
837         for (i = 1; i < hdr->e_shnum; i++) {
838
839                 if (sechdrs[i].sh_type != SHT_NOBITS
840                     && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
841                         printk(KERN_ERR "VPE program length %u truncated\n",
842                                len);
843                         return -ENOEXEC;
844                 }
845
846                 /* Mark all sections sh_addr with their address in the
847                    temporary image. */
848                 sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
849
850                 /* Internal symbols and strings. */
851                 if (sechdrs[i].sh_type == SHT_SYMTAB) {
852                         symindex = i;
853                         strindex = sechdrs[i].sh_link;
854                         strtab = (char *)hdr + sechdrs[strindex].sh_offset;
855                 }
856         }
857
858         layout_sections(&mod, hdr, sechdrs, secstrings);
859
860         v->load_addr = alloc_progmem(mod.core_size);
861         memset(v->load_addr, 0, mod.core_size);
862
863         printk("VPE elf_loader: loading to %p\n", v->load_addr);
864
865         for (i = 0; i < hdr->e_shnum; i++) {
866                 void *dest;
867
868                 if (!(sechdrs[i].sh_flags & SHF_ALLOC))
869                         continue;
870
871                 dest = v->load_addr + sechdrs[i].sh_entsize;
872
873                 if (sechdrs[i].sh_type != SHT_NOBITS)
874                         memcpy(dest, (void *)sechdrs[i].sh_addr,
875                                sechdrs[i].sh_size);
876                 /* Update sh_addr to point to copy in image. */
877                 sechdrs[i].sh_addr = (unsigned long)dest;
878         }
879
880         /* Fix up syms, so that st_value is a pointer to location. */
881         err =
882                 simplify_symbols(sechdrs, symindex, strtab, secstrings,
883                                  hdr->e_shnum, &mod);
884         if (err < 0) {
885                 printk(KERN_WARNING "VPE: unable to simplify symbols\n");
886                 goto cleanup;
887         }
888
889         /* Now do relocations. */
890         for (i = 1; i < hdr->e_shnum; i++) {
891                 const char *strtab = (char *)sechdrs[strindex].sh_addr;
892                 unsigned int info = sechdrs[i].sh_info;
893
894                 /* Not a valid relocation section? */
895                 if (info >= hdr->e_shnum)
896                         continue;
897
898                 /* Don't bother with non-allocated sections */
899                 if (!(sechdrs[info].sh_flags & SHF_ALLOC))
900                         continue;
901
902                 if (sechdrs[i].sh_type == SHT_REL)
903                         err =
904                                 apply_relocations(sechdrs, strtab, symindex, i, &mod);
905                 else if (sechdrs[i].sh_type == SHT_RELA)
906                         err = apply_relocate_add(sechdrs, strtab, symindex, i,
907                                                  &mod);
908                 if (err < 0) {
909                         printk(KERN_WARNING
910                                "vpe_elfload: error in relocations err %ld\n",
911                                err);
912                         goto cleanup;
913                 }
914         }
915
916         /* make sure it's physically written out */
917         flush_icache_range((unsigned long)v->load_addr,
918                            (unsigned long)v->load_addr + v->len);
919
920         if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
921
922                 printk(KERN_WARNING
923                        "VPE: program doesn't contain __start or vpe_shared symbols\n");
924                 err = -ENOEXEC;
925         }
926
927         printk(" elf loaded\n");
928
929 cleanup:
930         return err;
931 }
932
933 static void dump_vpe(vpe_t * v)
934 {
935         struct tc *t;
936
937         printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol());
938         printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0());
939
940         list_for_each_entry(t, &vpecontrol.tc_list, list) {
941                 dump_tc(t);
942         }
943 }
944
945 /* checks for VPE is unused and gets ready to load program       */
946 static int vpe_open(struct inode *inode, struct file *filp)
947 {
948         int minor;
949         vpe_t *v;
950
951         /* assume only 1 device at the mo. */
952         if ((minor = MINOR(inode->i_rdev)) != 1) {
953                 printk(KERN_WARNING "VPE: only vpe1 is supported\n");
954                 return -ENODEV;
955         }
956
957         if ((v = get_vpe(minor)) == NULL) {
958                 printk(KERN_WARNING "VPE: unable to get vpe\n");
959                 return -ENODEV;
960         }
961
962         if (v->state != VPE_STATE_UNUSED) {
963                 unsigned long tmp;
964                 struct tc *t;
965
966                 printk(KERN_WARNING "VPE: device %d already in use\n", minor);
967
968                 dvpe();
969                 dump_vpe(v);
970
971                 printk(KERN_WARNING "VPE: re-initialising %d\n", minor);
972
973                 release_progmem(v->load_addr);
974
975                 t = get_tc(minor);
976                 settc(minor);
977                 tmp = read_tc_c0_tcstatus();
978
979                 /* mark not allocated and not dynamically allocatable */
980                 tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
981                 tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
982                 write_tc_c0_tcstatus(tmp);
983
984                 write_tc_c0_tchalt(TCHALT_H);
985
986         }
987
988         // allocate it so when we get write ops we know it's expected.
989         v->state = VPE_STATE_INUSE;
990
991         /* this of-course trashes what was there before... */
992         v->pbuffer = vmalloc(P_SIZE);
993         v->plen = P_SIZE;
994         v->load_addr = NULL;
995         v->len = 0;
996
997         return 0;
998 }
999
1000 static int vpe_release(struct inode *inode, struct file *filp)
1001 {
1002         int minor, ret = 0;
1003         vpe_t *v;
1004         Elf_Ehdr *hdr;
1005
1006         minor = MINOR(inode->i_rdev);
1007         if ((v = get_vpe(minor)) == NULL)
1008                 return -ENODEV;
1009
1010         // simple case of fire and forget, so tell the VPE to run...
1011
1012         hdr = (Elf_Ehdr *) v->pbuffer;
1013         if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) {
1014                 if (vpe_elfload(v) >= 0)
1015                         vpe_run(v);
1016                 else {
1017                         printk(KERN_WARNING "VPE: ELF load failed.\n");
1018                         ret = -ENOEXEC;
1019                 }
1020         } else {
1021                 printk(KERN_WARNING "VPE: only elf files are supported\n");
1022                 ret = -ENOEXEC;
1023         }
1024
1025         // cleanup any temp buffers
1026         if (v->pbuffer)
1027                 vfree(v->pbuffer);
1028         v->plen = 0;
1029         return ret;
1030 }
1031
1032 static ssize_t vpe_write(struct file *file, const char __user * buffer,
1033                          size_t count, loff_t * ppos)
1034 {
1035         int minor;
1036         size_t ret = count;
1037         vpe_t *v;
1038
1039         minor = MINOR(file->f_dentry->d_inode->i_rdev);
1040         if ((v = get_vpe(minor)) == NULL)
1041                 return -ENODEV;
1042
1043         if (v->pbuffer == NULL) {
1044                 printk(KERN_ERR "vpe_write: no pbuffer\n");
1045                 return -ENOMEM;
1046         }
1047
1048         if ((count + v->len) > v->plen) {
1049                 printk(KERN_WARNING
1050                        "VPE Loader: elf size too big. Perhaps strip uneeded symbols\n");
1051                 return -ENOMEM;
1052         }
1053
1054         count -= copy_from_user(v->pbuffer + v->len, buffer, count);
1055         if (!count) {
1056                 printk("vpe_write: copy_to_user failed\n");
1057                 return -EFAULT;
1058         }
1059
1060         v->len += count;
1061         return ret;
1062 }
1063
1064 static struct file_operations vpe_fops = {
1065         .owner = THIS_MODULE,
1066         .open = vpe_open,
1067         .release = vpe_release,
1068         .write = vpe_write
1069 };
1070
1071 /* module wrapper entry points */
1072 /* give me a vpe */
1073 vpe_handle vpe_alloc(void)
1074 {
1075         int i;
1076         struct vpe *v;
1077
1078         /* find a vpe */
1079         for (i = 1; i < MAX_VPES; i++) {
1080                 if ((v = get_vpe(i)) != NULL) {
1081                         v->state = VPE_STATE_INUSE;
1082                         return v;
1083                 }
1084         }
1085         return NULL;
1086 }
1087
1088 EXPORT_SYMBOL(vpe_alloc);
1089
1090 /* start running from here */
1091 int vpe_start(vpe_handle vpe, unsigned long start)
1092 {
1093         struct vpe *v = vpe;
1094
1095         v->__start = start;
1096         return vpe_run(v);
1097 }
1098
1099 EXPORT_SYMBOL(vpe_start);
1100
1101 /* halt it for now */
1102 int vpe_stop(vpe_handle vpe)
1103 {
1104         struct vpe *v = vpe;
1105         struct tc *t;
1106         unsigned int evpe_flags;
1107
1108         evpe_flags = dvpe();
1109
1110         if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {
1111
1112                 settc(t->index);
1113                 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1114         }
1115
1116         evpe(evpe_flags);
1117
1118         return 0;
1119 }
1120
1121 EXPORT_SYMBOL(vpe_stop);
1122
1123 /* I've done with it thank you */
1124 int vpe_free(vpe_handle vpe)
1125 {
1126         struct vpe *v = vpe;
1127         struct tc *t;
1128         unsigned int evpe_flags;
1129
1130         if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
1131                 return -ENOEXEC;
1132         }
1133
1134         evpe_flags = dvpe();
1135
1136         /* Put MVPE's into 'configuration state' */
1137         write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC);
1138
1139         settc(t->index);
1140         write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1141
1142         /* mark the TC unallocated and halt'ed */
1143         write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
1144         write_tc_c0_tchalt(TCHALT_H);
1145
1146         v->state = VPE_STATE_UNUSED;
1147
1148         write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC);
1149         evpe(evpe_flags);
1150
1151         return 0;
1152 }
1153
1154 EXPORT_SYMBOL(vpe_free);
1155
1156 void *vpe_get_shared(int index)
1157 {
1158         struct vpe *v;
1159
1160         if ((v = get_vpe(index)) == NULL) {
1161                 printk(KERN_WARNING "vpe: invalid vpe index %d\n", index);
1162                 return NULL;
1163         }
1164
1165         return v->shared_ptr;
1166 }
1167
1168 EXPORT_SYMBOL(vpe_get_shared);
1169
1170 static int __init vpe_module_init(void)
1171 {
1172         struct vpe *v = NULL;
1173         struct tc *t;
1174         unsigned long val;
1175         int i;
1176
1177         if (!cpu_has_mipsmt) {
1178                 printk("VPE loader: not a MIPS MT capable processor\n");
1179                 return -ENODEV;
1180         }
1181
1182         if ((major = register_chrdev(VPE_MAJOR, module_name, &vpe_fops) < 0)) {
1183                 printk("VPE loader: unable to register character device\n");
1184                 return -EBUSY;
1185         }
1186
1187         if (major == 0)
1188                 major = VPE_MAJOR;
1189
1190         dmt();
1191         dvpe();
1192
1193         /* Put MVPE's into 'configuration state' */
1194         write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC);
1195
1196         /* dump_mtregs(); */
1197
1198         INIT_LIST_HEAD(&vpecontrol.vpe_list);
1199         INIT_LIST_HEAD(&vpecontrol.tc_list);
1200
1201         val = read_c0_mvpconf0();
1202         for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) {
1203                 t = alloc_tc(i);
1204
1205                 /* VPE's */
1206                 if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) {
1207                         settc(i);
1208
1209                         if ((v = alloc_vpe(i)) == NULL) {
1210                                 printk(KERN_WARNING "VPE: unable to allocate VPE\n");
1211                                 return -ENODEV;
1212                         }
1213
1214                         list_add(&t->tc, &v->tc);       /* add the tc to the list of this vpe's tc's. */
1215
1216                         /* deactivate all but vpe0 */
1217                         if (i != 0) {
1218                                 unsigned long tmp = read_vpe_c0_vpeconf0();
1219
1220                                 tmp &= ~VPECONF0_VPA;
1221
1222                                 /* master VPE */
1223                                 tmp |= VPECONF0_MVP;
1224                                 write_vpe_c0_vpeconf0(tmp);
1225                         }
1226
1227                         /* disable multi-threading with TC's */
1228                         write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
1229
1230                         if (i != 0) {
1231                                 write_vpe_c0_status((read_c0_status() &
1232                                                      ~(ST0_IM | ST0_IE | ST0_KSU))
1233                                                     | ST0_CU0);
1234
1235                                 /* set config to be the same as vpe0, particularly kseg0 coherency alg */
1236                                 write_vpe_c0_config(read_c0_config());
1237                         }
1238
1239                 }
1240
1241                 /* TC's */
1242                 t->pvpe = v;    /* set the parent vpe */
1243
1244                 if (i != 0) {
1245                         unsigned long tmp;
1246
1247                         /* tc 0 will of course be running.... */
1248                         if (i == 0)
1249                                 t->state = TC_STATE_RUNNING;
1250
1251                         settc(i);
1252
1253                         /* bind a TC to each VPE, May as well put all excess TC's
1254                            on the last VPE */
1255                         if (i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1))
1256                                 write_tc_c0_tcbind(read_tc_c0_tcbind() |
1257                                                    ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT));
1258                         else
1259                                 write_tc_c0_tcbind(read_tc_c0_tcbind() | i);
1260
1261                         tmp = read_tc_c0_tcstatus();
1262
1263                         /* mark not allocated and not dynamically allocatable */
1264                         tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1265                         tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
1266                         write_tc_c0_tcstatus(tmp);
1267
1268                         write_tc_c0_tchalt(TCHALT_H);
1269                 }
1270         }
1271
1272         /* release config state */
1273         write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC);
1274
1275         return 0;
1276 }
1277
1278 static void __exit vpe_module_exit(void)
1279 {
1280         struct vpe *v, *n;
1281
1282         list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
1283                 if (v->state != VPE_STATE_UNUSED) {
1284                         release_vpe(v);
1285                 }
1286         }
1287
1288         unregister_chrdev(major, module_name);
1289 }
1290
1291 module_init(vpe_module_init);
1292 module_exit(vpe_module_exit);
1293 MODULE_DESCRIPTION("MIPS VPE Loader");
1294 MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc");
1295 MODULE_LICENSE("GPL");