elf_trampoline.c revision 186933
1/*- 2 * Copyright (c) 2005 Olivier Houchard. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include <sys/cdefs.h> 26__FBSDID("$FreeBSD: head/sys/arm/arm/elf_trampoline.c 186933 2009-01-09 10:45:04Z raj $"); 27#include <machine/asm.h> 28#include <sys/param.h> 29#include <sys/elf32.h> 30#include <sys/inflate.h> 31#include <machine/elf.h> 32#include <machine/pte.h> 33#include <machine/cpufunc.h> 34#include <machine/armreg.h> 35 36/* 37 * Since we are compiled outside of the normal kernel build process, we 38 * need to include opt_global.h manually. 39 */ 40#include "opt_global.h" 41#include "opt_kernname.h" 42 43extern char kernel_start[]; 44extern char kernel_end[]; 45 46extern void *_end; 47 48void _start(void); 49void __start(void); 50void __startC(void); 51 52#define GZ_HEAD 0xa 53 54#ifdef CPU_ARM7TDMI 55#define cpu_idcache_wbinv_all arm7tdmi_cache_flushID 56#elif defined(CPU_ARM8) 57#define cpu_idcache_wbinv_all arm8_cache_purgeID 58#elif defined(CPU_ARM9) 59#define cpu_idcache_wbinv_all arm9_idcache_wbinv_all 60#elif defined(CPU_ARM9E) 61#define cpu_idcache_wbinv_all armv5_ec_idcache_wbinv_all 62#elif defined(CPU_ARM10) 63#define cpu_idcache_wbinv_all arm10_idcache_wbinv_all 64#elif defined(CPU_SA110) || defined(CPU_SA1110) || defined(CPU_SA1100) || \ 65 defined(CPU_IXP12X0) 66#define cpu_idcache_wbinv_all sa1_cache_purgeID 67#elif defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \ 68 defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ 69 defined(CPU_XSCALE_80219) 70#define cpu_idcache_wbinv_all xscale_cache_purgeID 71#elif defined(CPU_XSCALE_81342) 72#define cpu_idcache_wbinv_all xscalec3_cache_purgeID 73#endif 74#ifdef CPU_XSCALE_81342 75#define cpu_l2cache_wbinv_all xscalec3_l2cache_purge 76#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 77#define cpu_l2cache_wbinv_all sheeva_l2cache_wbinv_all 78#else 79#define cpu_l2cache_wbinv_all() 80#endif 81 82 83int arm_picache_size; 84int arm_picache_line_size; 85int arm_picache_ways; 86 87int arm_pdcache_size; /* and unified */ 88int arm_pdcache_line_size = 32; 89int arm_pdcache_ways; 90 91int arm_pcache_type; 92int arm_pcache_unified; 93 94int arm_dcache_align; 95int arm_dcache_align_mask; 96 97/* Additional cache information local to this file. Log2 of some of the 98 above numbers. */ 99static int arm_dcache_l2_nsets; 100static int arm_dcache_l2_assoc; 101static int arm_dcache_l2_linesize; 102 103 104int block_userspace_access = 0; 105extern int arm9_dcache_sets_inc; 106extern int arm9_dcache_sets_max; 107extern int arm9_dcache_index_max; 108extern int arm9_dcache_index_inc; 109 110static __inline void * 111memcpy(void *dst, const void *src, int len) 112{ 113 const char *s = src; 114 char *d = dst; 115 116 while (len) { 117 if (0 && len >= 4 && !((vm_offset_t)d & 3) && 118 !((vm_offset_t)s & 3)) { 119 *(uint32_t *)d = *(uint32_t *)s; 120 s += 4; 121 d += 4; 122 len -= 4; 123 } else { 124 *d++ = *s++; 125 len--; 126 } 127 } 128 return (dst); 129} 130 131static __inline void 132bzero(void *addr, int count) 133{ 134 char *tmp = (char *)addr; 135 136 while (count > 0) { 137 if (count >= 4 && !((vm_offset_t)tmp & 3)) { 138 *(uint32_t *)tmp = 0; 139 tmp += 4; 140 count -= 4; 141 } else { 142 *tmp = 0; 143 tmp++; 144 count--; 145 } 146 } 147} 148 149static void arm9_setup(void); 150 151void 152_startC(void) 153{ 154 int physaddr = KERNPHYSADDR; 155 int tmp1; 156 unsigned int sp = ((unsigned int)&_end & ~3) + 4; 157#if defined(FLASHADDR) && defined(LOADERRAMADDR) 158 unsigned int pc; 159 160 __asm __volatile("adr %0, _start\n" 161 : "=r" (pc)); 162 if ((FLASHADDR > LOADERRAMADDR && pc >= FLASHADDR) || 163 (FLASHADDR < LOADERRAMADDR && pc < LOADERRAMADDR)) { 164 /* 165 * We're running from flash, so just copy the whole thing 166 * from flash to memory. 167 * This is far from optimal, we could do the relocation or 168 * the unzipping directly from flash to memory to avoid this 169 * needless copy, but it would require to know the flash 170 * physical address. 171 */ 172 unsigned int target_addr; 173 unsigned int tmp_sp; 174 175 target_addr = (unsigned int)&_start - PHYSADDR + LOADERRAMADDR; 176 tmp_sp = target_addr + 0x100000 + 177 (unsigned int)&_end - (unsigned int)&_start; 178 memcpy((char *)target_addr, (char *)pc, 179 (unsigned int)&_end - (unsigned int)&_start); 180 /* Temporary set the sp and jump to the new location. */ 181 __asm __volatile( 182 "mov sp, %1\n" 183 "mov pc, %0\n" 184 : : "r" (target_addr), "r" (tmp_sp)); 185 186 } 187#endif 188#ifdef KZIP 189 sp += KERNSIZE + 0x100; 190 sp &= ~(L1_TABLE_SIZE - 1); 191 sp += 2 * L1_TABLE_SIZE; 192#endif 193 sp += 1024 * 1024; /* Should be enough for a stack */ 194 195 __asm __volatile("adr %0, 2f\n" 196 "bic %0, %0, #0xff000000\n" 197 "and %1, %1, #0xff000000\n" 198 "orr %0, %0, %1\n" 199 "mrc p15, 0, %1, c1, c0, 0\n" 200 "bic %1, %1, #1\n" /* Disable MMU */ 201 "orr %1, %1, #(4 | 8)\n" /* Add DC enable, 202 WBUF enable */ 203 "orr %1, %1, #0x1000\n" /* Add IC enable */ 204 "orr %1, %1, #(0x800)\n" /* BPRD enable */ 205 206 "mcr p15, 0, %1, c1, c0, 0\n" 207 "nop\n" 208 "nop\n" 209 "nop\n" 210 "mov pc, %0\n" 211 "2: nop\n" 212 "mov sp, %2\n" 213 : "=r" (tmp1), "+r" (physaddr), "+r" (sp)); 214#ifndef KZIP 215#ifdef CPU_ARM9 216 /* So that idcache_wbinv works; */ 217 if ((cpufunc_id() & 0x0000f000) == 0x00009000) 218 arm9_setup(); 219#endif 220 cpu_idcache_wbinv_all(); 221 cpu_l2cache_wbinv_all(); 222#endif 223 __start(); 224} 225 226static void 227get_cachetype_cp15() 228{ 229 u_int ctype, isize, dsize; 230 u_int multiplier; 231 232 __asm __volatile("mrc p15, 0, %0, c0, c0, 1" 233 : "=r" (ctype)); 234 235 /* 236 * ...and thus spake the ARM ARM: 237 * 238 * If an <opcode2> value corresponding to an unimplemented or 239 * reserved ID register is encountered, the System Control 240 * processor returns the value of the main ID register. 241 */ 242 if (ctype == cpufunc_id()) 243 goto out; 244 245 if ((ctype & CPU_CT_S) == 0) 246 arm_pcache_unified = 1; 247 248 /* 249 * If you want to know how this code works, go read the ARM ARM. 250 */ 251 252 arm_pcache_type = CPU_CT_CTYPE(ctype); 253 if (arm_pcache_unified == 0) { 254 isize = CPU_CT_ISIZE(ctype); 255 multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2; 256 arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3); 257 if (CPU_CT_xSIZE_ASSOC(isize) == 0) { 258 if (isize & CPU_CT_xSIZE_M) 259 arm_picache_line_size = 0; /* not present */ 260 else 261 arm_picache_ways = 1; 262 } else { 263 arm_picache_ways = multiplier << 264 (CPU_CT_xSIZE_ASSOC(isize) - 1); 265 } 266 arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8); 267 } 268 269 dsize = CPU_CT_DSIZE(ctype); 270 multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2; 271 arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3); 272 if (CPU_CT_xSIZE_ASSOC(dsize) == 0) { 273 if (dsize & CPU_CT_xSIZE_M) 274 arm_pdcache_line_size = 0; /* not present */ 275 else 276 arm_pdcache_ways = 1; 277 } else { 278 arm_pdcache_ways = multiplier << 279 (CPU_CT_xSIZE_ASSOC(dsize) - 1); 280 } 281 arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8); 282 283 arm_dcache_align = arm_pdcache_line_size; 284 285 arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2; 286 arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3; 287 arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) - 288 CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize); 289 out: 290 arm_dcache_align_mask = arm_dcache_align - 1; 291} 292 293static void 294arm9_setup(void) 295{ 296 297 get_cachetype_cp15(); 298 arm9_dcache_sets_inc = 1U << arm_dcache_l2_linesize; 299 arm9_dcache_sets_max = (1U << (arm_dcache_l2_linesize + 300 arm_dcache_l2_nsets)) - arm9_dcache_sets_inc; 301 arm9_dcache_index_inc = 1U << (32 - arm_dcache_l2_assoc); 302 arm9_dcache_index_max = 0U - arm9_dcache_index_inc; 303} 304 305 306#ifdef KZIP 307static unsigned char *orig_input, *i_input, *i_output; 308 309 310static u_int memcnt; /* Memory allocated: blocks */ 311static size_t memtot; /* Memory allocated: bytes */ 312/* 313 * Library functions required by inflate(). 314 */ 315 316#define MEMSIZ 0x8000 317 318/* 319 * Allocate memory block. 320 */ 321unsigned char * 322kzipmalloc(int size) 323{ 324 void *ptr; 325 static u_char mem[MEMSIZ]; 326 327 if (memtot + size > MEMSIZ) 328 return NULL; 329 ptr = mem + memtot; 330 memtot += size; 331 memcnt++; 332 return ptr; 333} 334 335/* 336 * Free allocated memory block. 337 */ 338void 339kzipfree(void *ptr) 340{ 341 memcnt--; 342 if (!memcnt) 343 memtot = 0; 344} 345 346void 347putstr(char *dummy) 348{ 349} 350 351static int 352input(void *dummy) 353{ 354 if ((size_t)(i_input - orig_input) >= KERNCOMPSIZE) { 355 return (GZ_EOF); 356 } 357 return *i_input++; 358} 359 360static int 361output(void *dummy, unsigned char *ptr, unsigned long len) 362{ 363 364 365 memcpy(i_output, ptr, len); 366 i_output += len; 367 return (0); 368} 369 370static void * 371inflate_kernel(void *kernel, void *startaddr) 372{ 373 struct inflate infl; 374 char slide[GZ_WSIZE]; 375 376 orig_input = kernel; 377 memcnt = memtot = 0; 378 i_input = (char *)kernel + GZ_HEAD; 379 if (((char *)kernel)[3] & 0x18) { 380 while (*i_input) 381 i_input++; 382 i_input++; 383 } 384 i_output = startaddr; 385 bzero(&infl, sizeof(infl)); 386 infl.gz_input = input; 387 infl.gz_output = output; 388 infl.gz_slide = slide; 389 inflate(&infl); 390 return ((char *)(((vm_offset_t)i_output & ~3) + 4)); 391} 392 393#endif 394 395void * 396load_kernel(unsigned int kstart, unsigned int curaddr,unsigned int func_end, 397 int d) 398{ 399 Elf32_Ehdr *eh; 400 Elf32_Phdr phdr[64] /* XXX */, *php; 401 Elf32_Shdr shdr[64] /* XXX */; 402 int i,j; 403 void *entry_point; 404 int symtabindex = -1; 405 int symstrindex = -1; 406 vm_offset_t lastaddr = 0; 407 Elf_Addr ssym = 0, esym = 0; 408 Elf_Dyn *dp; 409 410 eh = (Elf32_Ehdr *)kstart; 411 ssym = esym = 0; 412 entry_point = (void*)eh->e_entry; 413 memcpy(phdr, (void *)(kstart + eh->e_phoff ), 414 eh->e_phnum * sizeof(phdr[0])); 415 416 /* Determine lastaddr. */ 417 for (i = 0; i < eh->e_phnum; i++) { 418 if (lastaddr < (phdr[i].p_vaddr - KERNVIRTADDR + curaddr 419 + phdr[i].p_memsz)) 420 lastaddr = phdr[i].p_vaddr - KERNVIRTADDR + 421 curaddr + phdr[i].p_memsz; 422 } 423 424 /* Save the symbol tables, as there're about to be scratched. */ 425 memcpy(shdr, (void *)(kstart + eh->e_shoff), 426 sizeof(*shdr) * eh->e_shnum); 427 if (eh->e_shnum * eh->e_shentsize != 0 && 428 eh->e_shoff != 0) { 429 for (i = 0; i < eh->e_shnum; i++) { 430 if (shdr[i].sh_type == SHT_SYMTAB) { 431 for (j = 0; j < eh->e_phnum; j++) { 432 if (phdr[j].p_type == PT_LOAD && 433 shdr[i].sh_offset >= 434 phdr[j].p_offset && 435 (shdr[i].sh_offset + 436 shdr[i].sh_size <= 437 phdr[j].p_offset + 438 phdr[j].p_filesz)) { 439 shdr[i].sh_offset = 0; 440 shdr[i].sh_size = 0; 441 j = eh->e_phnum; 442 } 443 } 444 if (shdr[i].sh_offset != 0 && 445 shdr[i].sh_size != 0) { 446 symtabindex = i; 447 symstrindex = shdr[i].sh_link; 448 } 449 } 450 } 451 func_end = roundup(func_end, sizeof(long)); 452 if (symtabindex >= 0 && symstrindex >= 0) { 453 ssym = lastaddr; 454 if (d) { 455 memcpy((void *)func_end, (void *)( 456 shdr[symtabindex].sh_offset + kstart), 457 shdr[symtabindex].sh_size); 458 memcpy((void *)(func_end + 459 shdr[symtabindex].sh_size), 460 (void *)(shdr[symstrindex].sh_offset + 461 kstart), shdr[symstrindex].sh_size); 462 } else { 463 lastaddr += shdr[symtabindex].sh_size; 464 lastaddr = roundup(lastaddr, 465 sizeof(shdr[symtabindex].sh_size)); 466 lastaddr += sizeof(shdr[symstrindex].sh_size); 467 lastaddr += shdr[symstrindex].sh_size; 468 lastaddr = roundup(lastaddr, 469 sizeof(shdr[symstrindex].sh_size)); 470 } 471 472 } 473 } 474 if (!d) 475 return ((void *)lastaddr); 476 477 j = eh->e_phnum; 478 for (i = 0; i < j; i++) { 479 volatile char c; 480 481 if (phdr[i].p_type != PT_LOAD) 482 continue; 483 memcpy((void *)(phdr[i].p_vaddr - KERNVIRTADDR + curaddr), 484 (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz); 485 /* Clean space from oversized segments, eg: bss. */ 486 if (phdr[i].p_filesz < phdr[i].p_memsz) 487 bzero((void *)(phdr[i].p_vaddr - KERNVIRTADDR + 488 curaddr + phdr[i].p_filesz), phdr[i].p_memsz - 489 phdr[i].p_filesz); 490 } 491 /* Now grab the symbol tables. */ 492 if (symtabindex >= 0 && symstrindex >= 0) { 493 *(Elf_Size *)lastaddr = 494 shdr[symtabindex].sh_size; 495 lastaddr += sizeof(shdr[symtabindex].sh_size); 496 memcpy((void*)lastaddr, 497 (void *)func_end, 498 shdr[symtabindex].sh_size); 499 lastaddr += shdr[symtabindex].sh_size; 500 lastaddr = roundup(lastaddr, 501 sizeof(shdr[symtabindex].sh_size)); 502 *(Elf_Size *)lastaddr = 503 shdr[symstrindex].sh_size; 504 lastaddr += sizeof(shdr[symstrindex].sh_size); 505 memcpy((void*)lastaddr, 506 (void*)(func_end + 507 shdr[symtabindex].sh_size), 508 shdr[symstrindex].sh_size); 509 lastaddr += shdr[symstrindex].sh_size; 510 lastaddr = roundup(lastaddr, 511 sizeof(shdr[symstrindex].sh_size)); 512 *(Elf_Addr *)curaddr = MAGIC_TRAMP_NUMBER; 513 *((Elf_Addr *)curaddr + 1) = ssym - curaddr + KERNVIRTADDR; 514 *((Elf_Addr *)curaddr + 2) = lastaddr - curaddr + KERNVIRTADDR; 515 } else 516 *(Elf_Addr *)curaddr = 0; 517 /* Invalidate the instruction cache. */ 518 __asm __volatile("mcr p15, 0, %0, c7, c5, 0\n" 519 "mcr p15, 0, %0, c7, c10, 4\n" 520 : : "r" (curaddr)); 521 __asm __volatile("mrc p15, 0, %0, c1, c0, 0\n" 522 "bic %0, %0, #1\n" /* MMU_ENABLE */ 523 "mcr p15, 0, %0, c1, c0, 0\n" 524 : "=r" (ssym)); 525 /* Jump to the entry point. */ 526 ((void(*)(void))(entry_point - KERNVIRTADDR + curaddr))(); 527 __asm __volatile(".globl func_end\n" 528 "func_end:"); 529 530} 531 532extern char func_end[]; 533 534 535#define PMAP_DOMAIN_KERNEL 0 /* 536 * Just define it instead of including the 537 * whole VM headers set. 538 */ 539int __hack; 540static __inline void 541setup_pagetables(unsigned int pt_addr, vm_paddr_t physstart, vm_paddr_t physend, 542 int write_back) 543{ 544 unsigned int *pd = (unsigned int *)pt_addr; 545 vm_paddr_t addr; 546 int domain = (DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) | DOMAIN_CLIENT; 547 int tmp; 548 549 bzero(pd, L1_TABLE_SIZE); 550 for (addr = physstart; addr < physend; addr += L1_S_SIZE) { 551 pd[addr >> L1_S_SHIFT] = L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)| 552 L1_S_DOM(PMAP_DOMAIN_KERNEL) | addr; 553 if (write_back) 554 pd[addr >> L1_S_SHIFT] |= L1_S_B; 555 } 556 /* XXX: See below */ 557 if (0xfff00000 < physstart || 0xfff00000 > physend) 558 pd[0xfff00000 >> L1_S_SHIFT] = L1_TYPE_S|L1_S_AP(AP_KRW)| 559 L1_S_DOM(PMAP_DOMAIN_KERNEL)|physstart; 560 __asm __volatile("mcr p15, 0, %1, c2, c0, 0\n" /* set TTB */ 561 "mcr p15, 0, %1, c8, c7, 0\n" /* Flush TTB */ 562 "mcr p15, 0, %2, c3, c0, 0\n" /* Set DAR */ 563 "mrc p15, 0, %0, c1, c0, 0\n" 564 "orr %0, %0, #1\n" /* MMU_ENABLE */ 565 "mcr p15, 0, %0, c1, c0, 0\n" 566 "mrc p15, 0, %0, c2, c0, 0\n" /* CPWAIT */ 567 "mov r0, r0\n" 568 "sub pc, pc, #4\n" : 569 "=r" (tmp) : "r" (pd), "r" (domain)); 570 571 /* 572 * XXX: This is the most stupid workaround I've ever wrote. 573 * For some reason, the KB9202 won't boot the kernel unless 574 * we access an address which is not in the 575 * 0x20000000 - 0x20ffffff range. I hope I'll understand 576 * what's going on later. 577 */ 578 __hack = *(volatile int *)0xfffff21c; 579} 580 581void 582__start(void) 583{ 584 void *curaddr; 585 void *dst, *altdst; 586 char *kernel = (char *)&kernel_start; 587 int sp; 588 int pt_addr; 589 590 __asm __volatile("mov %0, pc" : 591 "=r" (curaddr)); 592 curaddr = (void*)((unsigned int)curaddr & 0xfff00000); 593#ifdef KZIP 594 if (*kernel == 0x1f && kernel[1] == 0x8b) { 595 pt_addr = (((int)&_end + KERNSIZE + 0x100) & 596 ~(L1_TABLE_SIZE - 1)) + L1_TABLE_SIZE; 597 598#ifdef CPU_ARM9 599 /* So that idcache_wbinv works; */ 600 if ((cpufunc_id() & 0x0000f000) == 0x00009000) 601 arm9_setup(); 602#endif 603 setup_pagetables(pt_addr, (vm_paddr_t)curaddr, 604 (vm_paddr_t)curaddr + 0x10000000, 1); 605 /* Gzipped kernel */ 606 dst = inflate_kernel(kernel, &_end); 607 kernel = (char *)&_end; 608 altdst = 4 + load_kernel((unsigned int)kernel, 609 (unsigned int)curaddr, 610 (unsigned int)&func_end + 800 , 0); 611 if (altdst > dst) 612 dst = altdst; 613 cpu_idcache_wbinv_all(); 614 cpu_l2cache_wbinv_all(); 615 __asm __volatile("mrc p15, 0, %0, c1, c0, 0\n" 616 "bic %0, %0, #1\n" /* MMU_ENABLE */ 617 "mcr p15, 0, %0, c1, c0, 0\n" 618 : "=r" (pt_addr)); 619 } else 620#endif 621 dst = 4 + load_kernel((unsigned int)&kernel_start, 622 (unsigned int)curaddr, 623 (unsigned int)&func_end, 0); 624 dst = (void *)(((vm_offset_t)dst & ~3)); 625 pt_addr = ((unsigned int)dst &~(L1_TABLE_SIZE - 1)) + L1_TABLE_SIZE; 626 setup_pagetables(pt_addr, (vm_paddr_t)curaddr, 627 (vm_paddr_t)curaddr + 0x10000000, 0); 628 sp = pt_addr + L1_TABLE_SIZE + 8192; 629 sp = sp &~3; 630 dst = (void *)(sp + 4); 631 memcpy((void *)dst, (void *)&load_kernel, (unsigned int)&func_end - 632 (unsigned int)&load_kernel + 800); 633 do_call(dst, kernel, dst + (unsigned int)(&func_end) - 634 (unsigned int)(&load_kernel) + 800, sp); 635} 636