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