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