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