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