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