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#if ELFSIZE == 64 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 46#ifndef KERNNAME 47#error Kernel name not provided 48#endif 49 50extern char kernel_start[]; 51extern char kernel_end[]; 52 53static __inline void * 54memcpy(void *dst, const void *src, size_t len) 55{ 56 const char *s = src; 57 char *d = dst; 58 59 while (len) { 60 if (0 && len >= 4 && !((vm_offset_t)d & 3) && 61 !((vm_offset_t)s & 3)) { 62 *(uint32_t *)d = *(uint32_t *)s; 63 s += 4; 64 d += 4; 65 len -= 4; 66 } else { 67 *d++ = *s++; 68 len--; 69 } 70 } 71 return (dst); 72} 73 74static __inline void 75bzero(void *addr, size_t count) 76{ 77 char *tmp = (char *)addr; 78 79 while (count > 0) { 80 if (count >= 4 && !((vm_offset_t)tmp & 3)) { 81 *(uint32_t *)tmp = 0; 82 tmp += 4; 83 count -= 4; 84 } else { 85 *tmp = 0; 86 tmp++; 87 count--; 88 } 89 } 90} 91 92/* 93 * Convert number to pointer, truncate on 64->32 case, sign extend 94 * in 32->64 case 95 */ 96#define mkptr(x) ((void *)(intptr_t)(int)(x)) 97 98/* 99 * Relocate PT_LOAD segements of kernel ELF image to their respective 100 * virtual addresses and return entry point 101 */ 102void * 103load_kernel(void * kstart) 104{ 105#if ELFSIZE == 64 106 Elf64_Ehdr *eh; 107 Elf64_Phdr phdr[64] /* XXX */; 108 Elf64_Shdr shdr[64] /* XXX */; 109#else 110 Elf32_Ehdr *eh; 111 Elf32_Phdr phdr[64] /* XXX */; 112 Elf32_Shdr shdr[64] /* XXX */; 113#endif 114 int i, j; 115 void *entry_point; 116 vm_offset_t loadend = 0; 117 intptr_t lastaddr; 118 int symtabindex = -1; 119 int symstrindex = -1; 120 Elf_Size tmp; 121 122#if ELFSIZE == 64 123 eh = (Elf64_Ehdr *)kstart; 124#else 125 eh = (Elf32_Ehdr *)kstart; 126#endif 127 entry_point = mkptr(eh->e_entry); 128 memcpy(phdr, (void *)(kstart + eh->e_phoff), 129 eh->e_phnum * sizeof(phdr[0])); 130 131 memcpy(shdr, (void *)(kstart + eh->e_shoff), 132 sizeof(*shdr) * eh->e_shnum); 133 134 if (eh->e_shnum * eh->e_shentsize != 0 && eh->e_shoff != 0) { 135 for (i = 0; i < eh->e_shnum; i++) { 136 if (shdr[i].sh_type == SHT_SYMTAB) { 137 /* 138 * XXX: check if .symtab is in PT_LOAD? 139 */ 140 if (shdr[i].sh_offset != 0 && 141 shdr[i].sh_size != 0) { 142 symtabindex = i; 143 symstrindex = shdr[i].sh_link; 144 } 145 } 146 } 147 } 148 149 /* 150 * Copy loadable segments 151 */ 152 for (i = 0; i < eh->e_phnum; i++) { 153 volatile char c; 154 155 if (phdr[i].p_type != PT_LOAD) 156 continue; 157 158 memcpy(mkptr(phdr[i].p_vaddr), 159 (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz); 160 161 /* Clean space from oversized segments, eg: bss. */ 162 if (phdr[i].p_filesz < phdr[i].p_memsz) 163 bzero(mkptr(phdr[i].p_vaddr + phdr[i].p_filesz), 164 phdr[i].p_memsz - phdr[i].p_filesz); 165 166 if (loadend < phdr[i].p_vaddr + phdr[i].p_memsz) 167 loadend = phdr[i].p_vaddr + phdr[i].p_memsz; 168 } 169 170 /* Now grab the symbol tables. */ 171 lastaddr = (intptr_t)(int)loadend; 172 if (symtabindex >= 0 && symstrindex >= 0) { 173 tmp = SYMTAB_MAGIC; 174 memcpy((void *)lastaddr, &tmp, sizeof(tmp)); 175 lastaddr += sizeof(Elf_Size); 176 tmp = shdr[symtabindex].sh_size + 177 shdr[symstrindex].sh_size + 2*sizeof(Elf_Size); 178 memcpy((void *)lastaddr, &tmp, sizeof(tmp)); 179 lastaddr += sizeof(Elf_Size); 180 /* .symtab size */ 181 tmp = shdr[symtabindex].sh_size; 182 memcpy((void *)lastaddr, &tmp, sizeof(tmp)); 183 lastaddr += sizeof(shdr[symtabindex].sh_size); 184 /* .symtab data */ 185 memcpy((void*)lastaddr, 186 shdr[symtabindex].sh_offset + kstart, 187 shdr[symtabindex].sh_size); 188 lastaddr += shdr[symtabindex].sh_size; 189 190 /* .strtab size */ 191 tmp = shdr[symstrindex].sh_size; 192 memcpy((void *)lastaddr, &tmp, sizeof(tmp)); 193 lastaddr += sizeof(shdr[symstrindex].sh_size); 194 195 /* .strtab data */ 196 memcpy((void*)lastaddr, 197 shdr[symstrindex].sh_offset + kstart, 198 shdr[symstrindex].sh_size); 199 } else { 200 /* Do not take any chances */ 201 tmp = 0; 202 memcpy((void *)lastaddr, &tmp, sizeof(tmp)); 203 } 204 205 return entry_point; 206} 207 208void 209_startC(register_t a0, register_t a1, register_t a2, register_t a3) 210{ 211 unsigned int * code; 212 int i; 213 void (*entry_point)(register_t, register_t, register_t, register_t); 214 215 /* 216 * Relocate segment to the predefined memory location 217 * Most likely it will be KSEG0/KSEG1 address 218 */ 219 entry_point = load_kernel(kernel_start); 220 221 /* Pass saved registers to original _start */ 222 entry_point(a0, a1, a2, a3); 223} 224