/* Update size with this section: return offset. */ staticlong get_offset(unsignedlong *size, Elf_Shdr *sechdr)
{ long ret;
ret = ALIGN(*size, sechdr->sh_addralign ? : 1);
*size = ret + sechdr->sh_size; return ret;
}
/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld might--code,read-onlydata,read-writedata,smalldata.Tally sizes,andplacetheoffsetsintosh_entsizefields:highbitmeansit
belongs in init. */ staticvoid layout_sections(struct module *mod, const Elf_Ehdr *hdr,
Elf_Shdr *sechdrs, constchar *secstrings)
{ staticunsignedlongconst masks[][2] = { /* NOTE: all executable code must be the first section *inthisarray;otherwisemodifythetext_size
* finder in the two loops below */
{SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL},
{SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL},
{SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL},
{ARCH_SHF_SMALL | SHF_ALLOC, 0}
}; unsignedint m, i;
for (i = 0; i < hdr->e_shnum; i++)
sechdrs[i].sh_entsize = ~0UL;
for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < hdr->e_shnum; ++i) {
Elf_Shdr *s = &sechdrs[i]; struct module_memory *mod_mem;
if ((rel > 32768) || (rel < -32768)) {
pr_debug("VPE loader: apply_r_mips_gprel16: relative address 0x%x out of range of gp register\n",
rel); return -ENOEXEC;
}
staticint apply_r_mips_pc16(struct module *me, uint32_t *location,
Elf32_Addr v)
{ int rel;
rel = (((unsignedint)v - (unsignedint)location));
rel >>= 2; /* because the offset is in _instructions_ not bytes. */
rel -= 1; /* and one instruction less due to the branch delay slot. */
if ((rel > 32768) || (rel < -32768)) {
pr_debug("VPE loader: apply_r_mips_pc16: relative address out of range 0x%x\n",
rel); return -ENOEXEC;
}
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) {
pr_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)];
pr_warn("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;
}
}
/* Change all symbols so that sh_value encodes the pointer directly. */ staticvoid simplify_symbols(Elf_Shdr *sechdrs, unsignedint symindex, constchar *strtab, constchar *secstrings, unsignedint nsecs, struct module *mod)
{
Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; unsignedlong secbase, bssbase = 0; unsignedint 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_valueiscurrentlysize.
We want it to have the address of the symbol. */
pr_debug("dump_elfsymbols: n %d\n", n); for (i = 1; i < n; i++) {
pr_debug(" i %d name <%s> 0x%x\n", i, strtab + sym[i].st_name,
sym[i].st_value);
}
} #endif
v->load_addr = alloc_progmem(mod.mem[MOD_TEXT].size); if (!v->load_addr) return -ENOMEM;
pr_info("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 = (unsignedlong)dest;
/* 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++) { constchar *strtab = (char *)sechdrs[strindex].sh_addr; unsignedint 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); elseif (sechdrs[i].sh_type == SHT_RELA)
err = apply_relocate_add(sechdrs, strtab,
symindex, i, &mod); if (err < 0) return err;
/* make sure it's physically written out */
flush_icache_range((unsignedlong)v->load_addr,
(unsignedlong)v->load_addr + v->len);
if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { if (v->__start == 0) {
pr_warn("VPE loader: program does not contain a __start symbol\n"); return -ENOEXEC;
}
if (v->shared_ptr == NULL)
pr_warn("VPE loader: program does not contain vpe_shared symbol.\n" " Unable to use AMVP (AP/SP) facilities.\n");
}
pr_info(" elf loaded\n"); return0;
}
/* checks VPE is unused and gets ready to load program */ staticint vpe_open(struct inode *inode, struct file *filp)
{ enum vpe_state state; struct vpe_notifications *notifier; struct vpe *v;
if (VPE_MODULE_MINOR != iminor(inode)) { /* assume only 1 device at the moment. */
pr_warn("VPE loader: only vpe1 is supported\n");
return -ENODEV;
}
v = get_vpe(aprp_cpu_index()); if (v == NULL) {
pr_warn("VPE loader: unable to get vpe\n");
return -ENODEV;
}
state = xchg(&v->state, VPE_STATE_INUSE); if (state != VPE_STATE_UNUSED) {
pr_debug("VPE loader: tc in use dumping regs\n");
/* this of-course trashes what was there before... */
v->pbuffer = vmalloc(P_SIZE); if (!v->pbuffer) {
pr_warn("VPE loader: unable to allocate memory\n"); return -ENOMEM;
}
v->plen = P_SIZE;
v->load_addr = NULL;
v->len = 0;
v->shared_ptr = NULL;
v->__start = 0;
return0;
}
staticint vpe_release(struct inode *inode, struct file *filp)
{ #ifdef CONFIG_MIPS_VPE_LOADER_MT struct vpe *v;
Elf_Ehdr *hdr; int ret = 0;
v = get_vpe(aprp_cpu_index()); if (v == NULL) return -ENODEV;
hdr = (Elf_Ehdr *) v->pbuffer; if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { if (vpe_elfload(v) >= 0) {
vpe_run(v);
} else {
pr_warn("VPE loader: ELF load failed.\n");
ret = -ENOEXEC;
}
} else {
pr_warn("VPE loader: only elf files are supported\n");
ret = -ENOEXEC;
}
/* It's good to be able to run the SP and if it chokes have a look at the/dev/rt?.Butifweresetthepointertothesharedstructwe losewhathashappened.Soperhapsifgarbageissenttothevpe device,useitasatriggerforthereset.Hopefullyanice
executable will be along shortly. */ if (ret < 0)
v->shared_ptr = NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.