elf_trampoline.c revision 202105
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$"); 27#include <machine/asm.h> 28#include <sys/param.h> 29 30#ifdef __mips_n64 31#include <sys/elf64.h> 32#else 33#include <sys/elf32.h> 34#endif 35#include <sys/inflate.h> 36#include <machine/elf.h> 37#include <machine/cpufunc.h> 38#include <machine/stdarg.h> 39 40/* 41 * Since we are compiled outside of the normal kernel build process, we 42 * need to include opt_global.h manually. 43 */ 44#include "opt_global.h" 45#include "opt_kernname.h" 46 47extern char kernel_start[]; 48extern char kernel_end[]; 49 50static __inline void * 51memcpy(void *dst, const void *src, size_t len) 52{ 53 const char *s = src; 54 char *d = dst; 55 56 while (len) { 57 if (0 && len >= 4 && !((vm_offset_t)d & 3) && 58 !((vm_offset_t)s & 3)) { 59 *(uint32_t *)d = *(uint32_t *)s; 60 s += 4; 61 d += 4; 62 len -= 4; 63 } else { 64 *d++ = *s++; 65 len--; 66 } 67 } 68 return (dst); 69} 70 71static __inline void 72bzero(void *addr, size_t count) 73{ 74 char *tmp = (char *)addr; 75 76 while (count > 0) { 77 if (count >= 4 && !((vm_offset_t)tmp & 3)) { 78 *(uint32_t *)tmp = 0; 79 tmp += 4; 80 count -= 4; 81 } else { 82 *tmp = 0; 83 tmp++; 84 count--; 85 } 86 } 87} 88 89/* 90 * Relocate PT_LOAD segements of kernel ELF image to their respective 91 * virtual addresses and return entry point 92 */ 93void * 94load_kernel(void * kstart) 95{ 96#ifdef __mips_n64 97 Elf64_Ehdr *eh; 98 Elf64_Phdr phdr[64] /* XXX */; 99#else 100 Elf32_Ehdr *eh; 101 Elf32_Phdr phdr[64] /* XXX */; 102#endif 103 int i; 104 void *entry_point; 105 106#ifdef __mips_n64 107 eh = (Elf64_Ehdr *)kstart; 108#else 109 eh = (Elf32_Ehdr *)kstart; 110#endif 111 entry_point = (void*)eh->e_entry; 112 memcpy(phdr, (void *)(kstart + eh->e_phoff ), 113 eh->e_phnum * sizeof(phdr[0])); 114 115 for (i = 0; i < eh->e_phnum; i++) { 116 volatile char c; 117 118 if (phdr[i].p_type != PT_LOAD) 119 continue; 120 121 memcpy((void *)(phdr[i].p_vaddr), 122 (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz); 123 /* Clean space from oversized segments, eg: bss. */ 124 if (phdr[i].p_filesz < phdr[i].p_memsz) 125 bzero((void *)(phdr[i].p_vaddr + phdr[i].p_filesz), 126 phdr[i].p_memsz - phdr[i].p_filesz); 127 } 128 129 return entry_point; 130} 131 132void 133_startC(register_t a0, register_t a1, register_t a2, register_t a3) 134{ 135 unsigned int * code; 136 int i; 137 void (*entry_point)(register_t, register_t, register_t, register_t); 138 139 /* 140 * Relocate segment to the predefined memory location 141 * Most likely it will be KSEG0/KSEG1 address 142 */ 143 entry_point = load_kernel(kernel_start); 144 145 /* Pass saved registers to original _start */ 146 entry_point(a0, a1, a2, a3); 147} 148