1*22028508SToomas Soome /*
2*22028508SToomas Soome * Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
3*22028508SToomas Soome * All rights reserved.
4*22028508SToomas Soome *
5*22028508SToomas Soome * Redistribution and use in source and binary forms, with or without
6*22028508SToomas Soome * modification, are permitted provided that the following conditions
7*22028508SToomas Soome * are met:
8*22028508SToomas Soome * 1. Redistributions of source code must retain the above copyright
9*22028508SToomas Soome * notice, this list of conditions and the following disclaimer.
10*22028508SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
11*22028508SToomas Soome * notice, this list of conditions and the following disclaimer in the
12*22028508SToomas Soome * documentation and/or other materials provided with the distribution.
13*22028508SToomas Soome *
14*22028508SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*22028508SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*22028508SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*22028508SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*22028508SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*22028508SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*22028508SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*22028508SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*22028508SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*22028508SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*22028508SToomas Soome * SUCH DAMAGE.
25*22028508SToomas Soome */
26*22028508SToomas Soome
27*22028508SToomas Soome /*
28*22028508SToomas Soome * This multiboot implementation only implements a subset of the full
29*22028508SToomas Soome * multiboot specification in order to be able to boot Xen and a
30*22028508SToomas Soome * FreeBSD Dom0. Trying to use it to boot other multiboot compliant
31*22028508SToomas Soome * kernels will most surely fail.
32*22028508SToomas Soome *
33*22028508SToomas Soome * The full multiboot specification can be found here:
34*22028508SToomas Soome * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
35*22028508SToomas Soome */
36*22028508SToomas Soome
37*22028508SToomas Soome #include <sys/cdefs.h>
38*22028508SToomas Soome
39*22028508SToomas Soome #include <sys/param.h>
40*22028508SToomas Soome #include <sys/exec.h>
41*22028508SToomas Soome #include <sys/linker.h>
42*22028508SToomas Soome #include <sys/module.h>
43*22028508SToomas Soome #include <sys/stdint.h>
44*22028508SToomas Soome #define _MACHINE_ELF_WANT_32BIT
45*22028508SToomas Soome #include <machine/elf.h>
46*22028508SToomas Soome #include <machine/metadata.h>
47*22028508SToomas Soome #include <machine/pc/bios.h>
48*22028508SToomas Soome #include <string.h>
49*22028508SToomas Soome #include <stand.h>
50*22028508SToomas Soome
51*22028508SToomas Soome #include "bootstrap.h"
52*22028508SToomas Soome #include <sys/multiboot.h>
53*22028508SToomas Soome #include "vbe.h"
54*22028508SToomas Soome #include "libzfs.h"
55*22028508SToomas Soome #include "libi386.h"
56*22028508SToomas Soome #include "../btx/lib/btxv86.h"
57*22028508SToomas Soome
58*22028508SToomas Soome #define SUPPORT_DHCP
59*22028508SToomas Soome #include <bootp.h>
60*22028508SToomas Soome
61*22028508SToomas Soome #define MULTIBOOT_SUPPORTED_FLAGS \
62*22028508SToomas Soome (MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
63*22028508SToomas Soome #define METADATA_FIXED_SIZE (PAGE_SIZE*4)
64*22028508SToomas Soome #define METADATA_MODULE_SIZE PAGE_SIZE
65*22028508SToomas Soome
66*22028508SToomas Soome #define METADATA_RESV_SIZE(mod_num) \
67*22028508SToomas Soome roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE)
68*22028508SToomas Soome
69*22028508SToomas Soome /* MB data heap pointer */
70*22028508SToomas Soome static vm_offset_t last_addr;
71*22028508SToomas Soome
72*22028508SToomas Soome static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **);
73*22028508SToomas Soome static int multiboot_exec(struct preloaded_file *);
74*22028508SToomas Soome
75*22028508SToomas Soome static int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **);
76*22028508SToomas Soome static int multiboot_obj_exec(struct preloaded_file *fp);
77*22028508SToomas Soome
78*22028508SToomas Soome struct file_format multiboot = { multiboot_loadfile, multiboot_exec };
79*22028508SToomas Soome struct file_format multiboot_obj =
80*22028508SToomas Soome { multiboot_obj_loadfile, multiboot_obj_exec };
81*22028508SToomas Soome
82*22028508SToomas Soome static int
num_modules(struct preloaded_file * kfp)83*22028508SToomas Soome num_modules(struct preloaded_file *kfp)
84*22028508SToomas Soome {
85*22028508SToomas Soome struct kernel_module *kmp;
86*22028508SToomas Soome int mod_num = 0;
87*22028508SToomas Soome
88*22028508SToomas Soome for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next)
89*22028508SToomas Soome mod_num++;
90*22028508SToomas Soome
91*22028508SToomas Soome return (mod_num);
92*22028508SToomas Soome }
93*22028508SToomas Soome
94*22028508SToomas Soome static int
multiboot_loadfile(char * filename,u_int64_t dest,struct preloaded_file ** result)95*22028508SToomas Soome multiboot_loadfile(char *filename, u_int64_t dest,
96*22028508SToomas Soome struct preloaded_file **result)
97*22028508SToomas Soome {
98*22028508SToomas Soome uint32_t *magic;
99*22028508SToomas Soome int i, error;
100*22028508SToomas Soome caddr_t header_search;
101*22028508SToomas Soome ssize_t search_size;
102*22028508SToomas Soome int fd;
103*22028508SToomas Soome struct multiboot_header *header;
104*22028508SToomas Soome struct preloaded_file *fp;
105*22028508SToomas Soome
106*22028508SToomas Soome if (filename == NULL)
107*22028508SToomas Soome return (EFTYPE);
108*22028508SToomas Soome
109*22028508SToomas Soome /* is kernel already loaded? */
110*22028508SToomas Soome fp = file_findfile(NULL, NULL);
111*22028508SToomas Soome if (fp != NULL) {
112*22028508SToomas Soome return (EFTYPE);
113*22028508SToomas Soome }
114*22028508SToomas Soome
115*22028508SToomas Soome if ((fd = open(filename, O_RDONLY)) == -1)
116*22028508SToomas Soome return (errno);
117*22028508SToomas Soome
118*22028508SToomas Soome /*
119*22028508SToomas Soome * Read MULTIBOOT_SEARCH size in order to search for the
120*22028508SToomas Soome * multiboot magic header.
121*22028508SToomas Soome */
122*22028508SToomas Soome header_search = malloc(MULTIBOOT_SEARCH);
123*22028508SToomas Soome if (header_search == NULL) {
124*22028508SToomas Soome close(fd);
125*22028508SToomas Soome return (ENOMEM);
126*22028508SToomas Soome }
127*22028508SToomas Soome
128*22028508SToomas Soome search_size = read(fd, header_search, MULTIBOOT_SEARCH);
129*22028508SToomas Soome magic = (uint32_t *)header_search;
130*22028508SToomas Soome
131*22028508SToomas Soome header = NULL;
132*22028508SToomas Soome for (i = 0; i < (search_size / sizeof(uint32_t)); i++) {
133*22028508SToomas Soome if (magic[i] == MULTIBOOT_HEADER_MAGIC) {
134*22028508SToomas Soome header = (struct multiboot_header *)&magic[i];
135*22028508SToomas Soome break;
136*22028508SToomas Soome }
137*22028508SToomas Soome }
138*22028508SToomas Soome
139*22028508SToomas Soome if (header == NULL) {
140*22028508SToomas Soome error = EFTYPE;
141*22028508SToomas Soome goto out;
142*22028508SToomas Soome }
143*22028508SToomas Soome
144*22028508SToomas Soome /* Valid multiboot header has been found, validate checksum */
145*22028508SToomas Soome if (header->magic + header->flags + header->checksum != 0) {
146*22028508SToomas Soome printf(
147*22028508SToomas Soome "Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n",
148*22028508SToomas Soome header->magic, header->flags, header->checksum);
149*22028508SToomas Soome error = EFTYPE;
150*22028508SToomas Soome goto out;
151*22028508SToomas Soome }
152*22028508SToomas Soome
153*22028508SToomas Soome if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) {
154*22028508SToomas Soome printf("Unsupported multiboot flags found: 0x%x\n",
155*22028508SToomas Soome header->flags);
156*22028508SToomas Soome error = EFTYPE;
157*22028508SToomas Soome goto out;
158*22028508SToomas Soome }
159*22028508SToomas Soome /* AOUT KLUDGE means we just load entire flat file as blob */
160*22028508SToomas Soome if (header->flags & MULTIBOOT_AOUT_KLUDGE) {
161*22028508SToomas Soome vm_offset_t laddr;
162*22028508SToomas Soome int got;
163*22028508SToomas Soome
164*22028508SToomas Soome dest = header->load_addr;
165*22028508SToomas Soome if (lseek(fd, 0, SEEK_SET) == -1) {
166*22028508SToomas Soome printf("lseek failed\n");
167*22028508SToomas Soome error = EIO;
168*22028508SToomas Soome goto out;
169*22028508SToomas Soome }
170*22028508SToomas Soome laddr = dest;
171*22028508SToomas Soome for (;;) {
172*22028508SToomas Soome got = archsw.arch_readin(fd, laddr, 4096);
173*22028508SToomas Soome if (got == 0)
174*22028508SToomas Soome break;
175*22028508SToomas Soome if (got < 0) {
176*22028508SToomas Soome printf("error reading: %s", strerror(errno));
177*22028508SToomas Soome error = EIO;
178*22028508SToomas Soome goto out;
179*22028508SToomas Soome }
180*22028508SToomas Soome laddr += got;
181*22028508SToomas Soome }
182*22028508SToomas Soome
183*22028508SToomas Soome fp = file_alloc();
184*22028508SToomas Soome if (fp == NULL) {
185*22028508SToomas Soome error = ENOMEM;
186*22028508SToomas Soome goto out;
187*22028508SToomas Soome }
188*22028508SToomas Soome fp->f_name = strdup(filename);
189*22028508SToomas Soome fp->f_type = strdup("aout multiboot kernel");
190*22028508SToomas Soome fp->f_addr = header->entry_addr;
191*22028508SToomas Soome fp->f_size = laddr - dest;
192*22028508SToomas Soome if (fp->f_size == 0) {
193*22028508SToomas Soome file_discard(fp);
194*22028508SToomas Soome error = EIO;
195*22028508SToomas Soome goto out;
196*22028508SToomas Soome }
197*22028508SToomas Soome fp->f_metadata = NULL;
198*22028508SToomas Soome error = 0;
199*22028508SToomas Soome } else {
200*22028508SToomas Soome error = elf32_loadfile_raw(filename, dest, &fp, 1);
201*22028508SToomas Soome if (error != 0) {
202*22028508SToomas Soome printf("elf32_loadfile_raw failed: %d unable to "
203*22028508SToomas Soome "load multiboot kernel\n", error);
204*22028508SToomas Soome goto out;
205*22028508SToomas Soome }
206*22028508SToomas Soome }
207*22028508SToomas Soome
208*22028508SToomas Soome setenv("kernelname", fp->f_name, 1);
209*22028508SToomas Soome bios_addsmapdata(fp);
210*22028508SToomas Soome *result = fp;
211*22028508SToomas Soome out:
212*22028508SToomas Soome free(header_search);
213*22028508SToomas Soome close(fd);
214*22028508SToomas Soome return (error);
215*22028508SToomas Soome }
216*22028508SToomas Soome
217*22028508SToomas Soome /*
218*22028508SToomas Soome * returns allocated virtual address from MB info area
219*22028508SToomas Soome */
220*22028508SToomas Soome static vm_offset_t
mb_malloc(size_t n)221*22028508SToomas Soome mb_malloc(size_t n)
222*22028508SToomas Soome {
223*22028508SToomas Soome vm_offset_t ptr = last_addr;
224*22028508SToomas Soome if (ptr + n >= high_heap_base)
225*22028508SToomas Soome return (0);
226*22028508SToomas Soome last_addr = roundup(last_addr + n, MULTIBOOT_INFO_ALIGN);
227*22028508SToomas Soome return (ptr);
228*22028508SToomas Soome }
229*22028508SToomas Soome
230*22028508SToomas Soome static int
multiboot_exec(struct preloaded_file * fp)231*22028508SToomas Soome multiboot_exec(struct preloaded_file *fp)
232*22028508SToomas Soome {
233*22028508SToomas Soome struct preloaded_file *mfp;
234*22028508SToomas Soome vm_offset_t entry;
235*22028508SToomas Soome struct file_metadata *md;
236*22028508SToomas Soome struct multiboot_info *mb_info = NULL;
237*22028508SToomas Soome struct multiboot_mod_list *mb_mod = NULL;
238*22028508SToomas Soome multiboot_memory_map_t *mmap;
239*22028508SToomas Soome struct bios_smap *smap;
240*22028508SToomas Soome struct devdesc *rootdev;
241*22028508SToomas Soome char *cmdline = NULL;
242*22028508SToomas Soome size_t len;
243*22028508SToomas Soome int error, num, i;
244*22028508SToomas Soome int rootfs = 0; /* flag for rootfs */
245*22028508SToomas Soome int xen = 0; /* flag for xen */
246*22028508SToomas Soome int kernel = 0; /* flag for kernel */
247*22028508SToomas Soome
248*22028508SToomas Soome /* Set up base for mb_malloc. */
249*22028508SToomas Soome for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);
250*22028508SToomas Soome
251*22028508SToomas Soome /* Start info block from new page. */
252*22028508SToomas Soome last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);
253*22028508SToomas Soome
254*22028508SToomas Soome /* Allocate the multiboot struct and fill the basic details. */
255*22028508SToomas Soome mb_info = (struct multiboot_info *)PTOV(mb_malloc(sizeof (*mb_info)));
256*22028508SToomas Soome
257*22028508SToomas Soome bzero(mb_info, sizeof(struct multiboot_info));
258*22028508SToomas Soome mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME;
259*22028508SToomas Soome mb_info->mem_lower = bios_basemem / 1024;
260*22028508SToomas Soome mb_info->mem_upper = bios_extmem / 1024;
261*22028508SToomas Soome mb_info->boot_loader_name = mb_malloc(strlen(bootprog_info) + 1);
262*22028508SToomas Soome
263*22028508SToomas Soome i386_copyin(bootprog_info, mb_info->boot_loader_name,
264*22028508SToomas Soome strlen(bootprog_info) + 1);
265*22028508SToomas Soome
266*22028508SToomas Soome i386_getdev((void **)(&rootdev), NULL, NULL);
267*22028508SToomas Soome if (rootdev == NULL) {
268*22028508SToomas Soome printf("can't determine root device\n");
269*22028508SToomas Soome error = EINVAL;
270*22028508SToomas Soome goto error;
271*22028508SToomas Soome }
272*22028508SToomas Soome
273*22028508SToomas Soome /*
274*22028508SToomas Soome * Boot image command line. If args were not provided, we need to set
275*22028508SToomas Soome * args here, and that depends on image type...
276*22028508SToomas Soome * Fortunately we only have following options:
277*22028508SToomas Soome * 64 or 32 bit unix or xen. So we just check if f_name has unix.
278*22028508SToomas Soome */
279*22028508SToomas Soome /* Do we boot xen? */
280*22028508SToomas Soome if (strstr(fp->f_name, "unix") == NULL)
281*22028508SToomas Soome xen = 1;
282*22028508SToomas Soome
283*22028508SToomas Soome entry = fp->f_addr;
284*22028508SToomas Soome
285*22028508SToomas Soome num = 0;
286*22028508SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
287*22028508SToomas Soome num++;
288*22028508SToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
289*22028508SToomas Soome rootfs++;
290*22028508SToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0)
291*22028508SToomas Soome kernel++;
292*22028508SToomas Soome }
293*22028508SToomas Soome
294*22028508SToomas Soome if (num == 0 || rootfs == 0) {
295*22028508SToomas Soome /* We need at least one module - rootfs. */
296*22028508SToomas Soome printf("No rootfs module provided, aborting\n");
297*22028508SToomas Soome error = EINVAL;
298*22028508SToomas Soome goto error;
299*22028508SToomas Soome }
300*22028508SToomas Soome if (xen == 1 && kernel == 0) {
301*22028508SToomas Soome printf("No kernel module provided for xen, aborting\n");
302*22028508SToomas Soome error = EINVAL;
303*22028508SToomas Soome goto error;
304*22028508SToomas Soome }
305*22028508SToomas Soome mb_mod = (struct multiboot_mod_list *) PTOV(last_addr);
306*22028508SToomas Soome last_addr += roundup(sizeof(*mb_mod) * num, MULTIBOOT_INFO_ALIGN);
307*22028508SToomas Soome
308*22028508SToomas Soome bzero(mb_mod, sizeof(*mb_mod) * num);
309*22028508SToomas Soome
310*22028508SToomas Soome num = 0;
311*22028508SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
312*22028508SToomas Soome mb_mod[num].mod_start = mfp->f_addr;
313*22028508SToomas Soome mb_mod[num].mod_end = mfp->f_addr + mfp->f_size;
314*22028508SToomas Soome
315*22028508SToomas Soome if (strcmp(mfp->f_type, "kernel") == 0) {
316*22028508SToomas Soome cmdline = NULL;
317*22028508SToomas Soome error = mb_kernel_cmdline(mfp, rootdev, &cmdline);
318*22028508SToomas Soome if (error != 0)
319*22028508SToomas Soome goto error;
320*22028508SToomas Soome } else {
321*22028508SToomas Soome len = strlen(mfp->f_name) + 1;
322*22028508SToomas Soome len += strlen(mfp->f_type) + 5 + 1;
323*22028508SToomas Soome if (mfp->f_args != NULL) {
324*22028508SToomas Soome len += strlen(mfp->f_args) + 1;
325*22028508SToomas Soome }
326*22028508SToomas Soome cmdline = malloc(len);
327*22028508SToomas Soome if (cmdline == NULL) {
328*22028508SToomas Soome error = ENOMEM;
329*22028508SToomas Soome goto error;
330*22028508SToomas Soome }
331*22028508SToomas Soome
332*22028508SToomas Soome if (mfp->f_args != NULL)
333*22028508SToomas Soome snprintf(cmdline, len, "%s type=%s %s",
334*22028508SToomas Soome mfp->f_name, mfp->f_type, mfp->f_args);
335*22028508SToomas Soome else
336*22028508SToomas Soome snprintf(cmdline, len, "%s type=%s",
337*22028508SToomas Soome mfp->f_name, mfp->f_type);
338*22028508SToomas Soome }
339*22028508SToomas Soome
340*22028508SToomas Soome mb_mod[num].cmdline = mb_malloc(strlen(cmdline)+1);
341*22028508SToomas Soome i386_copyin(cmdline, mb_mod[num].cmdline, strlen(cmdline)+1);
342*22028508SToomas Soome free(cmdline);
343*22028508SToomas Soome num++;
344*22028508SToomas Soome }
345*22028508SToomas Soome
346*22028508SToomas Soome mb_info->mods_count = num;
347*22028508SToomas Soome mb_info->mods_addr = VTOP(mb_mod);
348*22028508SToomas Soome mb_info->flags |= MULTIBOOT_INFO_MODS;
349*22028508SToomas Soome
350*22028508SToomas Soome md = file_findmetadata(fp, MODINFOMD_SMAP);
351*22028508SToomas Soome if (md == NULL) {
352*22028508SToomas Soome printf("no memory smap\n");
353*22028508SToomas Soome error = EINVAL;
354*22028508SToomas Soome goto error;
355*22028508SToomas Soome }
356*22028508SToomas Soome
357*22028508SToomas Soome num = md->md_size / sizeof(struct bios_smap); /* number of entries */
358*22028508SToomas Soome mmap = (multiboot_memory_map_t *)PTOV(mb_malloc(sizeof(*mmap) * num));
359*22028508SToomas Soome
360*22028508SToomas Soome mb_info->mmap_length = num * sizeof(*mmap);
361*22028508SToomas Soome smap = (struct bios_smap *)md->md_data;
362*22028508SToomas Soome
363*22028508SToomas Soome for (i = 0; i < num; i++) {
364*22028508SToomas Soome mmap[i].size = sizeof(*smap);
365*22028508SToomas Soome mmap[i].addr = smap[i].base;
366*22028508SToomas Soome mmap[i].len = smap[i].length;
367*22028508SToomas Soome mmap[i].type = smap[i].type;
368*22028508SToomas Soome }
369*22028508SToomas Soome mb_info->mmap_addr = VTOP(mmap);
370*22028508SToomas Soome mb_info->flags |= MULTIBOOT_INFO_MEM_MAP;
371*22028508SToomas Soome
372*22028508SToomas Soome if (strstr(getenv("loaddev"), "net") != NULL &&
373*22028508SToomas Soome bootp_response != NULL) {
374*22028508SToomas Soome mb_info->drives_length = bootp_response_size;
375*22028508SToomas Soome mb_info->drives_addr = mb_malloc(bootp_response_size);
376*22028508SToomas Soome i386_copyin(bootp_response, mb_info->drives_addr,
377*22028508SToomas Soome bootp_response_size);
378*22028508SToomas Soome mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO;
379*22028508SToomas Soome }
380*22028508SToomas Soome /*
381*22028508SToomas Soome * Set the image command line. Need to do this as last thing,
382*22028508SToomas Soome * as illumos kernel dboot_startkern will check cmdline
383*22028508SToomas Soome * address as last check to find first free address.
384*22028508SToomas Soome */
385*22028508SToomas Soome if (fp->f_args == NULL) {
386*22028508SToomas Soome if (xen)
387*22028508SToomas Soome cmdline = getenv("xen_cmdline");
388*22028508SToomas Soome else
389*22028508SToomas Soome cmdline = getenv("boot-args");
390*22028508SToomas Soome if (cmdline != NULL) {
391*22028508SToomas Soome fp->f_args = strdup(cmdline);
392*22028508SToomas Soome if (fp->f_args == NULL) {
393*22028508SToomas Soome error = ENOMEM;
394*22028508SToomas Soome goto error;
395*22028508SToomas Soome }
396*22028508SToomas Soome }
397*22028508SToomas Soome }
398*22028508SToomas Soome
399*22028508SToomas Soome /*
400*22028508SToomas Soome * If the image is xen, we just use f_name + f_args for commandline
401*22028508SToomas Soome * for unix, we need to add zfs-bootfs.
402*22028508SToomas Soome */
403*22028508SToomas Soome if (xen) {
404*22028508SToomas Soome len = strlen(fp->f_name) + 1;
405*22028508SToomas Soome if (fp->f_args != NULL)
406*22028508SToomas Soome len += strlen(fp->f_args) + 1;
407*22028508SToomas Soome
408*22028508SToomas Soome if (fp->f_args != NULL) {
409*22028508SToomas Soome if((cmdline = malloc(len)) == NULL) {
410*22028508SToomas Soome error = ENOMEM;
411*22028508SToomas Soome goto error;
412*22028508SToomas Soome }
413*22028508SToomas Soome snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
414*22028508SToomas Soome } else {
415*22028508SToomas Soome cmdline = strdup(fp->f_name);
416*22028508SToomas Soome if (cmdline == NULL) {
417*22028508SToomas Soome error = ENOMEM;
418*22028508SToomas Soome goto error;
419*22028508SToomas Soome }
420*22028508SToomas Soome }
421*22028508SToomas Soome } else {
422*22028508SToomas Soome cmdline = NULL;
423*22028508SToomas Soome if ((error = mb_kernel_cmdline(fp, rootdev, &cmdline)) != 0)
424*22028508SToomas Soome goto error;
425*22028508SToomas Soome }
426*22028508SToomas Soome
427*22028508SToomas Soome mb_info->cmdline = mb_malloc(strlen(cmdline)+1);
428*22028508SToomas Soome i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1);
429*22028508SToomas Soome mb_info->flags |= MULTIBOOT_INFO_CMDLINE;
430*22028508SToomas Soome free(cmdline);
431*22028508SToomas Soome cmdline = NULL;
432*22028508SToomas Soome
433*22028508SToomas Soome /* make sure we have text mode */
434*22028508SToomas Soome bios_set_text_mode(VGA_TEXT_MODE);
435*22028508SToomas Soome
436*22028508SToomas Soome dev_cleanup();
437*22028508SToomas Soome __exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC,
438*22028508SToomas Soome (void *)entry, (void *)VTOP(mb_info));
439*22028508SToomas Soome
440*22028508SToomas Soome panic("exec returned");
441*22028508SToomas Soome
442*22028508SToomas Soome error:
443*22028508SToomas Soome free(cmdline);
444*22028508SToomas Soome return (error);
445*22028508SToomas Soome }
446*22028508SToomas Soome
447*22028508SToomas Soome static int
multiboot_obj_loadfile(char * filename,u_int64_t dest,struct preloaded_file ** result)448*22028508SToomas Soome multiboot_obj_loadfile(char *filename, u_int64_t dest,
449*22028508SToomas Soome struct preloaded_file **result)
450*22028508SToomas Soome {
451*22028508SToomas Soome struct preloaded_file *mfp, *kfp, *rfp;
452*22028508SToomas Soome int error, mod_num;
453*22028508SToomas Soome
454*22028508SToomas Soome /* See if there's a aout multiboot kernel loaded */
455*22028508SToomas Soome mfp = file_findfile(NULL, "aout multiboot kernel");
456*22028508SToomas Soome if (mfp != NULL) {
457*22028508SToomas Soome /* we have normal kernel loaded, add module */
458*22028508SToomas Soome rfp = file_loadraw(filename, "module", 0, NULL, 0);
459*22028508SToomas Soome if (rfp == NULL) {
460*22028508SToomas Soome printf(
461*22028508SToomas Soome "Unable to load %s as a multiboot payload module\n",
462*22028508SToomas Soome filename);
463*22028508SToomas Soome return (EINVAL);
464*22028508SToomas Soome }
465*22028508SToomas Soome rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
466*22028508SToomas Soome *result = rfp;
467*22028508SToomas Soome return (0);
468*22028508SToomas Soome }
469*22028508SToomas Soome
470*22028508SToomas Soome /* See if there's a multiboot kernel loaded */
471*22028508SToomas Soome mfp = file_findfile(NULL, "elf multiboot kernel");
472*22028508SToomas Soome if (mfp == NULL) {
473*22028508SToomas Soome return (EFTYPE); /* this allows to check other methods */
474*22028508SToomas Soome }
475*22028508SToomas Soome
476*22028508SToomas Soome /*
477*22028508SToomas Soome * We have a multiboot kernel loaded, see if there's a
478*22028508SToomas Soome * kernel loaded also.
479*22028508SToomas Soome */
480*22028508SToomas Soome kfp = file_findfile(NULL, "elf kernel");
481*22028508SToomas Soome if (kfp == NULL) {
482*22028508SToomas Soome /*
483*22028508SToomas Soome * No kernel loaded, this must be it. The kernel has to
484*22028508SToomas Soome * be loaded as a raw file, it will be processed by
485*22028508SToomas Soome * Xen and correctly loaded as an ELF file.
486*22028508SToomas Soome */
487*22028508SToomas Soome rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0);
488*22028508SToomas Soome if (rfp == NULL) {
489*22028508SToomas Soome printf(
490*22028508SToomas Soome "Unable to load %s as a multiboot payload kernel\n",
491*22028508SToomas Soome filename);
492*22028508SToomas Soome return (EINVAL);
493*22028508SToomas Soome }
494*22028508SToomas Soome
495*22028508SToomas Soome /* Load kernel metadata... */
496*22028508SToomas Soome setenv("kernelname", filename, 1);
497*22028508SToomas Soome error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size);
498*22028508SToomas Soome if (error) {
499*22028508SToomas Soome printf("Unable to load kernel %s metadata error: %d\n",
500*22028508SToomas Soome rfp->f_name, error);
501*22028508SToomas Soome return (EINVAL);
502*22028508SToomas Soome }
503*22028508SToomas Soome
504*22028508SToomas Soome /*
505*22028508SToomas Soome * Save space at the end of the kernel in order to place
506*22028508SToomas Soome * the metadata information. We do an approximation of the
507*22028508SToomas Soome * max metadata size, this is not optimal but it's probably
508*22028508SToomas Soome * the best we can do at this point. Once all modules are
509*22028508SToomas Soome * loaded and the size of the metadata is known this
510*22028508SToomas Soome * space will be recovered if not used.
511*22028508SToomas Soome */
512*22028508SToomas Soome mod_num = num_modules(rfp);
513*22028508SToomas Soome rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
514*22028508SToomas Soome rfp->f_size += METADATA_RESV_SIZE(mod_num);
515*22028508SToomas Soome *result = rfp;
516*22028508SToomas Soome } else {
517*22028508SToomas Soome /* The rest should be loaded as regular modules */
518*22028508SToomas Soome error = elf64_obj_loadfile(filename, dest, result);
519*22028508SToomas Soome if (error != 0) {
520*22028508SToomas Soome printf("Unable to load %s as an object file, error: %d",
521*22028508SToomas Soome filename, error);
522*22028508SToomas Soome return (error);
523*22028508SToomas Soome }
524*22028508SToomas Soome }
525*22028508SToomas Soome
526*22028508SToomas Soome return (0);
527*22028508SToomas Soome }
528*22028508SToomas Soome
529*22028508SToomas Soome static int
multiboot_obj_exec(struct preloaded_file * fp __unused)530*22028508SToomas Soome multiboot_obj_exec(struct preloaded_file *fp __unused)
531*22028508SToomas Soome {
532*22028508SToomas Soome
533*22028508SToomas Soome return (EFTYPE);
534*22028508SToomas Soome }
535