]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/elf_trampoline.c
Import tzdata 2018d
[FreeBSD/FreeBSD.git] / sys / mips / mips / elf_trampoline.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 #include <machine/asm.h>
30 #include <sys/param.h>
31
32 #if ELFSIZE == 64
33 #include <sys/elf64.h>
34 #else
35 #include <sys/elf32.h>
36 #endif
37
38 /*
39  * Since we are compiled outside of the normal kernel build process, we
40  * need to include opt_global.h manually.
41  */
42 #include "opt_global.h"
43
44 #include <sys/inflate.h>
45 #include <machine/elf.h>
46 #include <machine/cpufunc.h>
47 #include <machine/stdarg.h>
48
49 #ifndef KERNNAME
50 #error Kernel name not provided
51 #endif
52
53 extern char kernel_start[];
54 extern char kernel_end[];
55
56 static __inline void *
57 memcpy(void *dst, const void *src, size_t len)
58 {
59         const char *s = src;
60         char *d = dst;
61
62         while (len) {
63                 if (0 && len >= 4 && !((vm_offset_t)d & 3) &&
64                     !((vm_offset_t)s & 3)) {
65                         *(uint32_t *)d = *(uint32_t *)s;
66                         s += 4;
67                         d += 4;
68                         len -= 4;
69                 } else {
70                         *d++ = *s++;
71                         len--;
72                 }
73         }
74         return (dst);
75 }
76
77 static __inline void
78 bzero(void *addr, size_t count)
79 {
80         char *tmp = (char *)addr;
81
82         while (count > 0) {
83                 if (count >= 4 && !((vm_offset_t)tmp & 3)) {
84                         *(uint32_t *)tmp = 0;
85                         tmp += 4;
86                         count -= 4;
87                 } else {
88                         *tmp = 0;
89                         tmp++;
90                         count--;
91                 }
92         }
93 }
94
95 /*
96  * Convert number to pointer, truncate on 64->32 case, sign extend
97  * in 32->64 case
98  */
99 #define mkptr(x)        ((void *)(intptr_t)(int)(x))
100
101 /*
102  * Relocate PT_LOAD segements of kernel ELF image to their respective
103  * virtual addresses and return entry point
104  */
105 void *
106 load_kernel(void * kstart)
107 {
108 #if ELFSIZE == 64
109         Elf64_Ehdr *eh;
110         Elf64_Phdr phdr[64] /* XXX */;
111         Elf64_Shdr shdr[64] /* XXX */;
112 #else
113         Elf32_Ehdr *eh;
114         Elf32_Phdr phdr[64] /* XXX */;
115         Elf32_Shdr shdr[64] /* XXX */;
116 #endif
117         int i, j;
118         void *entry_point;
119         vm_offset_t loadend = 0;
120         intptr_t lastaddr;
121         int symtabindex = -1;
122         int symstrindex = -1;
123         Elf_Size tmp;
124         
125 #if ELFSIZE == 64
126         eh = (Elf64_Ehdr *)kstart;
127 #else
128         eh = (Elf32_Ehdr *)kstart;
129 #endif
130         entry_point = mkptr(eh->e_entry);
131         memcpy(phdr, (void *)(kstart + eh->e_phoff),
132             eh->e_phnum * sizeof(phdr[0]));
133
134         memcpy(shdr, (void *)(kstart + eh->e_shoff),
135             sizeof(*shdr) * eh->e_shnum);
136
137         if (eh->e_shnum * eh->e_shentsize != 0 && eh->e_shoff != 0) {
138                 for (i = 0; i < eh->e_shnum; i++) {
139                         if (shdr[i].sh_type == SHT_SYMTAB) {
140                                 /*
141                                  * XXX: check if .symtab is in PT_LOAD?
142                                  */
143                                 if (shdr[i].sh_offset != 0 && 
144                                     shdr[i].sh_size != 0) {
145                                         symtabindex = i;
146                                         symstrindex = shdr[i].sh_link;
147                                 }
148                         }
149                 }
150         }
151
152         /*
153          * Copy loadable segments
154          */
155         for (i = 0; i < eh->e_phnum; i++) {
156                 volatile char c;
157
158                 if (phdr[i].p_type != PT_LOAD)
159                         continue;
160                 
161                 memcpy(mkptr(phdr[i].p_vaddr),
162                     (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz);
163
164                 /* Clean space from oversized segments, eg: bss. */
165                 if (phdr[i].p_filesz < phdr[i].p_memsz)
166                         bzero(mkptr(phdr[i].p_vaddr + phdr[i].p_filesz),
167                             phdr[i].p_memsz - phdr[i].p_filesz);
168
169                 if (loadend < phdr[i].p_vaddr + phdr[i].p_memsz)
170                         loadend = phdr[i].p_vaddr + phdr[i].p_memsz;
171         }
172
173         /* Now grab the symbol tables. */
174         lastaddr = (intptr_t)(int)loadend;
175         if (symtabindex >= 0 && symstrindex >= 0) {
176                 tmp = SYMTAB_MAGIC;
177                 memcpy((void *)lastaddr, &tmp, sizeof(tmp));
178                 lastaddr += sizeof(Elf_Size);
179                 tmp = shdr[symtabindex].sh_size +
180                     shdr[symstrindex].sh_size + 2*sizeof(Elf_Size);
181                 memcpy((void *)lastaddr, &tmp, sizeof(tmp));
182                 lastaddr += sizeof(Elf_Size);
183                 /* .symtab size */
184                 tmp = shdr[symtabindex].sh_size;
185                 memcpy((void *)lastaddr, &tmp, sizeof(tmp));
186                 lastaddr += sizeof(shdr[symtabindex].sh_size);
187                 /* .symtab data */
188                 memcpy((void*)lastaddr,
189                     shdr[symtabindex].sh_offset + kstart,
190                     shdr[symtabindex].sh_size);
191                 lastaddr += shdr[symtabindex].sh_size;
192
193                 /* .strtab size */
194                 tmp = shdr[symstrindex].sh_size;
195                 memcpy((void *)lastaddr, &tmp, sizeof(tmp));
196                 lastaddr += sizeof(shdr[symstrindex].sh_size);
197
198                 /* .strtab data */
199                 memcpy((void*)lastaddr,
200                     shdr[symstrindex].sh_offset + kstart,
201                     shdr[symstrindex].sh_size);
202         } else {
203                 /* Do not take any chances */
204                 tmp = 0;
205                 memcpy((void *)lastaddr, &tmp, sizeof(tmp));
206         }
207
208         return entry_point;
209 }
210
211 void
212 _startC(register_t a0, register_t a1, register_t a2, register_t a3)
213 {
214         unsigned int * code;
215         int i;
216         void (*entry_point)(register_t, register_t, register_t, register_t);
217
218         /* 
219          * Relocate segment to the predefined memory location
220          * Most likely it will be KSEG0/KSEG1 address
221          */
222         entry_point = load_kernel(kernel_start);
223
224         /* Pass saved registers to original _start */
225         entry_point(a0, a1, a2, a3);
226 }