📄 vpe.c
字号:
/* * Ok, we're done with the HI16 relocs. Now deal with the LO16. */ val = v + vallo; insnlo = (insnlo & ~0xffff) | (val & 0xffff); *location = insnlo; return 0;}static int (*reloc_handlers[]) (struct module *me, uint32_t *location, Elf32_Addr v) = { [R_MIPS_NONE] = apply_r_mips_none, [R_MIPS_32] = apply_r_mips_32, [R_MIPS_26] = apply_r_mips_26, [R_MIPS_HI16] = apply_r_mips_hi16, [R_MIPS_LO16] = apply_r_mips_lo16, [R_MIPS_GPREL16] = apply_r_mips_gprel16, [R_MIPS_PC16] = apply_r_mips_pc16};static char *rstrs[] = { [R_MIPS_NONE] = "MIPS_NONE", [R_MIPS_32] = "MIPS_32", [R_MIPS_26] = "MIPS_26", [R_MIPS_HI16] = "MIPS_HI16", [R_MIPS_LO16] = "MIPS_LO16", [R_MIPS_GPREL16] = "MIPS_GPREL16", [R_MIPS_PC16] = "MIPS_PC16"};int apply_relocations(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me){ Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr; Elf32_Sym *sym; uint32_t *location; unsigned int i; Elf32_Addr v; int res; for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { Elf32_Word r_info = rel[i].r_info; /* This is where to make the change */ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; /* This is the symbol it is referring to */ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + ELF32_R_SYM(r_info); if (!sym->st_value) { printk(KERN_DEBUG "%s: undefined weak symbol %s\n", me->name, strtab + sym->st_name); /* just print the warning, dont barf */ } v = sym->st_value; res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v); if( res ) { char *r = rstrs[ELF32_R_TYPE(r_info)]; printk(KERN_WARNING "VPE loader: .text+0x%x " "relocation type %s for symbol \"%s\" failed\n", rel[i].r_offset, r ? r : "UNKNOWN", strtab + sym->st_name); return res; } } return 0;}void save_gp_address(unsigned int secbase, unsigned int rel){ gp_addr = secbase + rel; gp_offs = gp_addr - (secbase & 0xffff0000);}/* end module-elf32.c *//* Change all symbols so that sh_value encodes the pointer directly. */static void simplify_symbols(Elf_Shdr * sechdrs, unsigned int symindex, const char *strtab, const char *secstrings, unsigned int nsecs, struct module *mod){ Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; unsigned long secbase, bssbase = 0; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); int size; /* find the .bss section for COMMON symbols */ for (i = 0; i < nsecs; i++) { if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) { bssbase = sechdrs[i].sh_addr; break; } } for (i = 1; i < n; i++) { switch (sym[i].st_shndx) { case SHN_COMMON: /* Allocate space for the symbol in the .bss section. st_value is currently size. We want it to have the address of the symbol. */ size = sym[i].st_value; sym[i].st_value = bssbase; bssbase += size; break; case SHN_ABS: /* Don't need to do anything */ break; case SHN_UNDEF: /* ret = -ENOENT; */ break; case SHN_MIPS_SCOMMON: printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON" "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name, sym[i].st_shndx); // .sbss section break; default: secbase = sechdrs[sym[i].st_shndx].sh_addr; if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) { save_gp_address(secbase, sym[i].st_value); } sym[i].st_value += secbase; break; } }}#ifdef DEBUG_ELFLOADERstatic void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex, const char *strtab, struct module *mod){ Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n); for (i = 1; i < n; i++) { printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i, strtab + sym[i].st_name, sym[i].st_value); }}#endifstatic void dump_tc(struct tc *t){ unsigned long val; settc(t->index); printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld " "TCStatus 0x%lx halt 0x%lx\n", t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC, read_tc_c0_tcstatus(), read_tc_c0_tchalt()); printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart()); printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind()); val = read_c0_vpeconf0(); printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val, (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT); printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status()); printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause()); printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr()); printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc());}static void dump_tclist(void){ struct tc *t; list_for_each_entry(t, &vpecontrol.tc_list, list) { dump_tc(t); }}/* We are prepared so configure and start the VPE... */int vpe_run(struct vpe * v){ struct vpe_notifications *n; unsigned long val, dmt_flag; struct tc *t; /* check we are the Master VPE */ val = read_c0_vpeconf0(); if (!(val & VPECONF0_MVP)) { printk(KERN_WARNING "VPE loader: only Master VPE's are allowed to configure MT\n"); return -1; } /* disable MT (using dvpe) */ dvpe(); if (!list_empty(&v->tc)) { if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", t->index); return -ENOEXEC; } } else { printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", v->minor); return -ENOEXEC; } /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); settc(t->index); /* should check it is halted, and not activated */ if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n", t->index); dump_tclist(); return -ENOEXEC; } /* * Disable multi-threaded execution whilst we activate, clear the * halt bit and bound the tc to the other VPE... */ dmt_flag = dmt(); /* Write the address we want it to start running from in the TCPC register. */ write_tc_c0_tcrestart((unsigned long)v->__start); write_tc_c0_tccontext((unsigned long)0); /* * Mark the TC as activated, not interrupt exempt and not dynamically * allocatable */ val = read_tc_c0_tcstatus(); val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; write_tc_c0_tcstatus(val); write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); /* * The sde-kit passes 'memsize' to __start in $a3, so set something * here... Or set $a3 to zero and define DFLT_STACK_SIZE and * DFLT_HEAP_SIZE when you compile your program */ mttgpr(7, physical_memsize); /* set up VPE1 */ /* * bind the TC to VPE 1 as late as possible so we only have the final * VPE registers to set up, and so an EJTAG probe can trigger on it */ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); /* Set up the XTC bit in vpeconf0 to point at our tc */ write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) | (t->index << VPECONF0_XTC_SHIFT)); /* enable this VPE */ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); /* clear out any left overs from a previous program */ write_vpe_c0_status(0); write_vpe_c0_cause(0); /* take system out of configuration state */ clear_c0_mvpcontrol(MVPCONTROL_VPC); /* now safe to re-enable multi-threading */ emt(dmt_flag); /* set it running */ evpe(EVPE_ENABLE); list_for_each_entry(n, &v->notify, list) { n->start(v->minor); } return 0;}static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, unsigned int symindex, const char *strtab, struct module *mod){ Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); for (i = 1; i < n; i++) { if (strcmp(strtab + sym[i].st_name, "__start") == 0) { v->__start = sym[i].st_value; } if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) { v->shared_ptr = (void *)sym[i].st_value; } } if ( (v->__start == 0) || (v->shared_ptr == NULL)) return -1; return 0;}/* * Allocates a VPE with some program code space(the load address), copies the * contents of the program (p)buffer performing relocatations/etc, free's it * when finished. */int vpe_elfload(struct vpe * v){ Elf_Ehdr *hdr; Elf_Shdr *sechdrs; long err = 0; char *secstrings, *strtab = NULL; unsigned int len, i, symindex = 0, strindex = 0, relocate = 0; struct module mod; // so we can re-use the relocations code memset(&mod, 0, sizeof(struct module)); strcpy(mod.name, "VPE loader"); hdr = (Elf_Ehdr *) v->pbuffer; len = v->plen; /* Sanity checks against insmoding binaries or wrong arch, weird elf version */ if (memcmp(hdr->e_ident, ELFMAG, 4) != 0 || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC) || !elf_check_arch(hdr) || hdr->e_shentsize != sizeof(*sechdrs)) { printk(KERN_WARNING "VPE loader: program wrong arch or weird elf version\n"); return -ENOEXEC; } if (hdr->e_type == ET_REL) relocate = 1; if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { printk(KERN_ERR "VPE loader: program length %u truncated\n", len); return -ENOEXEC; } /* Convenience variables */ sechdrs = (void *)hdr + hdr->e_shoff; secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; sechdrs[0].sh_addr = 0; /* And these should exist, but gcc whinges if we don't init them */ symindex = strindex = 0; if (relocate) { for (i = 1; i < hdr->e_shnum; i++) { if (sechdrs[i].sh_type != SHT_NOBITS && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) { printk(KERN_ERR "VPE program length %u truncated\n", len); return -ENOEXEC; } /* Mark all sections sh_addr with their address in the temporary image. */ sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; /* Internal symbols and strings. */ if (sechdrs[i].sh_type == SHT_SYMTAB) { symindex = i; strindex = sechdrs[i].sh_link; strtab = (char *)hdr + sechdrs[strindex].sh_offset; } } layout_sections(&mod, hdr, sechdrs, secstrings); } v->load_addr = alloc_progmem(mod.core_size); memset(v->load_addr, 0, mod.core_size); printk("VPE loader: loading to %p\n", v->load_addr); if (relocate) { for (i = 0; i < hdr->e_shnum; i++) { void *dest; if (!(sechdrs[i].sh_flags & SHF_ALLOC)) continue; dest = v->load_addr + sechdrs[i].sh_entsize; if (sechdrs[i].sh_type != SHT_NOBITS) memcpy(dest, (void *)sechdrs[i].sh_addr, sechdrs[i].sh_size); /* Update sh_addr to point to copy in image. */ sechdrs[i].sh_addr = (unsigned long)dest; printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n", secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr); } /* Fix up syms, so that st_value is a pointer to location. */ simplify_symbols(sechdrs, symindex, strtab, secstrings, hdr->e_shnum, &mod); /* Now do relocations. */ for (i = 1; i < hdr->e_shnum; i++) { const char *strtab = (char *)sechdrs[strindex].sh_addr; unsigned int info = sechdrs[i].sh_info; /* Not a valid relocation section? */ if (info >= hdr->e_shnum) continue; /* Don't bother with non-allocated sections */ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) continue; if (sechdrs[i].sh_type == SHT_REL) err = apply_relocations(sechdrs, strtab, symindex, i, &mod); else if (sechdrs[i].sh_type == SHT_RELA) err = apply_relocate_add(sechdrs, strtab, symindex, i, &mod); if (err < 0) return err; } } else { for (i = 0; i < hdr->e_shnum; i++) { /* Internal symbols and strings. */ if (sechdrs[i].sh_type == SHT_SYMTAB) { symindex = i; strindex = sechdrs[i].sh_link; strtab = (char *)hdr + sechdrs[strindex].sh_offset; /* mark the symtab's address for when we try to find the magic symbols */ sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; } /* filter sections we dont want in the final image */ if (!(sechdrs[i].sh_flags & SHF_ALLOC) || (sechdrs[i].sh_type == SHT_MIPS_REGINFO)) { printk( KERN_DEBUG " ignoring section, " "name %s type %x address 0x%x \n", secstrings + sechdrs[i].sh_name, sechdrs[i].sh_type, sechdrs[i].sh_addr); continue; } if (sechdrs[i].sh_addr < (unsigned int)v->load_addr) { printk( KERN_WARNING "VPE loader: " "fully linked image has invalid section, " "name %s type %x address 0x%x, before load " "address of 0x%x\n", secstrings + sechdrs[i].sh_name, sechdrs[i].sh_type, sechdrs[i].sh_addr, (unsigned int)v->load_addr); return -ENOEXEC; } printk(KERN_DEBUG " copying section sh_name %s, sh_addr 0x%x " "size 0x%x0 from x%p\n", secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr, sechdrs[i].sh_size, hdr + sechdrs[i].sh_offset); if (sechdrs[i].sh_type != SHT_NOBITS) memcpy((void *)sechdrs[i].sh_addr, (char *)hdr + sechdrs[i].sh_offset, sechdrs[i].sh_size); else memset((void *)sechdrs[i].sh_addr, 0, sechdrs[i].sh_size); } } /* make sure it's physically written out */ flush_icache_range((unsigned long)v->load_addr, (unsigned long)v->load_addr + v->len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -