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 31 #include <linux/config.h> 32 #include <linux/kernel.h> 33 #include <linux/module.h> 34 #include <linux/fs.h> 35 #include <linux/init.h> 36 #include <asm/uaccess.h> 37 #include <linux/slab.h> 38 #include <linux/list.h> 39 #include <linux/vmalloc.h> 40 #include <linux/elf.h> 41 #include <linux/seq_file.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/processor.h> 53 #include <asm/system.h> 54 #include <asm/vpe.h> 55 #include <asm/kspd.h> 56 57 typedef void *vpe_handle; 58 59 #ifndef ARCH_SHF_SMALL 60 #define ARCH_SHF_SMALL 0 61 #endif 62 63 /* If this is set, the section belongs in the init part of the module */ 64 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) 65 66 static char module_name[] = "vpe"; 67 static int major; 68 69 #ifdef CONFIG_MIPS_APSP_KSPD 70 static struct kspd_notifications kspd_events; 71 static int kspd_events_reqd = 0; 72 #endif 73 74 /* grab the likely amount of memory we will need. */ 75 #ifdef CONFIG_MIPS_VPE_LOADER_TOM 76 #define P_SIZE (2 * 1024 * 1024) 77 #else 78 /* add an overhead to the max kmalloc size for non-striped symbols/etc */ 79 #define P_SIZE (256 * 1024) 80 #endif 81 82 extern unsigned long physical_memsize; 83 84 #define MAX_VPES 16 85 #define VPE_PATH_MAX 256 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 enum vpe_state state; 102 103 /* (device) minor associated with this vpe */ 104 int minor; 105 106 /* elfloader stuff */ 107 void *load_addr; 108 unsigned long len; 109 char *pbuffer; 110 unsigned long plen; 111 unsigned int uid, gid; 112 char cwd[VPE_PATH_MAX]; 113 114 unsigned long __start; 115 116 /* tc's associated with this vpe */ 117 struct list_head tc; 118 119 /* The list of vpe's */ 120 struct list_head list; 121 122 /* shared symbol address */ 123 void *shared_ptr; 124 125 /* the list of who wants to know when something major happens */ 126 struct list_head notify; 127 }; 128 129 struct tc { 130 enum tc_state state; 131 int index; 132 133 /* parent VPE */ 134 struct vpe *pvpe; 135 136 /* The list of TC's with this VPE */ 137 struct list_head tc; 138 139 /* The global list of tc's */ 140 struct list_head list; 141 }; 142 143 struct vpecontrol_ { 144 /* Virtual processing elements */ 145 struct list_head vpe_list; 146 147 /* Thread contexts */ 148 struct list_head tc_list; 149 } vpecontrol; 150 151 static void release_progmem(void *ptr); 152 /* static __attribute_used__ void dump_vpe(struct vpe * v); */ 153 extern void save_gp_address(unsigned int secbase, unsigned int rel); 154 155 /* get the vpe associated with this minor */ 156 struct vpe *get_vpe(int minor) 157 { 158 struct vpe *v; 159 160 if (!cpu_has_mipsmt) 161 return NULL; 162 163 list_for_each_entry(v, &vpecontrol.vpe_list, list) { 164 if (v->minor == minor) 165 return v; 166 } 167 168 return NULL; 169 } 170 171 /* get the vpe associated with this minor */ 172 struct tc *get_tc(int index) 173 { 174 struct tc *t; 175 176 list_for_each_entry(t, &vpecontrol.tc_list, list) { 177 if (t->index == index) 178 return t; 179 } 180 181 return NULL; 182 } 183 184 struct tc *get_tc_unused(void) 185 { 186 struct tc *t; 187 188 list_for_each_entry(t, &vpecontrol.tc_list, list) { 189 if (t->state == TC_STATE_UNUSED) 190 return t; 191 } 192 193 return NULL; 194 } 195 196 /* allocate a vpe and associate it with this minor (or index) */ 197 struct vpe *alloc_vpe(int minor) 198 { 199 struct vpe *v; 200 201 if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) { 202 return NULL; 203 } 204 205 INIT_LIST_HEAD(&v->tc); 206 list_add_tail(&v->list, &vpecontrol.vpe_list); 207 208 INIT_LIST_HEAD(&v->notify); 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 = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { 219 return NULL; 220 } 221 222 INIT_LIST_HEAD(&t->tc); 223 list_add_tail(&t->list, &vpecontrol.tc_list); 224 225 t->index = index; 226 227 return t; 228 } 229 230 /* clean up and free everything */ 231 void release_vpe(struct vpe *v) 232 { 233 list_del(&v->list); 234 if (v->load_addr) 235 release_progmem(v); 236 kfree(v); 237 } 238 239 void dump_mtregs(void) 240 { 241 unsigned long val; 242 243 val = read_c0_config3(); 244 printk("config3 0x%lx MT %ld\n", val, 245 (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT); 246 247 val = read_c0_mvpcontrol(); 248 printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val, 249 (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT, 250 (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT, 251 (val & MVPCONTROL_EVP)); 252 253 val = read_c0_mvpconf0(); 254 printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val, 255 (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT, 256 val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT); 257 } 258 259 /* Find some VPE program space */ 260 static void *alloc_progmem(unsigned long len) 261 { 262 #ifdef CONFIG_MIPS_VPE_LOADER_TOM 263 /* this means you must tell linux to use less memory than you physically have */ 264 return pfn_to_kaddr(max_pfn); 265 #else 266 // simple grab some mem for now 267 return kmalloc(len, GFP_KERNEL); 268 #endif 269 } 270 271 static void release_progmem(void *ptr) 272 { 273 #ifndef CONFIG_MIPS_VPE_LOADER_TOM 274 kfree(ptr); 275 #endif 276 } 277 278 /* Update size with this section: return offset. */ 279 static long get_offset(unsigned long *size, Elf_Shdr * sechdr) 280 { 281 long ret; 282 283 ret = ALIGN(*size, sechdr->sh_addralign ? : 1); 284 *size = ret + sechdr->sh_size; 285 return ret; 286 } 287 288 /* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld 289 might -- code, read-only data, read-write data, small data. Tally 290 sizes, and place the offsets into sh_entsize fields: high bit means it 291 belongs in init. */ 292 static void layout_sections(struct module *mod, const Elf_Ehdr * hdr, 293 Elf_Shdr * sechdrs, const char *secstrings) 294 { 295 static unsigned long const masks[][2] = { 296 /* NOTE: all executable code must be the first section 297 * in this array; otherwise modify the text_size 298 * finder in the two loops below */ 299 {SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL}, 300 {SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL}, 301 {SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL}, 302 {ARCH_SHF_SMALL | SHF_ALLOC, 0} 303 }; 304 unsigned int m, i; 305 306 for (i = 0; i < hdr->e_shnum; i++) 307 sechdrs[i].sh_entsize = ~0UL; 308 309 for (m = 0; m < ARRAY_SIZE(masks); ++m) { 310 for (i = 0; i < hdr->e_shnum; ++i) { 311 Elf_Shdr *s = &sechdrs[i]; 312 313 // || strncmp(secstrings + s->sh_name, ".init", 5) == 0) 314 if ((s->sh_flags & masks[m][0]) != masks[m][0] 315 || (s->sh_flags & masks[m][1]) 316 || s->sh_entsize != ~0UL) 317 continue; 318 s->sh_entsize = get_offset(&mod->core_size, s); 319 } 320 321 if (m == 0) 322 mod->core_text_size = mod->core_size; 323 324 } 325 } 326 327 328 /* from module-elf32.c, but subverted a little */ 329 330 struct mips_hi16 { 331 struct mips_hi16 *next; 332 Elf32_Addr *addr; 333 Elf32_Addr value; 334 }; 335 336 static struct mips_hi16 *mips_hi16_list; 337 static unsigned int gp_offs, gp_addr; 338 339 static int apply_r_mips_none(struct module *me, uint32_t *location, 340 Elf32_Addr v) 341 { 342 return 0; 343 } 344 345 static int apply_r_mips_gprel16(struct module *me, uint32_t *location, 346 Elf32_Addr v) 347 { 348 int rel; 349 350 if( !(*location & 0xffff) ) { 351 rel = (int)v - gp_addr; 352 } 353 else { 354 /* .sbss + gp(relative) + offset */ 355 /* kludge! */ 356 rel = (int)(short)((int)v + gp_offs + 357 (int)(short)(*location & 0xffff) - gp_addr); 358 } 359 360 if( (rel > 32768) || (rel < -32768) ) { 361 printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: " 362 "relative address 0x%x out of range of gp register\n", 363 rel); 364 return -ENOEXEC; 365 } 366 367 *location = (*location & 0xffff0000) | (rel & 0xffff); 368 369 return 0; 370 } 371 372 static int apply_r_mips_pc16(struct module *me, uint32_t *location, 373 Elf32_Addr v) 374 { 375 int rel; 376 rel = (((unsigned int)v - (unsigned int)location)); 377 rel >>= 2; // because the offset is in _instructions_ not bytes. 378 rel -= 1; // and one instruction less due to the branch delay slot. 379 380 if( (rel > 32768) || (rel < -32768) ) { 381 printk(KERN_DEBUG "VPE loader: " 382 "apply_r_mips_pc16: relative address out of range 0x%x\n", rel); 383 return -ENOEXEC; 384 } 385 386 *location = (*location & 0xffff0000) | (rel & 0xffff); 387 388 return 0; 389 } 390 391 static int apply_r_mips_32(struct module *me, uint32_t *location, 392 Elf32_Addr v) 393 { 394 *location += v; 395 396 return 0; 397 } 398 399 static int apply_r_mips_26(struct module *me, uint32_t *location, 400 Elf32_Addr v) 401 { 402 if (v % 4) { 403 printk(KERN_DEBUG "VPE loader: apply_r_mips_26 " 404 " unaligned relocation\n"); 405 return -ENOEXEC; 406 } 407 408 /* 409 * Not desperately convinced this is a good check of an overflow condition 410 * anyway. But it gets in the way of handling undefined weak symbols which 411 * we want to set to zero. 412 * if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { 413 * printk(KERN_ERR 414 * "module %s: relocation overflow\n", 415 * me->name); 416 * return -ENOEXEC; 417 * } 418 */ 419 420 *location = (*location & ~0x03ffffff) | 421 ((*location + (v >> 2)) & 0x03ffffff); 422 return 0; 423 } 424 425 static int apply_r_mips_hi16(struct module *me, uint32_t *location, 426 Elf32_Addr v) 427 { 428 struct mips_hi16 *n; 429 430 /* 431 * We cannot relocate this one now because we don't know the value of 432 * the carry we need to add. Save the information, and let LO16 do the 433 * actual relocation. 434 */ 435 n = kmalloc(sizeof *n, GFP_KERNEL); 436 if (!n) 437 return -ENOMEM; 438 439 n->addr = location; 440 n->value = v; 441 n->next = mips_hi16_list; 442 mips_hi16_list = n; 443 444 return 0; 445 } 446 447 static int apply_r_mips_lo16(struct module *me, uint32_t *location, 448 Elf32_Addr v) 449 { 450 unsigned long insnlo = *location; 451 Elf32_Addr val, vallo; 452 453 /* Sign extend the addend we extract from the lo insn. */ 454 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; 455 456 if (mips_hi16_list != NULL) { 457 struct mips_hi16 *l; 458 459 l = mips_hi16_list; 460 while (l != NULL) { 461 struct mips_hi16 *next; 462 unsigned long insn; 463 464 /* 465 * The value for the HI16 had best be the same. 466 */ 467 if (v != l->value) { 468 printk(KERN_DEBUG "VPE loader: " 469 "apply_r_mips_lo16/hi16: " 470 "inconsistent value information\n"); 471 return -ENOEXEC; 472 } 473 474 /* 475 * Do the HI16 relocation. Note that we actually don't 476 * need to know anything about the LO16 itself, except 477 * where to find the low 16 bits of the addend needed 478 * by the LO16. 479 */ 480 insn = *l->addr; 481 val = ((insn & 0xffff) << 16) + vallo; 482 val += v; 483 484 /* 485 * Account for the sign extension that will happen in 486 * the low bits. 487 */ 488 val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; 489 490 insn = (insn & ~0xffff) | val; 491 *l->addr = insn; 492 493 next = l->next; 494 kfree(l); 495 l = next; 496 } 497 498 mips_hi16_list = NULL; 499 } 500 501 /* 502 * Ok, we're done with the HI16 relocs. Now deal with the LO16. 503 */ 504 val = v + vallo; 505 insnlo = (insnlo & ~0xffff) | (val & 0xffff); 506 *location = insnlo; 507 508 return 0; 509 } 510 511 static int (*reloc_handlers[]) (struct module *me, uint32_t *location, 512 Elf32_Addr v) = { 513 [R_MIPS_NONE] = apply_r_mips_none, 514 [R_MIPS_32] = apply_r_mips_32, 515 [R_MIPS_26] = apply_r_mips_26, 516 [R_MIPS_HI16] = apply_r_mips_hi16, 517 [R_MIPS_LO16] = apply_r_mips_lo16, 518 [R_MIPS_GPREL16] = apply_r_mips_gprel16, 519 [R_MIPS_PC16] = apply_r_mips_pc16 520 }; 521 522 static char *rstrs[] = { 523 [R_MIPS_NONE] = "MIPS_NONE", 524 [R_MIPS_32] = "MIPS_32", 525 [R_MIPS_26] = "MIPS_26", 526 [R_MIPS_HI16] = "MIPS_HI16", 527 [R_MIPS_LO16] = "MIPS_LO16", 528 [R_MIPS_GPREL16] = "MIPS_GPREL16", 529 [R_MIPS_PC16] = "MIPS_PC16" 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 char *r = rstrs[ELF32_R_TYPE(r_info)]; 566 printk(KERN_WARNING "VPE loader: .text+0x%x " 567 "relocation type %s for symbol \"%s\" failed\n", 568 rel[i].r_offset, r ? r : "UNKNOWN", 569 strtab + sym->st_name); 570 return res; 571 } 572 } 573 574 return 0; 575 } 576 577 void save_gp_address(unsigned int secbase, unsigned int rel) 578 { 579 gp_addr = secbase + rel; 580 gp_offs = gp_addr - (secbase & 0xffff0000); 581 } 582 /* end module-elf32.c */ 583 584 585 586 /* Change all symbols so that sh_value encodes the pointer directly. */ 587 static void simplify_symbols(Elf_Shdr * sechdrs, 588 unsigned int symindex, 589 const char *strtab, 590 const char *secstrings, 591 unsigned int nsecs, struct module *mod) 592 { 593 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 594 unsigned long secbase, bssbase = 0; 595 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 596 int size; 597 598 /* find the .bss section for COMMON symbols */ 599 for (i = 0; i < nsecs; i++) { 600 if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) { 601 bssbase = sechdrs[i].sh_addr; 602 break; 603 } 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. 610 st_value is currently size. 611 We want it to have the address of the symbol. */ 612 613 size = sym[i].st_value; 614 sym[i].st_value = bssbase; 615 616 bssbase += size; 617 break; 618 619 case SHN_ABS: 620 /* Don't need to do anything */ 621 break; 622 623 case SHN_UNDEF: 624 /* ret = -ENOENT; */ 625 break; 626 627 case SHN_MIPS_SCOMMON: 628 printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON" 629 "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name, 630 sym[i].st_shndx); 631 // .sbss section 632 break; 633 634 default: 635 secbase = sechdrs[sym[i].st_shndx].sh_addr; 636 637 if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) { 638 save_gp_address(secbase, sym[i].st_value); 639 } 640 641 sym[i].st_value += secbase; 642 break; 643 } 644 } 645 } 646 647 #ifdef DEBUG_ELFLOADER 648 static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex, 649 const char *strtab, struct module *mod) 650 { 651 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 652 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 653 654 printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n); 655 for (i = 1; i < n; i++) { 656 printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i, 657 strtab + sym[i].st_name, sym[i].st_value); 658 } 659 } 660 #endif 661 662 static void dump_tc(struct tc *t) 663 { 664 unsigned long val; 665 666 settc(t->index); 667 printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld " 668 "TCStatus 0x%lx halt 0x%lx\n", 669 t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC, 670 read_tc_c0_tcstatus(), read_tc_c0_tchalt()); 671 672 printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart()); 673 printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind()); 674 675 val = read_c0_vpeconf0(); 676 printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val, 677 (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT); 678 679 printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status()); 680 printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause()); 681 682 printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr()); 683 printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc()); 684 } 685 686 static void dump_tclist(void) 687 { 688 struct tc *t; 689 690 list_for_each_entry(t, &vpecontrol.tc_list, list) { 691 dump_tc(t); 692 } 693 } 694 695 /* We are prepared so configure and start the VPE... */ 696 int vpe_run(struct vpe * v) 697 { 698 struct vpe_notifications *n; 699 unsigned long val, dmt_flag; 700 struct tc *t; 701 702 /* check we are the Master VPE */ 703 val = read_c0_vpeconf0(); 704 if (!(val & VPECONF0_MVP)) { 705 printk(KERN_WARNING 706 "VPE loader: only Master VPE's are allowed to configure MT\n"); 707 return -1; 708 } 709 710 /* disable MT (using dvpe) */ 711 dvpe(); 712 713 if (!list_empty(&v->tc)) { 714 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 715 printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", 716 t->index); 717 return -ENOEXEC; 718 } 719 } else { 720 printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", 721 v->minor); 722 return -ENOEXEC; 723 } 724 725 /* Put MVPE's into 'configuration state' */ 726 set_c0_mvpcontrol(MVPCONTROL_VPC); 727 728 settc(t->index); 729 730 /* should check it is halted, and not activated */ 731 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { 732 printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n", 733 t->index); 734 dump_tclist(); 735 return -ENOEXEC; 736 } 737 738 /* 739 * Disable multi-threaded execution whilst we activate, clear the 740 * halt bit and bound the tc to the other VPE... 741 */ 742 dmt_flag = dmt(); 743 744 /* Write the address we want it to start running from in the TCPC register. */ 745 write_tc_c0_tcrestart((unsigned long)v->__start); 746 write_tc_c0_tccontext((unsigned long)0); 747 /* 748 * Mark the TC as activated, not interrupt exempt and not dynamically 749 * allocatable 750 */ 751 val = read_tc_c0_tcstatus(); 752 val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; 753 write_tc_c0_tcstatus(val); 754 755 write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); 756 757 /* 758 * The sde-kit passes 'memsize' to __start in $a3, so set something 759 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and 760 * DFLT_HEAP_SIZE when you compile your program 761 */ 762 mttgpr(7, physical_memsize); 763 764 765 /* set up VPE1 */ 766 /* 767 * bind the TC to VPE 1 as late as possible so we only have the final 768 * VPE registers to set up, and so an EJTAG probe can trigger on it 769 */ 770 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); 771 772 /* Set up the XTC bit in vpeconf0 to point at our tc */ 773 write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) 774 | (t->index << VPECONF0_XTC_SHIFT)); 775 776 /* enable this VPE */ 777 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); 778 779 /* clear out any left overs from a previous program */ 780 write_vpe_c0_status(0); 781 write_vpe_c0_cause(0); 782 783 /* take system out of configuration state */ 784 clear_c0_mvpcontrol(MVPCONTROL_VPC); 785 786 /* now safe to re-enable multi-threading */ 787 emt(dmt_flag); 788 789 /* set it running */ 790 evpe(EVPE_ENABLE); 791 792 list_for_each_entry(n, &v->notify, list) { 793 n->start(v->minor); 794 } 795 796 return 0; 797 } 798 799 static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, 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 816 if ( (v->__start == 0) || (v->shared_ptr == NULL)) 817 return -1; 818 819 return 0; 820 } 821 822 /* 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 */ 827 int vpe_elfload(struct vpe * v) 828 { 829 Elf_Ehdr *hdr; 830 Elf_Shdr *sechdrs; 831 long err = 0; 832 char *secstrings, *strtab = NULL; 833 unsigned int len, i, symindex = 0, strindex = 0, relocate = 0; 834 struct module mod; // so we can re-use the relocations code 835 836 memset(&mod, 0, sizeof(struct module)); 837 strcpy(mod.name, "VPE loader"); 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 */ 844 if (memcmp(hdr->e_ident, ELFMAG, 4) != 0 845 || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC) 846 || !elf_check_arch(hdr) 847 || hdr->e_shentsize != sizeof(*sechdrs)) { 848 printk(KERN_WARNING 849 "VPE loader: program wrong arch or weird elf version\n"); 850 851 return -ENOEXEC; 852 } 853 854 if (hdr->e_type == ET_REL) 855 relocate = 1; 856 857 if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { 858 printk(KERN_ERR "VPE loader: program length %u truncated\n", 859 len); 860 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 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 } 880 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; 884 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 } 891 } 892 layout_sections(&mod, hdr, sechdrs, secstrings); 893 } 894 895 v->load_addr = alloc_progmem(mod.core_size); 896 memset(v->load_addr, 0, mod.core_size); 897 898 printk("VPE loader: loading to %p\n", v->load_addr); 899 900 if (relocate) { 901 for (i = 0; i < hdr->e_shnum; i++) { 902 void *dest; 903 904 if (!(sechdrs[i].sh_flags & SHF_ALLOC)) 905 continue; 906 907 dest = v->load_addr + sechdrs[i].sh_entsize; 908 909 if (sechdrs[i].sh_type != SHT_NOBITS) 910 memcpy(dest, (void *)sechdrs[i].sh_addr, 911 sechdrs[i].sh_size); 912 /* Update sh_addr to point to copy in image. */ 913 sechdrs[i].sh_addr = (unsigned long)dest; 914 915 printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n", 916 secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr); 917 } 918 919 /* Fix up syms, so that st_value is a pointer to location. */ 920 simplify_symbols(sechdrs, symindex, strtab, secstrings, 921 hdr->e_shnum, &mod); 922 923 /* Now do relocations. */ 924 for (i = 1; i < hdr->e_shnum; i++) { 925 const char *strtab = (char *)sechdrs[strindex].sh_addr; 926 unsigned int info = sechdrs[i].sh_info; 927 928 /* Not a valid relocation section? */ 929 if (info >= hdr->e_shnum) 930 continue; 931 932 /* Don't bother with non-allocated sections */ 933 if (!(sechdrs[info].sh_flags & SHF_ALLOC)) 934 continue; 935 936 if (sechdrs[i].sh_type == SHT_REL) 937 err = apply_relocations(sechdrs, strtab, symindex, i, 938 &mod); 939 else if (sechdrs[i].sh_type == SHT_RELA) 940 err = apply_relocate_add(sechdrs, strtab, symindex, i, 941 &mod); 942 if (err < 0) 943 return err; 944 945 } 946 } else { 947 for (i = 0; i < hdr->e_shnum; i++) { 948 949 /* Internal symbols and strings. */ 950 if (sechdrs[i].sh_type == SHT_SYMTAB) { 951 symindex = i; 952 strindex = sechdrs[i].sh_link; 953 strtab = (char *)hdr + sechdrs[strindex].sh_offset; 954 955 /* mark the symtab's address for when we try to find the 956 magic symbols */ 957 sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; 958 } 959 960 /* filter sections we dont want in the final image */ 961 if (!(sechdrs[i].sh_flags & SHF_ALLOC) || 962 (sechdrs[i].sh_type == SHT_MIPS_REGINFO)) { 963 printk( KERN_DEBUG " ignoring section, " 964 "name %s type %x address 0x%x \n", 965 secstrings + sechdrs[i].sh_name, 966 sechdrs[i].sh_type, sechdrs[i].sh_addr); 967 continue; 968 } 969 970 if (sechdrs[i].sh_addr < (unsigned int)v->load_addr) { 971 printk( KERN_WARNING "VPE loader: " 972 "fully linked image has invalid section, " 973 "name %s type %x address 0x%x, before load " 974 "address of 0x%x\n", 975 secstrings + sechdrs[i].sh_name, 976 sechdrs[i].sh_type, sechdrs[i].sh_addr, 977 (unsigned int)v->load_addr); 978 return -ENOEXEC; 979 } 980 981 printk(KERN_DEBUG " copying section sh_name %s, sh_addr 0x%x " 982 "size 0x%x0 from x%p\n", 983 secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr, 984 sechdrs[i].sh_size, hdr + sechdrs[i].sh_offset); 985 986 if (sechdrs[i].sh_type != SHT_NOBITS) 987 memcpy((void *)sechdrs[i].sh_addr, 988 (char *)hdr + sechdrs[i].sh_offset, 989 sechdrs[i].sh_size); 990 else 991 memset((void *)sechdrs[i].sh_addr, 0, sechdrs[i].sh_size); 992 } 993 } 994 995 /* make sure it's physically written out */ 996 flush_icache_range((unsigned long)v->load_addr, 997 (unsigned long)v->load_addr + v->len); 998 999 if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { 1000 if (v->__start == 0) { 1001 printk(KERN_WARNING "VPE loader: program does not contain " 1002 "a __start symbol\n"); 1003 return -ENOEXEC; 1004 } 1005 1006 if (v->shared_ptr == NULL) 1007 printk(KERN_WARNING "VPE loader: " 1008 "program does not contain vpe_shared symbol.\n" 1009 " Unable to use AMVP (AP/SP) facilities.\n"); 1010 } 1011 1012 printk(" elf loaded\n"); 1013 return 0; 1014 } 1015 1016 __attribute_used__ void dump_vpe(struct vpe * v) 1017 { 1018 struct tc *t; 1019 1020 settc(v->minor); 1021 1022 printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol()); 1023 printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0()); 1024 1025 list_for_each_entry(t, &vpecontrol.tc_list, list) 1026 dump_tc(t); 1027 } 1028 1029 static void cleanup_tc(struct tc *tc) 1030 { 1031 int tmp; 1032 1033 /* Put MVPE's into 'configuration state' */ 1034 set_c0_mvpcontrol(MVPCONTROL_VPC); 1035 1036 settc(tc->index); 1037 tmp = read_tc_c0_tcstatus(); 1038 1039 /* mark not allocated and not dynamically allocatable */ 1040 tmp &= ~(TCSTATUS_A | TCSTATUS_DA); 1041 tmp |= TCSTATUS_IXMT; /* interrupt exempt */ 1042 write_tc_c0_tcstatus(tmp); 1043 1044 write_tc_c0_tchalt(TCHALT_H); 1045 1046 /* bind it to anything other than VPE1 */ 1047 write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE 1048 1049 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1050 } 1051 1052 static int getcwd(char *buff, int size) 1053 { 1054 mm_segment_t old_fs; 1055 int ret; 1056 1057 old_fs = get_fs(); 1058 set_fs(KERNEL_DS); 1059 1060 ret = sys_getcwd(buff,size); 1061 1062 set_fs(old_fs); 1063 1064 return ret; 1065 } 1066 1067 /* checks VPE is unused and gets ready to load program */ 1068 static int vpe_open(struct inode *inode, struct file *filp) 1069 { 1070 int minor, ret; 1071 struct vpe *v; 1072 struct vpe_notifications *not; 1073 1074 /* assume only 1 device at the mo. */ 1075 if ((minor = iminor(inode)) != 1) { 1076 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n"); 1077 return -ENODEV; 1078 } 1079 1080 if ((v = get_vpe(minor)) == NULL) { 1081 printk(KERN_WARNING "VPE loader: unable to get vpe\n"); 1082 return -ENODEV; 1083 } 1084 1085 if (v->state != VPE_STATE_UNUSED) { 1086 dvpe(); 1087 1088 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); 1089 1090 dump_tc(get_tc(minor)); 1091 1092 list_for_each_entry(not, &v->notify, list) { 1093 not->stop(minor); 1094 } 1095 1096 release_progmem(v->load_addr); 1097 cleanup_tc(get_tc(minor)); 1098 } 1099 1100 // allocate it so when we get write ops we know it's expected. 1101 v->state = VPE_STATE_INUSE; 1102 1103 /* this of-course trashes what was there before... */ 1104 v->pbuffer = vmalloc(P_SIZE); 1105 v->plen = P_SIZE; 1106 v->load_addr = NULL; 1107 v->len = 0; 1108 1109 v->uid = filp->f_uid; 1110 v->gid = filp->f_gid; 1111 1112 #ifdef CONFIG_MIPS_APSP_KSPD 1113 /* get kspd to tell us when a syscall_exit happens */ 1114 if (!kspd_events_reqd) { 1115 kspd_notify(&kspd_events); 1116 kspd_events_reqd++; 1117 } 1118 #endif 1119 1120 v->cwd[0] = 0; 1121 ret = getcwd(v->cwd, VPE_PATH_MAX); 1122 if (ret < 0) 1123 printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret); 1124 1125 v->shared_ptr = NULL; 1126 v->__start = 0; 1127 return 0; 1128 } 1129 1130 static int vpe_release(struct inode *inode, struct file *filp) 1131 { 1132 int minor, ret = 0; 1133 struct vpe *v; 1134 Elf_Ehdr *hdr; 1135 1136 minor = iminor(inode); 1137 if ((v = get_vpe(minor)) == NULL) 1138 return -ENODEV; 1139 1140 // simple case of fire and forget, so tell the VPE to run... 1141 1142 hdr = (Elf_Ehdr *) v->pbuffer; 1143 if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) { 1144 if (vpe_elfload(v) >= 0) 1145 vpe_run(v); 1146 else { 1147 printk(KERN_WARNING "VPE loader: ELF load failed.\n"); 1148 ret = -ENOEXEC; 1149 } 1150 } else { 1151 printk(KERN_WARNING "VPE loader: only elf files are supported\n"); 1152 ret = -ENOEXEC; 1153 } 1154 1155 /* It's good to be able to run the SP and if it chokes have a look at 1156 the /dev/rt?. But if we reset the pointer to the shared struct we 1157 loose what has happened. So perhaps if garbage is sent to the vpe 1158 device, use it as a trigger for the reset. Hopefully a nice 1159 executable will be along shortly. */ 1160 if (ret < 0) 1161 v->shared_ptr = NULL; 1162 1163 // cleanup any temp buffers 1164 if (v->pbuffer) 1165 vfree(v->pbuffer); 1166 v->plen = 0; 1167 return ret; 1168 } 1169 1170 static ssize_t vpe_write(struct file *file, const char __user * buffer, 1171 size_t count, loff_t * ppos) 1172 { 1173 int minor; 1174 size_t ret = count; 1175 struct vpe *v; 1176 1177 minor = iminor(file->f_dentry->d_inode); 1178 if ((v = get_vpe(minor)) == NULL) 1179 return -ENODEV; 1180 1181 if (v->pbuffer == NULL) { 1182 printk(KERN_ERR "VPE loader: no buffer for program\n"); 1183 return -ENOMEM; 1184 } 1185 1186 if ((count + v->len) > v->plen) { 1187 printk(KERN_WARNING 1188 "VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); 1189 return -ENOMEM; 1190 } 1191 1192 count -= copy_from_user(v->pbuffer + v->len, buffer, count); 1193 if (!count) 1194 return -EFAULT; 1195 1196 v->len += count; 1197 return ret; 1198 } 1199 1200 static struct file_operations vpe_fops = { 1201 .owner = THIS_MODULE, 1202 .open = vpe_open, 1203 .release = vpe_release, 1204 .write = vpe_write 1205 }; 1206 1207 /* module wrapper entry points */ 1208 /* give me a vpe */ 1209 vpe_handle vpe_alloc(void) 1210 { 1211 int i; 1212 struct vpe *v; 1213 1214 /* find a vpe */ 1215 for (i = 1; i < MAX_VPES; i++) { 1216 if ((v = get_vpe(i)) != NULL) { 1217 v->state = VPE_STATE_INUSE; 1218 return v; 1219 } 1220 } 1221 return NULL; 1222 } 1223 1224 EXPORT_SYMBOL(vpe_alloc); 1225 1226 /* start running from here */ 1227 int vpe_start(vpe_handle vpe, unsigned long start) 1228 { 1229 struct vpe *v = vpe; 1230 1231 v->__start = start; 1232 return vpe_run(v); 1233 } 1234 1235 EXPORT_SYMBOL(vpe_start); 1236 1237 /* halt it for now */ 1238 int vpe_stop(vpe_handle vpe) 1239 { 1240 struct vpe *v = vpe; 1241 struct tc *t; 1242 unsigned int evpe_flags; 1243 1244 evpe_flags = dvpe(); 1245 1246 if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) { 1247 1248 settc(t->index); 1249 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); 1250 } 1251 1252 evpe(evpe_flags); 1253 1254 return 0; 1255 } 1256 1257 EXPORT_SYMBOL(vpe_stop); 1258 1259 /* I've done with it thank you */ 1260 int vpe_free(vpe_handle vpe) 1261 { 1262 struct vpe *v = vpe; 1263 struct tc *t; 1264 unsigned int evpe_flags; 1265 1266 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 1267 return -ENOEXEC; 1268 } 1269 1270 evpe_flags = dvpe(); 1271 1272 /* Put MVPE's into 'configuration state' */ 1273 set_c0_mvpcontrol(MVPCONTROL_VPC); 1274 1275 settc(t->index); 1276 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); 1277 1278 /* mark the TC unallocated and halt'ed */ 1279 write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A); 1280 write_tc_c0_tchalt(TCHALT_H); 1281 1282 v->state = VPE_STATE_UNUSED; 1283 1284 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1285 evpe(evpe_flags); 1286 1287 return 0; 1288 } 1289 1290 EXPORT_SYMBOL(vpe_free); 1291 1292 void *vpe_get_shared(int index) 1293 { 1294 struct vpe *v; 1295 1296 if ((v = get_vpe(index)) == NULL) 1297 return NULL; 1298 1299 return v->shared_ptr; 1300 } 1301 1302 EXPORT_SYMBOL(vpe_get_shared); 1303 1304 int vpe_getuid(int index) 1305 { 1306 struct vpe *v; 1307 1308 if ((v = get_vpe(index)) == NULL) 1309 return -1; 1310 1311 return v->uid; 1312 } 1313 1314 EXPORT_SYMBOL(vpe_getuid); 1315 1316 int vpe_getgid(int index) 1317 { 1318 struct vpe *v; 1319 1320 if ((v = get_vpe(index)) == NULL) 1321 return -1; 1322 1323 return v->gid; 1324 } 1325 1326 EXPORT_SYMBOL(vpe_getgid); 1327 1328 int vpe_notify(int index, struct vpe_notifications *notify) 1329 { 1330 struct vpe *v; 1331 1332 if ((v = get_vpe(index)) == NULL) 1333 return -1; 1334 1335 list_add(¬ify->list, &v->notify); 1336 return 0; 1337 } 1338 1339 EXPORT_SYMBOL(vpe_notify); 1340 1341 char *vpe_getcwd(int index) 1342 { 1343 struct vpe *v; 1344 1345 if ((v = get_vpe(index)) == NULL) 1346 return NULL; 1347 1348 return v->cwd; 1349 } 1350 1351 EXPORT_SYMBOL(vpe_getcwd); 1352 1353 #ifdef CONFIG_MIPS_APSP_KSPD 1354 static void kspd_sp_exit( int sp_id) 1355 { 1356 cleanup_tc(get_tc(sp_id)); 1357 } 1358 #endif 1359 1360 static int __init vpe_module_init(void) 1361 { 1362 struct vpe *v = NULL; 1363 struct tc *t; 1364 unsigned long val; 1365 int i; 1366 1367 if (!cpu_has_mipsmt) { 1368 printk("VPE loader: not a MIPS MT capable processor\n"); 1369 return -ENODEV; 1370 } 1371 1372 major = register_chrdev(0, module_name, &vpe_fops); 1373 if (major < 0) { 1374 printk("VPE loader: unable to register character device\n"); 1375 return major; 1376 } 1377 1378 dmt(); 1379 dvpe(); 1380 1381 /* Put MVPE's into 'configuration state' */ 1382 set_c0_mvpcontrol(MVPCONTROL_VPC); 1383 1384 /* dump_mtregs(); */ 1385 1386 INIT_LIST_HEAD(&vpecontrol.vpe_list); 1387 INIT_LIST_HEAD(&vpecontrol.tc_list); 1388 1389 val = read_c0_mvpconf0(); 1390 for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) { 1391 t = alloc_tc(i); 1392 1393 /* VPE's */ 1394 if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) { 1395 settc(i); 1396 1397 if ((v = alloc_vpe(i)) == NULL) { 1398 printk(KERN_WARNING "VPE: unable to allocate VPE\n"); 1399 return -ENODEV; 1400 } 1401 1402 /* add the tc to the list of this vpe's tc's. */ 1403 list_add(&t->tc, &v->tc); 1404 1405 /* deactivate all but vpe0 */ 1406 if (i != 0) { 1407 unsigned long tmp = read_vpe_c0_vpeconf0(); 1408 1409 tmp &= ~VPECONF0_VPA; 1410 1411 /* master VPE */ 1412 tmp |= VPECONF0_MVP; 1413 write_vpe_c0_vpeconf0(tmp); 1414 } 1415 1416 /* disable multi-threading with TC's */ 1417 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); 1418 1419 if (i != 0) { 1420 write_vpe_c0_status((read_c0_status() & 1421 ~(ST0_IM | ST0_IE | ST0_KSU)) 1422 | ST0_CU0); 1423 1424 /* 1425 * Set config to be the same as vpe0, 1426 * particularly kseg0 coherency alg 1427 */ 1428 write_vpe_c0_config(read_c0_config()); 1429 } 1430 } 1431 1432 /* TC's */ 1433 t->pvpe = v; /* set the parent vpe */ 1434 1435 if (i != 0) { 1436 unsigned long tmp; 1437 1438 settc(i); 1439 1440 /* Any TC that is bound to VPE0 gets left as is - in case 1441 we are running SMTC on VPE0. A TC that is bound to any 1442 other VPE gets bound to VPE0, ideally I'd like to make 1443 it homeless but it doesn't appear to let me bind a TC 1444 to a non-existent VPE. Which is perfectly reasonable. 1445 1446 The (un)bound state is visible to an EJTAG probe so may 1447 notify GDB... 1448 */ 1449 1450 if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) { 1451 /* tc is bound >vpe0 */ 1452 write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE); 1453 1454 t->pvpe = get_vpe(0); /* set the parent vpe */ 1455 } 1456 1457 tmp = read_tc_c0_tcstatus(); 1458 1459 /* mark not activated and not dynamically allocatable */ 1460 tmp &= ~(TCSTATUS_A | TCSTATUS_DA); 1461 tmp |= TCSTATUS_IXMT; /* interrupt exempt */ 1462 write_tc_c0_tcstatus(tmp); 1463 1464 write_tc_c0_tchalt(TCHALT_H); 1465 } 1466 } 1467 1468 /* release config state */ 1469 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1470 1471 #ifdef CONFIG_MIPS_APSP_KSPD 1472 kspd_events.kspd_sp_exit = kspd_sp_exit; 1473 #endif 1474 return 0; 1475 } 1476 1477 static void __exit vpe_module_exit(void) 1478 { 1479 struct vpe *v, *n; 1480 1481 list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) { 1482 if (v->state != VPE_STATE_UNUSED) { 1483 release_vpe(v); 1484 } 1485 } 1486 1487 unregister_chrdev(major, module_name); 1488 } 1489 1490 module_init(vpe_module_init); 1491 module_exit(vpe_module_exit); 1492 MODULE_DESCRIPTION("MIPS VPE Loader"); 1493 MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); 1494 MODULE_LICENSE("GPL"); 1495