30 #include <linux/kernel.h>
31 #include <linux/device.h>
34 #include <asm/uaccess.h>
35 #include <linux/slab.h>
36 #include <linux/list.h>
38 #include <linux/elf.h>
43 #include <linux/poll.h>
47 #include <asm/cacheflush.h>
51 #include <asm/processor.h>
56 #ifndef ARCH_SHF_SMALL
57 #define ARCH_SHF_SMALL 0
61 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
66 static int hw_tcs, hw_vpes;
69 static const int minor = 1;
72 #ifdef CONFIG_MIPS_VPE_LOADER_TOM
73 #define P_SIZE (2 * 1024 * 1024)
76 #define P_SIZE (256 * 1024)
82 #define VPE_PATH_MAX 256
149 static void release_progmem(
void *
ptr);
152 static struct vpe *get_vpe(
int minor)
162 if (v->
minor == minor) {
173 static struct tc *get_tc(
int index)
180 if (t->
index == index) {
191 static struct vpe *alloc_vpe(
int minor)
198 INIT_LIST_HEAD(&v->
tc);
203 INIT_LIST_HEAD(&v->
notify);
210 static struct tc *alloc_tc(
int index)
217 INIT_LIST_HEAD(&tc->
tc);
229 static void release_vpe(
struct vpe *v)
242 printk(
"config3 0x%lx MT %ld\n", val,
246 printk(
"MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
252 printk(
"mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
258 static void *alloc_progmem(
unsigned long len)
262 #ifdef CONFIG_MIPS_VPE_LOADER_TOM
277 static void release_progmem(
void *
ptr)
279 #ifndef CONFIG_MIPS_VPE_LOADER_TOM
285 static long get_offset(
unsigned long *
size,
Elf_Shdr * sechdr)
289 ret =
ALIGN(*size, sechdr->sh_addralign ? : 1);
290 *size = ret + sechdr->sh_size;
299 Elf_Shdr * sechdrs,
const char *secstrings)
301 static unsigned long const masks[][2] = {
312 for (i = 0; i < hdr->e_shnum; i++)
313 sechdrs[i].sh_entsize = ~0
UL;
316 for (i = 0; i < hdr->e_shnum; ++
i) {
320 if ((s->sh_flags & masks[m][0]) != masks[
m][0]
321 || (s->sh_flags & masks[
m][1])
322 || s->sh_entsize != ~0
UL)
325 get_offset((
unsigned long *)&mod->core_size, s);
329 mod->core_text_size = mod->core_size;
344 static unsigned int gp_offs, gp_addr;
357 if( !(*location & 0xffff) ) {
358 rel = (
int)v - gp_addr;
363 rel = (
int)(
short)((
int)v + gp_offs +
364 (
int)(
short)(*location & 0xffff) - gp_addr);
367 if( (rel > 32768) || (rel < -32768) ) {
369 "relative address 0x%x out of range of gp register\n",
374 *location = (*location & 0xffff0000) | (rel & 0xffff);
379 static int apply_r_mips_pc16(
struct module *me,
uint32_t *location,
383 rel = (((
unsigned int)v - (
unsigned int)
location));
387 if( (rel > 32768) || (rel < -32768) ) {
389 "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
393 *location = (*location & 0xffff0000) | (rel & 0xffff);
411 " unaligned relocation\n");
427 *location = (*location & ~0x03ffffff) |
428 ((*location + (v >> 2)) & 0x03ffffff);
432 static int apply_r_mips_hi16(
struct module *me,
uint32_t *location,
448 n->
next = mips_hi16_list;
454 static int apply_r_mips_lo16(
struct module *me,
uint32_t *location,
462 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
464 if (mips_hi16_list !=
NULL) {
475 "apply_r_mips_lo16/hi16: \t"
476 "inconsistent value information\n");
487 val = ((insn & 0xffff) << 16) + vallo;
494 val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
496 insn = (insn & ~0xffff) | val;
504 mips_hi16_list =
NULL;
511 insnlo = (insnlo & ~0xffff) | (val & 0xffff);
522 mips_hi16_list =
NULL;
538 static char *rstrs[] = {
548 static int apply_relocations(
Elf32_Shdr *sechdrs,
550 unsigned int symindex,
554 Elf32_Rel *rel = (
void *) sechdrs[relsec].sh_addr;
561 for (i = 0; i < sechdrs[relsec].
sh_size /
sizeof(*rel); i++) {
565 location = (
void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
568 sym = (
Elf32_Sym *)sechdrs[symindex].sh_addr
583 "relocation type %s for symbol \"%s\" failed\n",
593 static inline void save_gp_address(
unsigned int secbase,
unsigned int rel)
595 gp_addr = secbase + rel;
596 gp_offs = gp_addr - (secbase & 0xffff0000);
603 static void simplify_symbols(
Elf_Shdr * sechdrs,
604 unsigned int symindex,
606 const char *secstrings,
609 Elf_Sym *sym = (
void *)sechdrs[symindex].sh_addr;
610 unsigned long secbase, bssbase = 0;
611 unsigned int i, n = sechdrs[symindex].sh_size /
sizeof(
Elf_Sym);
615 for (i = 0; i <
nsecs; i++) {
616 if (
strncmp(secstrings + sechdrs[i].sh_name,
".bss", 4) == 0) {
617 bssbase = sechdrs[
i].sh_addr;
622 for (i = 1; i <
n; i++) {
623 switch (sym[i].st_shndx) {
629 size = sym[
i].st_value;
630 sym[
i].st_value = bssbase;
645 "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
651 secbase = sechdrs[sym[
i].st_shndx].sh_addr;
653 if (
strncmp(strtab + sym[i].st_name,
"_gp", 3) == 0) {
654 save_gp_address(secbase, sym[i].st_value);
657 sym[
i].st_value += secbase;
663 #ifdef DEBUG_ELFLOADER
664 static void dump_elfsymbols(
Elf_Shdr * sechdrs,
unsigned int symindex,
665 const char *strtab,
struct module *mod)
667 Elf_Sym *sym = (
void *)sechdrs[symindex].sh_addr;
668 unsigned int i, n = sechdrs[symindex].sh_size /
sizeof(
Elf_Sym);
671 for (i = 1; i <
n; i++) {
673 strtab + sym[i].st_name, sym[i].st_value);
679 static int vpe_run(
struct vpe * v)
683 unsigned int vpeflags;
691 "VPE loader: only Master VPE's are allowed to configure MT\n");
700 if (!list_empty(&v->
tc)) {
707 "VPE loader: TC %d is already in use.\n",
717 "VPE loader: No TC's associated with VPE %d\n",
724 set_c0_mvpcontrol(MVPCONTROL_VPC);
771 back_to_back_c0_hazard();
777 back_to_back_c0_hazard();
787 clear_c0_mvpcontrol(MVPCONTROL_VPC);
809 unsigned int symindex,
const char *strtab,
812 Elf_Sym *sym = (
void *)sechdrs[symindex].sh_addr;
813 unsigned int i, n = sechdrs[symindex].sh_size /
sizeof(
Elf_Sym);
815 for (i = 1; i <
n; i++) {
816 if (
strcmp(strtab + sym[i].st_name,
"__start") == 0) {
817 v->__start = sym[
i].st_value;
820 if (
strcmp(strtab + sym[i].st_name,
"vpe_shared") == 0) {
821 v->shared_ptr = (
void *)sym[i].st_value;
825 if ( (v->__start == 0) || (v->shared_ptr ==
NULL))
836 static int vpe_elfload(
struct vpe * v)
841 char *secstrings, *strtab =
NULL;
842 unsigned int len,
i, symindex = 0, strindex = 0, relocate = 0;
846 strcpy(mod.name,
"VPE loader");
856 || hdr->e_shentsize !=
sizeof(*sechdrs)) {
858 "VPE loader: program wrong arch or weird elf version\n");
863 if (hdr->e_type ==
ET_REL)
866 if (len < hdr->e_shoff + hdr->e_shnum *
sizeof(
Elf_Shdr)) {
874 sechdrs = (
void *)hdr + hdr->e_shoff;
875 secstrings = (
void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
876 sechdrs[0].sh_addr = 0;
879 symindex = strindex = 0;
882 for (i = 1; i < hdr->e_shnum; i++) {
884 && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
892 sechdrs[
i].sh_addr = (
size_t) hdr + sechdrs[i].sh_offset;
897 strindex = sechdrs[
i].sh_link;
898 strtab = (
char *)hdr + sechdrs[strindex].sh_offset;
901 layout_sections(&mod, hdr, sechdrs, secstrings);
904 v->
load_addr = alloc_progmem(mod.core_size);
911 for (i = 0; i < hdr->e_shnum; i++) {
920 memcpy(dest, (
void *)sechdrs[i].sh_addr,
923 sechdrs[
i].sh_addr = (
unsigned long)dest;
926 secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
930 simplify_symbols(sechdrs, symindex, strtab, secstrings,
934 for (i = 1; i < hdr->e_shnum; i++) {
935 const char *strtab = (
char *)sechdrs[strindex].sh_addr;
936 unsigned int info = sechdrs[
i].sh_info;
939 if (info >= hdr->e_shnum)
943 if (!(sechdrs[info].sh_flags & SHF_ALLOC))
946 if (sechdrs[i].sh_type ==
SHT_REL)
947 err = apply_relocations(sechdrs, strtab, symindex, i,
949 else if (sechdrs[i].sh_type ==
SHT_RELA)
959 for (i = 0; i < hdr->e_phnum; i++) {
961 memcpy((
void *)phdr->p_paddr,
962 (
char *)hdr + phdr->p_offset,
964 memset((
void *)phdr->p_paddr + phdr->p_filesz,
965 0, phdr->p_memsz - phdr->p_filesz);
970 for (i = 0; i < hdr->e_shnum; i++) {
974 strindex = sechdrs[
i].sh_link;
975 strtab = (
char *)hdr + sechdrs[strindex].sh_offset;
979 sechdrs[
i].sh_addr = (
size_t) hdr + sechdrs[i].sh_offset;
988 if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
991 "a __start symbol\n");
997 "program does not contain vpe_shared symbol.\n"
998 " Unable to use AMVP (AP/SP) facilities.\n");
1005 static void cleanup_tc(
struct tc *tc)
1007 unsigned long flags;
1008 unsigned int mtflags, vpflags;
1015 set_c0_mvpcontrol(MVPCONTROL_VPC);
1031 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1037 static int getcwd(
char *buff,
int size)
1060 if (minor != iminor(inode)) {
1062 pr_warning(
"VPE loader: only vpe1 is supported\n");
1068 pr_warning(
"VPE loader: unable to get vpe\n");
1088 pr_warning(
"VPE loader: unable to allocate memory\n");
1109 static int vpe_release(
struct inode *inode,
struct file *filp)
1121 if (vpe_elfload(v) >= 0) {
1147 size_t count, loff_t * ppos)
1152 if (iminor(file->
f_path.dentry->d_inode) != minor)
1159 if ((count + v->
len) > v->
plen) {
1161 "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
1176 .release = vpe_release,
1190 if ((v = get_vpe(i)) !=
NULL) {
1203 struct vpe *v = vpe;
1214 struct vpe *v = vpe;
1216 unsigned int evpe_flags;
1218 evpe_flags = dvpe();
1236 struct vpe *v = vpe;
1238 unsigned int evpe_flags;
1244 evpe_flags = dvpe();
1247 set_c0_mvpcontrol(MVPCONTROL_VPC);
1261 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1273 if ((v = get_vpe(index)) ==
NULL)
1285 if ((v = get_vpe(index)) ==
NULL)
1297 if ((v = get_vpe(index)) ==
NULL)
1309 if ((v = get_vpe(index)) ==
NULL)
1322 if ((v = get_vpe(index)) ==
NULL)
1331 const char *
buf,
size_t len)
1351 struct vpe *vpe = get_vpe(
tclimit);
1357 const char *buf,
size_t len)
1359 struct vpe *vpe = get_vpe(
tclimit);
1367 if (
new == 0 ||
new > (hw_tcs -
tclimit))
1384 static void vpe_device_release(
struct device *
cd)
1392 .dev_release = vpe_device_release,
1393 .dev_attrs = vpe_class_attributes,
1398 static int __init vpe_module_init(
void)
1400 unsigned int mtflags, vpflags;
1402 struct vpe *v =
NULL;
1407 printk(
"VPE loader: not a MIPS MT capable processor\n");
1413 "initializing VPE loader.\nPass maxvpes=<n> argument as "
1414 "kernel argument\n");
1421 "initializing VPE loader.\nPass maxtcs=<n> argument as "
1422 "kernel argument\n");
1427 major = register_chrdev(0,
module_name, &vpe_fops);
1429 printk(
"VPE loader: unable to register character device\n");
1455 set_c0_mvpcontrol(MVPCONTROL_VPC);
1463 for (tc =
tclimit; tc < hw_tcs; tc++) {
1468 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1481 set_c0_mvpcontrol(MVPCONTROL_VPC);
1487 if ((v = alloc_vpe(tc)) ==
NULL) {
1496 list_add(&t->
tc, &v->
tc);
1499 if (tc >= tclimit) {
1524 if (tc >= tclimit) {
1543 t->
pvpe = get_vpe(0);
1561 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1578 static void __exit vpe_module_exit(
void)