elf_trampoline.c revision 183840
1194676Sthompsa/*- 2194676Sthompsa * Copyright (c) 2005 Olivier Houchard. All rights reserved. 3194676Sthompsa * 4194676Sthompsa * Redistribution and use in source and binary forms, with or without 5194676Sthompsa * modification, are permitted provided that the following conditions 6194676Sthompsa * are met: 7194676Sthompsa * 1. Redistributions of source code must retain the above copyright 8194676Sthompsa * notice, this list of conditions and the following disclaimer. 9194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 10194676Sthompsa * notice, this list of conditions and the following disclaimer in the 11194676Sthompsa * documentation and/or other materials provided with the distribution. 12194676Sthompsa * 13194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14194676Sthompsa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15194676Sthompsa * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16194676Sthompsa * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17194676Sthompsa * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18194676Sthompsa * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19194676Sthompsa * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20194676Sthompsa * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21194676Sthompsa * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22194676Sthompsa * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23194676Sthompsa */ 24194676Sthompsa 25194676Sthompsa#include <sys/cdefs.h> 26194676Sthompsa__FBSDID("$FreeBSD: head/sys/arm/arm/elf_trampoline.c 183840 2008-10-13 20:07:13Z raj $"); 27203815Swkoszek#include <machine/asm.h> 28203815Swkoszek#include <sys/param.h> 29203815Swkoszek#include <sys/elf32.h> 30194676Sthompsa#include <sys/inflate.h> 31194676Sthompsa#include <machine/elf.h> 32203815Swkoszek#include <machine/pte.h> 33203815Swkoszek#include <machine/cpufunc.h> 34194676Sthompsa#include <machine/armreg.h> 35203815Swkoszek 36194676Sthompsa/* 37194676Sthompsa * Since we are compiled outside of the normal kernel build process, we 38194676Sthompsa * need to include opt_global.h manually. 39194676Sthompsa */ 40194676Sthompsa#include "opt_global.h" 41194676Sthompsa#include "opt_kernname.h" 42194676Sthompsa 43195957Salfredextern char kernel_start[]; 44195957Salfredextern char kernel_end[]; 45195957Salfred 46195560Sthompsaextern void *_end; 47195560Sthompsa 48195957Salfredvoid _start(void); 49195560Sthompsavoid __start(void); 50195957Salfredvoid __startC(void); 51195957Salfred 52195957Salfred#define GZ_HEAD 0xa 53195957Salfred 54195957Salfred#ifdef CPU_ARM7TDMI 55195957Salfred#define cpu_idcache_wbinv_all arm7tdmi_cache_flushID 56195957Salfred#elif defined(CPU_ARM8) 57195560Sthompsa#define cpu_idcache_wbinv_all arm8_cache_purgeID 58195560Sthompsa#elif defined(CPU_ARM9) 59195560Sthompsa#define cpu_idcache_wbinv_all arm9_idcache_wbinv_all 60195957Salfred#elif defined(CPU_ARM9E) 61195957Salfred#define cpu_idcache_wbinv_all armv5_ec_idcache_wbinv_all 62195957Salfred#elif defined(CPU_ARM10) 63195560Sthompsa#define cpu_idcache_wbinv_all arm10_idcache_wbinv_all 64195560Sthompsa#elif defined(CPU_SA110) || defined(CPU_SA1110) || defined(CPU_SA1100) || \ 65195560Sthompsa defined(CPU_IXP12X0) 66195560Sthompsa#define cpu_idcache_wbinv_all sa1_cache_purgeID 67195560Sthompsa#elif defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \ 68195560Sthompsa defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ 69195957Salfred defined(CPU_XSCALE_80219) 70195560Sthompsa#define cpu_idcache_wbinv_all xscale_cache_purgeID 71195957Salfred#elif defined(CPU_XSCALE_81342) 72195957Salfred#define cpu_idcache_wbinv_all xscalec3_cache_purgeID 73195560Sthompsa#endif 74195957Salfred#ifdef CPU_XSCALE_81342 75195957Salfred#define cpu_l2cache_wbinv_all xscalec3_l2cache_purge 76195560Sthompsa#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 77195957Salfred#define cpu_l2cache_wbinv_all feroceon_l2cache_wbinv_all 78195957Salfred#else 79195957Salfred#define cpu_l2cache_wbinv_all() 80195957Salfred#endif 81195560Sthompsa 82195560Sthompsa 83195957Salfredint arm_picache_size; 84195560Sthompsaint arm_picache_line_size; 85195560Sthompsaint arm_picache_ways; 86195957Salfred 87195560Sthompsaint arm_pdcache_size; /* and unified */ 88195957Salfredint arm_pdcache_line_size = 32; 89195957Salfredint arm_pdcache_ways; 90195560Sthompsa 91195957Salfredint arm_pcache_type; 92195957Salfredint arm_pcache_unified; 93195957Salfred 94195957Salfredint arm_dcache_align; 95195957Salfredint arm_dcache_align_mask; 96194676Sthompsa 97194676Sthompsa/* Additional cache information local to this file. Log2 of some of the 98194676Sthompsa above numbers. */ 99194676Sthompsastatic int arm_dcache_l2_nsets; 100195957Salfredstatic int arm_dcache_l2_assoc; 101194676Sthompsastatic int arm_dcache_l2_linesize; 102195957Salfred 103195957Salfred 104194676Sthompsaint block_userspace_access = 0; 105195957Salfredextern int arm9_dcache_sets_inc; 106195957Salfredextern int arm9_dcache_sets_max; 107195957Salfredextern int arm9_dcache_index_max; 108194676Sthompsaextern int arm9_dcache_index_inc; 109195560Sthompsa 110194676Sthompsastatic __inline void * 111194676Sthompsamemcpy(void *dst, const void *src, int len) 112194676Sthompsa{ 113195957Salfred const char *s = src; 114195957Salfred char *d = dst; 115195957Salfred 116195957Salfred while (len) { 117195957Salfred if (0 && len >= 4 && !((vm_offset_t)d & 3) && 118195957Salfred !((vm_offset_t)s & 3)) { 119195957Salfred *(uint32_t *)d = *(uint32_t *)s; 120195957Salfred s += 4; 121195957Salfred d += 4; 122195957Salfred len -= 4; 123195957Salfred } else { 124194676Sthompsa *d++ = *s++; 125194676Sthompsa len--; 126194676Sthompsa } 127195957Salfred } 128195957Salfred return (dst); 129195957Salfred} 130195957Salfred 131194676Sthompsastatic __inline void 132195957Salfredbzero(void *addr, int count) 133195957Salfred{ 134195957Salfred char *tmp = (char *)addr; 135194676Sthompsa 136195957Salfred while (count > 0) { 137195957Salfred if (count >= 4 && !((vm_offset_t)tmp & 3)) { 138195957Salfred *(uint32_t *)tmp = 0; 139195957Salfred tmp += 4; 140194676Sthompsa count -= 4; 141195957Salfred } else { 142195957Salfred *tmp = 0; 143195957Salfred tmp++; 144195957Salfred count--; 145195957Salfred } 146195957Salfred } 147195957Salfred} 148194676Sthompsa 149195957Salfredstatic void arm9_setup(void); 150194676Sthompsa 151195957Salfredvoid 152195957Salfred_startC(void) 153195957Salfred{ 154194676Sthompsa int physaddr = KERNPHYSADDR; 155199055Sthompsa int tmp1; 156199055Sthompsa unsigned int sp = ((unsigned int)&_end & ~3) + 4; 157199055Sthompsa#if defined(FLASHADDR) && defined(LOADERRAMADDR) 158199055Sthompsa unsigned int pc; 159199055Sthompsa 160195957Salfred __asm __volatile("adr %0, _start\n" 161195957Salfred : "=r" (pc)); 162195957Salfred if ((FLASHADDR > LOADERRAMADDR && pc >= FLASHADDR) || 163199055Sthompsa (FLASHADDR < LOADERRAMADDR && pc < LOADERRAMADDR)) { 164199055Sthompsa /* 165195957Salfred * We're running from flash, so just copy the whole thing 166195957Salfred * from flash to memory. 167195957Salfred * This is far from optimal, we could do the relocation or 168195957Salfred * the unzipping directly from flash to memory to avoid this 169195957Salfred * needless copy, but it would require to know the flash 170194676Sthompsa * physical address. 171195957Salfred */ 172195957Salfred unsigned int target_addr; 173194676Sthompsa unsigned int tmp_sp; 174195957Salfred 175195957Salfred target_addr = (unsigned int)&_start - PHYSADDR + LOADERRAMADDR; 176195957Salfred tmp_sp = target_addr + 0x100000 + 177195957Salfred (unsigned int)&_end - (unsigned int)&_start; 178194676Sthompsa memcpy((char *)target_addr, (char *)pc, 179195957Salfred (unsigned int)&_end - (unsigned int)&_start); 180194676Sthompsa /* Temporary set the sp and jump to the new location. */ 181195957Salfred __asm __volatile( 182194676Sthompsa "mov sp, %1\n" 183195957Salfred "mov pc, %0\n" 184194676Sthompsa : : "r" (target_addr), "r" (tmp_sp)); 185195957Salfred 186194676Sthompsa } 187195957Salfred#endif 188195957Salfred#ifdef KZIP 189195957Salfred sp += KERNSIZE + 0x100; 190194676Sthompsa sp &= ~(L1_TABLE_SIZE - 1); 191195957Salfred sp += 2 * L1_TABLE_SIZE; 192195957Salfred#endif 193195957Salfred sp += 1024 * 1024; /* Should be enough for a stack */ 194195957Salfred 195195957Salfred __asm __volatile("adr %0, 2f\n" 196195957Salfred "bic %0, %0, #0xff000000\n" 197195957Salfred "and %1, %1, #0xff000000\n" 198195957Salfred "orr %0, %0, %1\n" 199195957Salfred "mrc p15, 0, %1, c1, c0, 0\n" 200195957Salfred "bic %1, %1, #1\n" /* Disable MMU */ 201195957Salfred "orr %1, %1, #(4 | 8)\n" /* Add DC enable, 202195957Salfred WBUF enable */ 203195957Salfred "orr %1, %1, #0x1000\n" /* Add IC enable */ 204195957Salfred "orr %1, %1, #(0x800)\n" /* BPRD enable */ 205195957Salfred 206195957Salfred "mcr p15, 0, %1, c1, c0, 0\n" 207195957Salfred "nop\n" 208195957Salfred "nop\n" 209195957Salfred "nop\n" 210195957Salfred "mov pc, %0\n" 211194676Sthompsa "2: nop\n" 212194676Sthompsa "mov sp, %2\n" 213195957Salfred : "=r" (tmp1), "+r" (physaddr), "+r" (sp)); 214195957Salfred#ifndef KZIP 215194676Sthompsa#ifdef CPU_ARM9 216195957Salfred /* So that idcache_wbinv works; */ 217194676Sthompsa if ((cpufunc_id() & 0x0000f000) == 0x00009000) 218194676Sthompsa arm9_setup(); 219194676Sthompsa#endif 220194676Sthompsa cpu_idcache_wbinv_all(); 221194676Sthompsa cpu_l2cache_wbinv_all(); 222195957Salfred#endif 223194676Sthompsa __start(); 224195957Salfred} 225194676Sthompsa 226195957Salfredstatic void 227195957Salfredget_cachetype_cp15() 228194676Sthompsa{ 229194676Sthompsa u_int ctype, isize, dsize; 230195957Salfred u_int multiplier; 231195957Salfred 232194676Sthompsa __asm __volatile("mrc p15, 0, %0, c0, c0, 1" 233194676Sthompsa : "=r" (ctype)); 234195957Salfred 235195957Salfred /* 236195957Salfred * ...and thus spake the ARM ARM: 237195957Salfred * 238195957Salfred * If an <opcode2> value corresponding to an unimplemented or 239195957Salfred * reserved ID register is encountered, the System Control 240195957Salfred * processor returns the value of the main ID register. 241194676Sthompsa */ 242194676Sthompsa if (ctype == cpufunc_id()) 243194676Sthompsa goto out; 244195957Salfred 245194676Sthompsa if ((ctype & CPU_CT_S) == 0) 246195957Salfred arm_pcache_unified = 1; 247195957Salfred 248195957Salfred /* 249195957Salfred * If you want to know how this code works, go read the ARM ARM. 250194676Sthompsa */ 251194676Sthompsa 252194676Sthompsa arm_pcache_type = CPU_CT_CTYPE(ctype); 253195957Salfred if (arm_pcache_unified == 0) { 254194676Sthompsa isize = CPU_CT_ISIZE(ctype); 255195957Salfred multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2; 256195957Salfred arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3); 257195957Salfred if (CPU_CT_xSIZE_ASSOC(isize) == 0) { 258195957Salfred if (isize & CPU_CT_xSIZE_M) 259195957Salfred arm_picache_line_size = 0; /* not present */ 260195957Salfred else 261194676Sthompsa arm_picache_ways = 1; 262194676Sthompsa } else { 263194676Sthompsa arm_picache_ways = multiplier << 264195957Salfred (CPU_CT_xSIZE_ASSOC(isize) - 1); 265194676Sthompsa } 266195957Salfred arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8); 267195957Salfred } 268194676Sthompsa 269194676Sthompsa dsize = CPU_CT_DSIZE(ctype); 270194676Sthompsa multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2; 271195957Salfred arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3); 272194676Sthompsa if (CPU_CT_xSIZE_ASSOC(dsize) == 0) { 273195957Salfred if (dsize & CPU_CT_xSIZE_M) 274195957Salfred arm_pdcache_line_size = 0; /* not present */ 275194676Sthompsa else 276194676Sthompsa arm_pdcache_ways = 1; 277194676Sthompsa } else { 278195957Salfred arm_pdcache_ways = multiplier << 279194676Sthompsa (CPU_CT_xSIZE_ASSOC(dsize) - 1); 280195957Salfred } 281195957Salfred arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8); 282194676Sthompsa 283194676Sthompsa arm_dcache_align = arm_pdcache_line_size; 284194676Sthompsa 285195957Salfred arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2; 286194676Sthompsa arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3; 287195957Salfred arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) - 288195957Salfred CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize); 289194676Sthompsa out: 290194676Sthompsa arm_dcache_align_mask = arm_dcache_align - 1; 291194676Sthompsa} 292195957Salfred 293194676Sthompsastatic void 294194676Sthompsaarm9_setup(void) 295195957Salfred{ 296194676Sthompsa 297195957Salfred get_cachetype_cp15(); 298195560Sthompsa arm9_dcache_sets_inc = 1U << arm_dcache_l2_linesize; 299194676Sthompsa arm9_dcache_sets_max = (1U << (arm_dcache_l2_linesize + 300194676Sthompsa arm_dcache_l2_nsets)) - arm9_dcache_sets_inc; 301195957Salfred arm9_dcache_index_inc = 1U << (32 - arm_dcache_l2_assoc); 302195957Salfred arm9_dcache_index_max = 0U - arm9_dcache_index_inc; 303194676Sthompsa} 304194676Sthompsa 305195957Salfred 306195957Salfred#ifdef KZIP 307194676Sthompsastatic unsigned char *orig_input, *i_input, *i_output; 308194676Sthompsa 309194676Sthompsa 310194676Sthompsastatic u_int memcnt; /* Memory allocated: blocks */ 311195957Salfredstatic size_t memtot; /* Memory allocated: bytes */ 312194676Sthompsa/* 313194676Sthompsa * Library functions required by inflate(). 314194676Sthompsa */ 315195957Salfred 316195957Salfred#define MEMSIZ 0x8000 317194676Sthompsa 318195957Salfred/* 319194676Sthompsa * Allocate memory block. 320194676Sthompsa */ 321194676Sthompsaunsigned char * 322194676Sthompsakzipmalloc(int size) 323194676Sthompsa{ 324194676Sthompsa void *ptr; 325195957Salfred static u_char mem[MEMSIZ]; 326194676Sthompsa 327195957Salfred if (memtot + size > MEMSIZ) 328195957Salfred return NULL; 329195957Salfred ptr = mem + memtot; 330195957Salfred memtot += size; 331195560Sthompsa memcnt++; 332194676Sthompsa return ptr; 333195957Salfred} 334194676Sthompsa 335195957Salfred/* 336194676Sthompsa * Free allocated memory block. 337195957Salfred */ 338194676Sthompsavoid 339195560Sthompsakzipfree(void *ptr) 340195957Salfred{ 341195957Salfred memcnt--; 342194676Sthompsa if (!memcnt) 343194676Sthompsa memtot = 0; 344194676Sthompsa} 345195957Salfred 346194676Sthompsavoid 347195957Salfredputstr(char *dummy) 348194676Sthompsa{ 349194676Sthompsa} 350194676Sthompsa 351195957Salfredstatic int 352194676Sthompsainput(void *dummy) 353195957Salfred{ 354194676Sthompsa if ((size_t)(i_input - orig_input) >= KERNCOMPSIZE) { 355195957Salfred return (GZ_EOF); 356194676Sthompsa } 357195957Salfred return *i_input++; 358195957Salfred} 359195957Salfred 360195957Salfredstatic int 361195957Salfredoutput(void *dummy, unsigned char *ptr, unsigned long len) 362194676Sthompsa{ 363195957Salfred 364194676Sthompsa 365194676Sthompsa memcpy(i_output, ptr, len); 366194676Sthompsa i_output += len; 367195957Salfred return (0); 368194676Sthompsa} 369195957Salfred 370195957Salfredstatic void * 371195957Salfredinflate_kernel(void *kernel, void *startaddr) 372194676Sthompsa{ 373194676Sthompsa struct inflate infl; 374194676Sthompsa char slide[GZ_WSIZE]; 375195957Salfred 376194676Sthompsa orig_input = kernel; 377194676Sthompsa memcnt = memtot = 0; 378194676Sthompsa i_input = (char *)kernel + GZ_HEAD; 379195957Salfred if (((char *)kernel)[3] & 0x18) { 380194676Sthompsa while (*i_input) 381194676Sthompsa i_input++; 382194676Sthompsa i_input++; 383194676Sthompsa } 384194676Sthompsa i_output = startaddr; 385194676Sthompsa bzero(&infl, sizeof(infl)); 386194676Sthompsa infl.gz_input = input; 387195957Salfred infl.gz_output = output; 388194676Sthompsa infl.gz_slide = slide; 389195957Salfred inflate(&infl); 390194676Sthompsa return ((char *)(((vm_offset_t)i_output & ~3) + 4)); 391194676Sthompsa} 392194676Sthompsa 393195957Salfred#endif 394194676Sthompsa 395195957Salfredvoid * 396195957Salfredload_kernel(unsigned int kstart, unsigned int curaddr,unsigned int func_end, 397194676Sthompsa int d) 398195957Salfred{ 399195957Salfred Elf32_Ehdr *eh; 400194676Sthompsa Elf32_Phdr phdr[64] /* XXX */, *php; 401195957Salfred Elf32_Shdr shdr[64] /* XXX */; 402195957Salfred int i,j; 403195957Salfred void *entry_point; 404194676Sthompsa int symtabindex = -1; 405194676Sthompsa int symstrindex = -1; 406195957Salfred vm_offset_t lastaddr = 0; 407195957Salfred Elf_Addr ssym = 0, esym = 0; 408194676Sthompsa Elf_Dyn *dp; 409194676Sthompsa 410195957Salfred eh = (Elf32_Ehdr *)kstart; 411195957Salfred ssym = esym = 0; 412194676Sthompsa entry_point = (void*)eh->e_entry; 413194676Sthompsa memcpy(phdr, (void *)(kstart + eh->e_phoff ), 414194676Sthompsa eh->e_phnum * sizeof(phdr[0])); 415194676Sthompsa 416194676Sthompsa /* Determine lastaddr. */ 417194676Sthompsa for (i = 0; i < eh->e_phnum; i++) { 418194676Sthompsa if (lastaddr < (phdr[i].p_vaddr - KERNVIRTADDR + curaddr 419195957Salfred + phdr[i].p_memsz)) 420194676Sthompsa lastaddr = phdr[i].p_vaddr - KERNVIRTADDR + 421195957Salfred curaddr + phdr[i].p_memsz; 422194676Sthompsa } 423195957Salfred 424195957Salfred /* Save the symbol tables, as there're about to be scratched. */ 425195957Salfred memcpy(shdr, (void *)(kstart + eh->e_shoff), 426194676Sthompsa sizeof(*shdr) * eh->e_shnum); 427195957Salfred if (eh->e_shnum * eh->e_shentsize != 0 && 428195957Salfred eh->e_shoff != 0) { 429194676Sthompsa for (i = 0; i < eh->e_shnum; i++) { 430195957Salfred if (shdr[i].sh_type == SHT_SYMTAB) { 431195957Salfred for (j = 0; j < eh->e_phnum; j++) { 432194676Sthompsa if (phdr[j].p_type == PT_LOAD && 433195957Salfred shdr[i].sh_offset >= 434194676Sthompsa phdr[j].p_offset && 435195957Salfred (shdr[i].sh_offset + 436195957Salfred shdr[i].sh_size <= 437195957Salfred phdr[j].p_offset + 438195957Salfred phdr[j].p_filesz)) { 439195957Salfred shdr[i].sh_offset = 0; 440194676Sthompsa shdr[i].sh_size = 0; 441195957Salfred j = eh->e_phnum; 442195957Salfred } 443194676Sthompsa } 444195957Salfred if (shdr[i].sh_offset != 0 && 445195957Salfred shdr[i].sh_size != 0) { 446195957Salfred symtabindex = i; 447195957Salfred symstrindex = shdr[i].sh_link; 448195957Salfred } 449195957Salfred } 450194676Sthompsa } 451195957Salfred func_end = roundup(func_end, sizeof(long)); 452195957Salfred if (symtabindex >= 0 && symstrindex >= 0) { 453194676Sthompsa ssym = lastaddr; 454195957Salfred if (d) { 455195957Salfred memcpy((void *)func_end, (void *)( 456195957Salfred shdr[symtabindex].sh_offset + kstart), 457195957Salfred shdr[symtabindex].sh_size); 458195957Salfred memcpy((void *)(func_end + 459194676Sthompsa shdr[symtabindex].sh_size), 460195957Salfred (void *)(shdr[symstrindex].sh_offset + 461194676Sthompsa kstart), shdr[symstrindex].sh_size); 462195957Salfred } else { 463194676Sthompsa lastaddr += shdr[symtabindex].sh_size; 464195957Salfred lastaddr = roundup(lastaddr, 465195957Salfred sizeof(shdr[symtabindex].sh_size)); 466194676Sthompsa lastaddr += sizeof(shdr[symstrindex].sh_size); 467194676Sthompsa lastaddr += shdr[symstrindex].sh_size; 468195957Salfred lastaddr = roundup(lastaddr, 469195957Salfred sizeof(shdr[symstrindex].sh_size)); 470195957Salfred } 471195957Salfred 472194676Sthompsa } 473195957Salfred } 474195957Salfred if (!d) 475194676Sthompsa return ((void *)lastaddr); 476194676Sthompsa 477195957Salfred j = eh->e_phnum; 478194676Sthompsa for (i = 0; i < j; i++) { 479195957Salfred volatile char c; 480194676Sthompsa 481194676Sthompsa if (phdr[i].p_type != PT_LOAD) 482195957Salfred continue; 483195957Salfred memcpy((void *)(phdr[i].p_vaddr - KERNVIRTADDR + curaddr), 484194676Sthompsa (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz); 485195957Salfred /* Clean space from oversized segments, eg: bss. */ 486195957Salfred if (phdr[i].p_filesz < phdr[i].p_memsz) 487195957Salfred bzero((void *)(phdr[i].p_vaddr - KERNVIRTADDR + 488194676Sthompsa curaddr + phdr[i].p_filesz), phdr[i].p_memsz - 489194676Sthompsa phdr[i].p_filesz); 490194676Sthompsa } 491194676Sthompsa /* Now grab the symbol tables. */ 492195957Salfred if (symtabindex >= 0 && symstrindex >= 0) { 493194676Sthompsa *(Elf_Size *)lastaddr = 494194676Sthompsa shdr[symtabindex].sh_size; 495194676Sthompsa lastaddr += sizeof(shdr[symtabindex].sh_size); 496194676Sthompsa memcpy((void*)lastaddr, 497194676Sthompsa (void *)func_end, 498194676Sthompsa shdr[symtabindex].sh_size); 499194676Sthompsa lastaddr += shdr[symtabindex].sh_size; 500195957Salfred lastaddr = roundup(lastaddr, 501195957Salfred sizeof(shdr[symtabindex].sh_size)); 502194676Sthompsa *(Elf_Size *)lastaddr = 503194676Sthompsa shdr[symstrindex].sh_size; 504194676Sthompsa lastaddr += sizeof(shdr[symstrindex].sh_size); 505194676Sthompsa memcpy((void*)lastaddr, 506194676Sthompsa (void*)(func_end + 507194676Sthompsa shdr[symtabindex].sh_size), 508194676Sthompsa shdr[symstrindex].sh_size); 509194676Sthompsa lastaddr += shdr[symstrindex].sh_size; 510194676Sthompsa lastaddr = roundup(lastaddr, 511195957Salfred sizeof(shdr[symstrindex].sh_size)); 512194676Sthompsa *(Elf_Addr *)curaddr = MAGIC_TRAMP_NUMBER; 513194676Sthompsa *((Elf_Addr *)curaddr + 1) = ssym - curaddr + KERNVIRTADDR; 514194676Sthompsa *((Elf_Addr *)curaddr + 2) = lastaddr - curaddr + KERNVIRTADDR; 515194676Sthompsa } else 516195957Salfred *(Elf_Addr *)curaddr = 0; 517194676Sthompsa /* Invalidate the instruction cache. */ 518194676Sthompsa __asm __volatile("mcr p15, 0, %0, c7, c5, 0\n" 519195957Salfred "mcr p15, 0, %0, c7, c10, 4\n" 520194676Sthompsa : : "r" (curaddr)); 521194676Sthompsa __asm __volatile("mrc p15, 0, %0, c1, c0, 0\n" 522195957Salfred "bic %0, %0, #1\n" /* MMU_ENABLE */ 523195957Salfred "mcr p15, 0, %0, c1, c0, 0\n" 524194676Sthompsa : "=r" (ssym)); 525195957Salfred /* Jump to the entry point. */ 526195957Salfred ((void(*)(void))(entry_point - KERNVIRTADDR + curaddr))(); 527194676Sthompsa __asm __volatile(".globl func_end\n" 528195957Salfred "func_end:"); 529195957Salfred 530194676Sthompsa} 531195957Salfred 532194676Sthompsaextern char func_end[]; 533194676Sthompsa 534194676Sthompsa 535195957Salfred#define PMAP_DOMAIN_KERNEL 0 /* 536194676Sthompsa * Just define it instead of including the 537194676Sthompsa * whole VM headers set. 538194676Sthompsa */ 539194676Sthompsaint __hack; 540194676Sthompsastatic __inline void 541194676Sthompsasetup_pagetables(unsigned int pt_addr, vm_paddr_t physstart, vm_paddr_t physend, 542194676Sthompsa int write_back) 543195957Salfred{ 544195957Salfred unsigned int *pd = (unsigned int *)pt_addr; 545194676Sthompsa vm_paddr_t addr; 546194676Sthompsa int domain = (DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) | DOMAIN_CLIENT; 547194676Sthompsa int tmp; 548194676Sthompsa 549195957Salfred bzero(pd, L1_TABLE_SIZE); 550195957Salfred for (addr = physstart; addr < physend; addr += L1_S_SIZE) { 551195560Sthompsa pd[addr >> L1_S_SHIFT] = L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)| 552194676Sthompsa L1_S_DOM(PMAP_DOMAIN_KERNEL) | addr; 553195957Salfred if (write_back) 554194676Sthompsa pd[addr >> L1_S_SHIFT] |= L1_S_B; 555194676Sthompsa } 556195560Sthompsa /* XXX: See below */ 557194676Sthompsa if (0xfff00000 < physstart || 0xfff00000 > physend) 558194676Sthompsa pd[0xfff00000 >> L1_S_SHIFT] = L1_TYPE_S|L1_S_AP(AP_KRW)| 559194676Sthompsa L1_S_DOM(PMAP_DOMAIN_KERNEL)|physstart; 560194676Sthompsa __asm __volatile("mcr p15, 0, %1, c2, c0, 0\n" /* set TTB */ 561195957Salfred "mcr p15, 0, %1, c8, c7, 0\n" /* Flush TTB */ 562195957Salfred "mcr p15, 0, %2, c3, c0, 0\n" /* Set DAR */ 563194676Sthompsa "mrc p15, 0, %0, c1, c0, 0\n" 564194676Sthompsa "orr %0, %0, #1\n" /* MMU_ENABLE */ 565194676Sthompsa "mcr p15, 0, %0, c1, c0, 0\n" 566194676Sthompsa "mrc p15, 0, %0, c2, c0, 0\n" /* CPWAIT */ 567194676Sthompsa "mov r0, r0\n" 568195957Salfred "sub pc, pc, #4\n" : 569195560Sthompsa "=r" (tmp) : "r" (pd), "r" (domain)); 570194676Sthompsa 571195957Salfred /* 572194676Sthompsa * XXX: This is the most stupid workaround I've ever wrote. 573194676Sthompsa * For some reason, the KB9202 won't boot the kernel unless 574195560Sthompsa * we access an address which is not in the 575194676Sthompsa * 0x20000000 - 0x20ffffff range. I hope I'll understand 576194676Sthompsa * what's going on later. 577199055Sthompsa */ 578199055Sthompsa __hack = *(volatile int *)0xfffff21c; 579199055Sthompsa} 580199055Sthompsa 581199055Sthompsavoid 582199055Sthompsa__start(void) 583199055Sthompsa{ 584199055Sthompsa void *curaddr; 585199055Sthompsa void *dst, *altdst; 586199055Sthompsa char *kernel = (char *)&kernel_start; 587199055Sthompsa int sp; 588199055Sthompsa int pt_addr; 589199055Sthompsa 590199055Sthompsa __asm __volatile("mov %0, pc" : 591199055Sthompsa "=r" (curaddr)); 592199055Sthompsa curaddr = (void*)((unsigned int)curaddr & 0xfff00000); 593199055Sthompsa#ifdef KZIP 594199055Sthompsa if (*kernel == 0x1f && kernel[1] == 0x8b) { 595199055Sthompsa pt_addr = (((int)&_end + KERNSIZE + 0x100) & 596199055Sthompsa ~(L1_TABLE_SIZE - 1)) + L1_TABLE_SIZE; 597199055Sthompsa 598199055Sthompsa#ifdef CPU_ARM9 599199055Sthompsa /* So that idcache_wbinv works; */ 600199055Sthompsa if ((cpufunc_id() & 0x0000f000) == 0x00009000) 601199055Sthompsa arm9_setup(); 602199055Sthompsa#endif 603199055Sthompsa setup_pagetables(pt_addr, (vm_paddr_t)curaddr, 604199055Sthompsa (vm_paddr_t)curaddr + 0x10000000, 1); 605199055Sthompsa /* Gzipped kernel */ 606199055Sthompsa dst = inflate_kernel(kernel, &_end); 607199055Sthompsa kernel = (char *)&_end; 608199055Sthompsa altdst = 4 + load_kernel((unsigned int)kernel, 609199055Sthompsa (unsigned int)curaddr, 610199055Sthompsa (unsigned int)&func_end + 800 , 0); 611199055Sthompsa if (altdst > dst) 612199055Sthompsa dst = altdst; 613199055Sthompsa cpu_idcache_wbinv_all(); 614199055Sthompsa cpu_l2cache_wbinv_all(); 615199055Sthompsa __asm __volatile("mrc p15, 0, %0, c1, c0, 0\n" 616199055Sthompsa "bic %0, %0, #1\n" /* MMU_ENABLE */ 617199055Sthompsa "mcr p15, 0, %0, c1, c0, 0\n" 618199055Sthompsa : "=r" (pt_addr)); 619199055Sthompsa } else 620199055Sthompsa#endif 621199055Sthompsa dst = 4 + load_kernel((unsigned int)&kernel_start, 622199055Sthompsa (unsigned int)curaddr, 623199055Sthompsa (unsigned int)&func_end, 0); 624199055Sthompsa dst = (void *)(((vm_offset_t)dst & ~3)); 625199055Sthompsa pt_addr = ((unsigned int)dst &~(L1_TABLE_SIZE - 1)) + L1_TABLE_SIZE; 626199055Sthompsa setup_pagetables(pt_addr, (vm_paddr_t)curaddr, 627199055Sthompsa (vm_paddr_t)curaddr + 0x10000000, 0); 628199055Sthompsa sp = pt_addr + L1_TABLE_SIZE + 8192; 629199055Sthompsa sp = sp &~3; 630199055Sthompsa dst = (void *)(sp + 4); 631199055Sthompsa memcpy((void *)dst, (void *)&load_kernel, (unsigned int)&func_end - 632199055Sthompsa (unsigned int)&load_kernel + 800); 633199055Sthompsa do_call(dst, kernel, dst + (unsigned int)(&func_end) - 634199055Sthompsa (unsigned int)(&load_kernel) + 800, sp); 635199055Sthompsa} 636199055Sthompsa