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