1 /* $NetBSD: exec_multiboot1.c,v 1.3 2019/10/18 01:09:46 manu Exp $ */
2
3 /*
4 * Copyright (c) 2019 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/reboot.h>
31
32 #include <i386/multiboot.h>
33
34 #include <lib/libsa/stand.h>
35 #include <lib/libkern/libkern.h>
36
37 #include "loadfile.h"
38 #include "libi386.h"
39 #include "bootinfo.h"
40 #include "bootmod.h"
41 #include "vbe.h"
42
43 extern struct btinfo_modulelist *btinfo_modulelist;
44
45 void
ksyms_addr_set(void * ehdr,void * shdr,void * symbase)46 ksyms_addr_set(void *ehdr, void *shdr, void *symbase)
47 {
48 int class;
49 Elf32_Ehdr *ehdr32 = NULL;
50 Elf64_Ehdr *ehdr64 = NULL;
51 uint64_t shnum;
52 int i;
53
54 class = ((Elf_Ehdr *)ehdr)->e_ident[EI_CLASS];
55
56 switch (class) {
57 case ELFCLASS32:
58 ehdr32 = (Elf32_Ehdr *)ehdr;
59 shnum = ehdr32->e_shnum;
60 break;
61 case ELFCLASS64:
62 ehdr64 = (Elf64_Ehdr *)ehdr;
63 shnum = ehdr64->e_shnum;
64 break;
65 default:
66 panic("Unexpected ELF class");
67 break;
68 }
69
70 for (i = 0; i < shnum; i++) {
71 Elf64_Shdr *shdrp64 = NULL;
72 Elf32_Shdr *shdrp32 = NULL;
73 uint64_t shtype, shaddr, shsize, shoffset;
74
75 switch(class) {
76 case ELFCLASS64:
77 shdrp64 = &((Elf64_Shdr *)shdr)[i];
78 shtype = shdrp64->sh_type;
79 shaddr = shdrp64->sh_addr;
80 shsize = shdrp64->sh_size;
81 shoffset = shdrp64->sh_offset;
82 break;
83 case ELFCLASS32:
84 shdrp32 = &((Elf32_Shdr *)shdr)[i];
85 shtype = shdrp32->sh_type;
86 shaddr = shdrp32->sh_addr;
87 shsize = shdrp32->sh_size;
88 shoffset = shdrp32->sh_offset;
89 break;
90 default:
91 panic("Unexpected ELF class");
92 break;
93 }
94
95 if (shtype != SHT_SYMTAB && shtype != SHT_STRTAB)
96 continue;
97
98 if (shaddr != 0 || shsize == 0)
99 continue;
100
101 shaddr = (uint64_t)(uintptr_t)(symbase + shoffset);
102
103 switch(class) {
104 case ELFCLASS64:
105 shdrp64->sh_addr = shaddr;
106 break;
107 case ELFCLASS32:
108 shdrp32->sh_addr = shaddr;
109 break;
110 default:
111 panic("Unexpected ELF class");
112 break;
113 }
114 }
115
116 return;
117 }
118
119 static int
exec_multiboot1(struct multiboot_package * mbp)120 exec_multiboot1(struct multiboot_package *mbp)
121 {
122 struct multiboot_info *mbi;
123 struct multiboot_module *mbm;
124 int i, len;
125 char *cmdline;
126 struct bi_modulelist_entry *bim;
127
128 mbi = alloc(sizeof(struct multiboot_info));
129 mbi->mi_flags = MULTIBOOT_INFO_HAS_MEMORY;
130
131 mbi->mi_mem_upper = mbp->mbp_extmem;
132 mbi->mi_mem_lower = mbp->mbp_basemem;
133
134 if (mbp->mbp_args) {
135 mbi->mi_flags |= MULTIBOOT_INFO_HAS_CMDLINE;
136 len = strlen(mbp->mbp_file) + 1 + strlen(mbp->mbp_args) + 1;
137 cmdline = alloc(len);
138 snprintf(cmdline, len, "%s %s", mbp->mbp_file, mbp->mbp_args);
139 mbi->mi_cmdline = (char *) vtophys(cmdline);
140 }
141
142 /* pull in any modules if necessary */
143 if (btinfo_modulelist) {
144 mbm = alloc(sizeof(struct multiboot_module) *
145 btinfo_modulelist->num);
146
147 bim = (struct bi_modulelist_entry *)
148 (((char *) btinfo_modulelist) +
149 sizeof(struct btinfo_modulelist));
150 for (i = 0; i < btinfo_modulelist->num; i++) {
151 mbm[i].mmo_start = bim->base;
152 mbm[i].mmo_end = bim->base + bim->len;
153 mbm[i].mmo_string = (char *)vtophys(bim->path);
154 mbm[i].mmo_reserved = 0;
155 bim++;
156 }
157 mbi->mi_flags |= MULTIBOOT_INFO_HAS_MODS;
158 mbi->mi_mods_count = btinfo_modulelist->num;
159 mbi->mi_mods_addr = vtophys(mbm);
160 }
161
162 if (mbp->mbp_marks[MARK_SYM] != 0) {
163 Elf32_Ehdr ehdr;
164 void *shbuf;
165 size_t shlen;
166 u_long shaddr;
167
168 pvbcopy((void *)mbp->mbp_marks[MARK_SYM], &ehdr, sizeof(ehdr));
169
170 if (memcmp(&ehdr.e_ident, ELFMAG, SELFMAG) != 0)
171 goto skip_ksyms;
172
173 shaddr = mbp->mbp_marks[MARK_SYM] + ehdr.e_shoff;
174
175 shlen = ehdr.e_shnum * ehdr.e_shentsize;
176 shbuf = alloc(shlen);
177
178 pvbcopy((void *)shaddr, shbuf, shlen);
179 ksyms_addr_set(&ehdr, shbuf,
180 (void *)(KERNBASE + mbp->mbp_marks[MARK_SYM]));
181 vpbcopy(shbuf, (void *)shaddr, shlen);
182
183 dealloc(shbuf, shlen);
184
185 mbi->mi_elfshdr_num = ehdr.e_shnum;
186 mbi->mi_elfshdr_size = ehdr.e_shentsize;
187 mbi->mi_elfshdr_addr = shaddr;
188 mbi->mi_elfshdr_shndx = ehdr.e_shstrndx;
189
190 mbi->mi_flags |= MULTIBOOT_INFO_HAS_ELF_SYMS;
191 }
192 skip_ksyms:
193
194 #ifdef DEBUG
195 printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n",
196 mbp->mbp_marks[MARK_ENTRY],
197 mbp->mbp_marks[MARK_NSYM],
198 mbp->mbp_marks[MARK_SYM],
199 mbp->mbp_marks[MARK_END]);
200 #endif
201
202 /* Does not return */
203 multiboot(mbp->mbp_marks[MARK_ENTRY], vtophys(mbi),
204 x86_trunc_page(mbi->mi_mem_lower * 1024), MULTIBOOT_INFO_MAGIC);
205
206 return 0;
207 }
208
209 static void
cleanup_multiboot1(struct multiboot_package * mbp)210 cleanup_multiboot1(struct multiboot_package *mbp)
211 {
212 dealloc(mbp->mbp_header, sizeof(*mbp->mbp_header));
213 dealloc(mbp, sizeof(*mbp));
214
215 return;
216 }
217
218
219 struct multiboot_package *
probe_multiboot1(const char * path)220 probe_multiboot1(const char *path)
221 {
222 int fd = -1;
223 size_t i;
224 char buf[8192 + sizeof(struct multiboot_header)];
225 ssize_t readen;
226 struct multiboot_package *mbp = NULL;
227
228 if ((fd = open(path, 0)) == -1)
229 goto out;
230
231 readen = read(fd, buf, sizeof(buf));
232 if (readen < sizeof(struct multiboot_header))
233 goto out;
234
235 for (i = 0; i < readen; i += 4) {
236 struct multiboot_header *mbh;
237
238 mbh = (struct multiboot_header *)(buf + i);
239
240 if (mbh->mh_magic != MULTIBOOT_HEADER_MAGIC)
241 continue;
242
243 if (mbh->mh_magic + mbh->mh_flags + mbh->mh_checksum)
244 continue;
245
246 mbp = alloc(sizeof(*mbp));
247 mbp->mbp_version = 1;
248 mbp->mbp_file = path;
249 mbp->mbp_header = alloc(sizeof(*mbp->mbp_header));
250 mbp->mbp_probe = *probe_multiboot1;
251 mbp->mbp_exec = *exec_multiboot1;
252 mbp->mbp_cleanup = *cleanup_multiboot1;
253
254 memcpy(mbp->mbp_header, mbh, sizeof(*mbp->mbp_header));
255
256 goto out;
257
258 }
259
260 out:
261 if (fd != -1)
262 close(fd);
263
264 return mbp;
265 }
266