13d4c0714SToomas Soome /*
2199767f8SToomas Soome * Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
3199767f8SToomas Soome * All rights reserved.
4199767f8SToomas Soome *
5199767f8SToomas Soome * Redistribution and use in source and binary forms, with or without
6199767f8SToomas Soome * modification, are permitted provided that the following conditions
7199767f8SToomas Soome * are met:
8199767f8SToomas Soome * 1. Redistributions of source code must retain the above copyright
9199767f8SToomas Soome * notice, this list of conditions and the following disclaimer.
10199767f8SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
11199767f8SToomas Soome * notice, this list of conditions and the following disclaimer in the
12199767f8SToomas Soome * documentation and/or other materials provided with the distribution.
13199767f8SToomas Soome *
14199767f8SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15199767f8SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16199767f8SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17199767f8SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18199767f8SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19199767f8SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20199767f8SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21199767f8SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22199767f8SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23199767f8SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24199767f8SToomas Soome * SUCH DAMAGE.
25199767f8SToomas Soome */
26199767f8SToomas Soome
27199767f8SToomas Soome /*
28199767f8SToomas Soome * This multiboot implementation only implements a subset of the full
29199767f8SToomas Soome * multiboot specification in order to be able to boot Xen and a
30199767f8SToomas Soome * FreeBSD Dom0. Trying to use it to boot other multiboot compliant
31199767f8SToomas Soome * kernels will most surely fail.
32199767f8SToomas Soome *
33199767f8SToomas Soome * The full multiboot specification can be found here:
34199767f8SToomas Soome * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
35199767f8SToomas Soome */
36199767f8SToomas Soome
37199767f8SToomas Soome #include <sys/cdefs.h>
38199767f8SToomas Soome
39199767f8SToomas Soome #include <sys/param.h>
40199767f8SToomas Soome #include <sys/exec.h>
41199767f8SToomas Soome #include <sys/linker.h>
42199767f8SToomas Soome #include <sys/module.h>
43199767f8SToomas Soome #include <sys/stdint.h>
44199767f8SToomas Soome #define _MACHINE_ELF_WANT_32BIT
45199767f8SToomas Soome #include <machine/elf.h>
46199767f8SToomas Soome #include <machine/metadata.h>
47199767f8SToomas Soome #include <machine/pc/bios.h>
48199767f8SToomas Soome #include <string.h>
49199767f8SToomas Soome #include <stand.h>
50199767f8SToomas Soome
51199767f8SToomas Soome #include "bootstrap.h"
5223274804SToomas Soome #include <sys/multiboot.h>
539890ff83SToomas Soome #include "vbe.h"
543d4c0714SToomas Soome #include "libzfs.h"
553d4c0714SToomas Soome #include "libi386.h"
563d4c0714SToomas Soome #include "../btx/lib/btxv86.h"
57199767f8SToomas Soome
58f9feecc1SToomas Soome #define SUPPORT_DHCP
59f9feecc1SToomas Soome #include <bootp.h>
60f9feecc1SToomas Soome
61199767f8SToomas Soome #define MULTIBOOT_SUPPORTED_FLAGS \
62199767f8SToomas Soome (MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
63199767f8SToomas Soome #define METADATA_FIXED_SIZE (PAGE_SIZE*4)
64199767f8SToomas Soome #define METADATA_MODULE_SIZE PAGE_SIZE
65199767f8SToomas Soome
66199767f8SToomas Soome #define METADATA_RESV_SIZE(mod_num) \
67199767f8SToomas Soome roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE)
68199767f8SToomas Soome
69199767f8SToomas Soome /* MB data heap pointer */
70199767f8SToomas Soome static vm_offset_t last_addr;
71199767f8SToomas Soome
72199767f8SToomas Soome static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **);
73199767f8SToomas Soome static int multiboot_exec(struct preloaded_file *);
74199767f8SToomas Soome
75199767f8SToomas Soome static int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **);
76199767f8SToomas Soome static int multiboot_obj_exec(struct preloaded_file *fp);
77199767f8SToomas Soome
78199767f8SToomas Soome struct file_format multiboot = { multiboot_loadfile, multiboot_exec };
79199767f8SToomas Soome struct file_format multiboot_obj =
80199767f8SToomas Soome { multiboot_obj_loadfile, multiboot_obj_exec };
81199767f8SToomas Soome
82199767f8SToomas Soome static int
num_modules(struct preloaded_file * kfp)83199767f8SToomas Soome num_modules(struct preloaded_file *kfp)
84199767f8SToomas Soome {
85199767f8SToomas Soome struct kernel_module *kmp;
86199767f8SToomas Soome int mod_num = 0;
87199767f8SToomas Soome
88199767f8SToomas Soome for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next)
89199767f8SToomas Soome mod_num++;
90199767f8SToomas Soome
91199767f8SToomas Soome return (mod_num);
92199767f8SToomas Soome }
93199767f8SToomas Soome
94199767f8SToomas Soome static int
multiboot_loadfile(char * filename,u_int64_t dest,struct preloaded_file ** result)95199767f8SToomas Soome multiboot_loadfile(char *filename, u_int64_t dest,
96199767f8SToomas Soome struct preloaded_file **result)
97199767f8SToomas Soome {
98199767f8SToomas Soome uint32_t *magic;
99199767f8SToomas Soome int i, error;
100199767f8SToomas Soome caddr_t header_search;
101199767f8SToomas Soome ssize_t search_size;
102199767f8SToomas Soome int fd;
103199767f8SToomas Soome struct multiboot_header *header;
104199767f8SToomas Soome struct preloaded_file *fp;
105199767f8SToomas Soome
106199767f8SToomas Soome if (filename == NULL)
107199767f8SToomas Soome return (EFTYPE);
108199767f8SToomas Soome
109199767f8SToomas Soome /* is kernel already loaded? */
110199767f8SToomas Soome fp = file_findfile(NULL, NULL);
111199767f8SToomas Soome if (fp != NULL) {
112199767f8SToomas Soome return (EFTYPE);
113199767f8SToomas Soome }
114199767f8SToomas Soome
115199767f8SToomas Soome if ((fd = open(filename, O_RDONLY)) == -1)
116199767f8SToomas Soome return (errno);
117199767f8SToomas Soome
118199767f8SToomas Soome /*
119199767f8SToomas Soome * Read MULTIBOOT_SEARCH size in order to search for the
120199767f8SToomas Soome * multiboot magic header.
121199767f8SToomas Soome */
122199767f8SToomas Soome header_search = malloc(MULTIBOOT_SEARCH);
123199767f8SToomas Soome if (header_search == NULL) {
124199767f8SToomas Soome close(fd);
125199767f8SToomas Soome return (ENOMEM);
126199767f8SToomas Soome }
127199767f8SToomas Soome
128199767f8SToomas Soome search_size = read(fd, header_search, MULTIBOOT_SEARCH);
129199767f8SToomas Soome magic = (uint32_t *)header_search;
130199767f8SToomas Soome
131199767f8SToomas Soome header = NULL;
132199767f8SToomas Soome for (i = 0; i < (search_size / sizeof(uint32_t)); i++) {
133199767f8SToomas Soome if (magic[i] == MULTIBOOT_HEADER_MAGIC) {
134199767f8SToomas Soome header = (struct multiboot_header *)&magic[i];
135199767f8SToomas Soome break;
136199767f8SToomas Soome }
137199767f8SToomas Soome }
138199767f8SToomas Soome
139199767f8SToomas Soome if (header == NULL) {
140199767f8SToomas Soome error = EFTYPE;
141199767f8SToomas Soome goto out;
142199767f8SToomas Soome }
143199767f8SToomas Soome
144199767f8SToomas Soome /* Valid multiboot header has been found, validate checksum */
145199767f8SToomas Soome if (header->magic + header->flags + header->checksum != 0) {
146199767f8SToomas Soome printf(
147199767f8SToomas Soome "Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n",
148199767f8SToomas Soome header->magic, header->flags, header->checksum);
149199767f8SToomas Soome error = EFTYPE;
150199767f8SToomas Soome goto out;
151199767f8SToomas Soome }
152199767f8SToomas Soome
153199767f8SToomas Soome if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) {
154199767f8SToomas Soome printf("Unsupported multiboot flags found: 0x%x\n",
155199767f8SToomas Soome header->flags);
156199767f8SToomas Soome error = EFTYPE;
157199767f8SToomas Soome goto out;
158199767f8SToomas Soome }
159199767f8SToomas Soome /* AOUT KLUDGE means we just load entire flat file as blob */
160199767f8SToomas Soome if (header->flags & MULTIBOOT_AOUT_KLUDGE) {
161199767f8SToomas Soome vm_offset_t laddr;
162199767f8SToomas Soome int got;
163199767f8SToomas Soome
164199767f8SToomas Soome dest = header->load_addr;
165199767f8SToomas Soome if (lseek(fd, 0, SEEK_SET) == -1) {
166199767f8SToomas Soome printf("lseek failed\n");
167199767f8SToomas Soome error = EIO;
168199767f8SToomas Soome goto out;
169199767f8SToomas Soome }
170199767f8SToomas Soome laddr = dest;
171199767f8SToomas Soome for (;;) {
172199767f8SToomas Soome got = archsw.arch_readin(fd, laddr, 4096);
173199767f8SToomas Soome if (got == 0)
174199767f8SToomas Soome break;
175199767f8SToomas Soome if (got < 0) {
176199767f8SToomas Soome printf("error reading: %s", strerror(errno));
177199767f8SToomas Soome error = EIO;
178199767f8SToomas Soome goto out;
179199767f8SToomas Soome }
180199767f8SToomas Soome laddr += got;
181199767f8SToomas Soome }
182199767f8SToomas Soome
183199767f8SToomas Soome fp = file_alloc();
184199767f8SToomas Soome if (fp == NULL) {
185199767f8SToomas Soome error = ENOMEM;
186199767f8SToomas Soome goto out;
187199767f8SToomas Soome }
188199767f8SToomas Soome fp->f_name = strdup(filename);
189199767f8SToomas Soome fp->f_type = strdup("aout multiboot kernel");
190199767f8SToomas Soome fp->f_addr = header->entry_addr;
191199767f8SToomas Soome fp->f_size = laddr - dest;
192199767f8SToomas Soome if (fp->f_size == 0) {
193199767f8SToomas Soome file_discard(fp);
194199767f8SToomas Soome error = EIO;
195199767f8SToomas Soome goto out;
196199767f8SToomas Soome }
197199767f8SToomas Soome fp->f_metadata = NULL;
198199767f8SToomas Soome error = 0;
199199767f8SToomas Soome } else {
20014ee0d29SToomas Soome error = elf32_loadfile_raw(filename, dest, &fp, 1);
201199767f8SToomas Soome if (error != 0) {
202199767f8SToomas Soome printf("elf32_loadfile_raw failed: %d unable to "
203199767f8SToomas Soome "load multiboot kernel\n", error);
204199767f8SToomas Soome goto out;
205199767f8SToomas Soome }
206199767f8SToomas Soome }
207199767f8SToomas Soome
20814ee0d29SToomas Soome setenv("kernelname", fp->f_name, 1);
20914ee0d29SToomas Soome bios_addsmapdata(fp);
21014ee0d29SToomas Soome *result = fp;
211199767f8SToomas Soome out:
212199767f8SToomas Soome free(header_search);
213199767f8SToomas Soome close(fd);
214199767f8SToomas Soome return (error);
215199767f8SToomas Soome }
216199767f8SToomas Soome
217199767f8SToomas Soome /*
218199767f8SToomas Soome * returns allocated virtual address from MB info area
219199767f8SToomas Soome */
220199767f8SToomas Soome static vm_offset_t
mb_malloc(size_t n)221199767f8SToomas Soome mb_malloc(size_t n)
222199767f8SToomas Soome {
223199767f8SToomas Soome vm_offset_t ptr = last_addr;
224199767f8SToomas Soome if (ptr + n >= high_heap_base)
225199767f8SToomas Soome return (0);
226199767f8SToomas Soome last_addr = roundup(last_addr + n, MULTIBOOT_INFO_ALIGN);
227199767f8SToomas Soome return (ptr);
228199767f8SToomas Soome }
229199767f8SToomas Soome
230199767f8SToomas Soome static int
multiboot_exec(struct preloaded_file * fp)231199767f8SToomas Soome multiboot_exec(struct preloaded_file *fp)
232199767f8SToomas Soome {
233199767f8SToomas Soome struct preloaded_file *mfp;
2346649cbccSToomas Soome vm_offset_t entry;
235199767f8SToomas Soome struct file_metadata *md;
236199767f8SToomas Soome struct multiboot_info *mb_info = NULL;
237199767f8SToomas Soome struct multiboot_mod_list *mb_mod = NULL;
238199767f8SToomas Soome multiboot_memory_map_t *mmap;
239199767f8SToomas Soome struct bios_smap *smap;
24014ee0d29SToomas Soome struct devdesc *rootdev;
241199767f8SToomas Soome char *cmdline = NULL;
242199767f8SToomas Soome size_t len;
243199767f8SToomas Soome int error, num, i;
244199767f8SToomas Soome int rootfs = 0; /* flag for rootfs */
245199767f8SToomas Soome int xen = 0; /* flag for xen */
246199767f8SToomas Soome int kernel = 0; /* flag for kernel */
247199767f8SToomas Soome
24814ee0d29SToomas Soome /* Set up base for mb_malloc. */
249199767f8SToomas Soome for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);
250199767f8SToomas Soome
25114ee0d29SToomas Soome /* Start info block from new page. */
252199767f8SToomas Soome last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);
253199767f8SToomas Soome
254199767f8SToomas Soome /* Allocate the multiboot struct and fill the basic details. */
255199767f8SToomas Soome mb_info = (struct multiboot_info *)PTOV(mb_malloc(sizeof (*mb_info)));
256199767f8SToomas Soome
257199767f8SToomas Soome bzero(mb_info, sizeof(struct multiboot_info));
258199767f8SToomas Soome mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME;
259199767f8SToomas Soome mb_info->mem_lower = bios_basemem / 1024;
260199767f8SToomas Soome mb_info->mem_upper = bios_extmem / 1024;
26114ee0d29SToomas Soome mb_info->boot_loader_name = mb_malloc(strlen(bootprog_info) + 1);
262199767f8SToomas Soome
26314ee0d29SToomas Soome i386_copyin(bootprog_info, mb_info->boot_loader_name,
26414ee0d29SToomas Soome strlen(bootprog_info) + 1);
265199767f8SToomas Soome
266199767f8SToomas Soome i386_getdev((void **)(&rootdev), NULL, NULL);
267199767f8SToomas Soome if (rootdev == NULL) {
268199767f8SToomas Soome printf("can't determine root device\n");
269199767f8SToomas Soome error = EINVAL;
270199767f8SToomas Soome goto error;
271199767f8SToomas Soome }
272199767f8SToomas Soome
273199767f8SToomas Soome /*
27414ee0d29SToomas Soome * Boot image command line. If args were not provided, we need to set
275199767f8SToomas Soome * args here, and that depends on image type...
27614ee0d29SToomas Soome * Fortunately we only have following options:
27714ee0d29SToomas Soome * 64 or 32 bit unix or xen. So we just check if f_name has unix.
278199767f8SToomas Soome */
27914ee0d29SToomas Soome /* Do we boot xen? */
280199767f8SToomas Soome if (strstr(fp->f_name, "unix") == NULL)
281199767f8SToomas Soome xen = 1;
282199767f8SToomas Soome
283199767f8SToomas Soome entry = fp->f_addr;
284199767f8SToomas Soome
285199767f8SToomas Soome num = 0;
286199767f8SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
287199767f8SToomas Soome num++;
288199767f8SToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
289199767f8SToomas Soome rootfs++;
290199767f8SToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0)
291199767f8SToomas Soome kernel++;
292199767f8SToomas Soome }
293199767f8SToomas Soome
294199767f8SToomas Soome if (num == 0 || rootfs == 0) {
29514ee0d29SToomas Soome /* We need at least one module - rootfs. */
296199767f8SToomas Soome printf("No rootfs module provided, aborting\n");
297199767f8SToomas Soome error = EINVAL;
298199767f8SToomas Soome goto error;
299199767f8SToomas Soome }
300199767f8SToomas Soome if (xen == 1 && kernel == 0) {
301199767f8SToomas Soome printf("No kernel module provided for xen, aborting\n");
302199767f8SToomas Soome error = EINVAL;
303199767f8SToomas Soome goto error;
304199767f8SToomas Soome }
305199767f8SToomas Soome mb_mod = (struct multiboot_mod_list *) PTOV(last_addr);
306199767f8SToomas Soome last_addr += roundup(sizeof(*mb_mod) * num, MULTIBOOT_INFO_ALIGN);
307199767f8SToomas Soome
308199767f8SToomas Soome bzero(mb_mod, sizeof(*mb_mod) * num);
309199767f8SToomas Soome
310199767f8SToomas Soome num = 0;
311199767f8SToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
312199767f8SToomas Soome mb_mod[num].mod_start = mfp->f_addr;
313199767f8SToomas Soome mb_mod[num].mod_end = mfp->f_addr + mfp->f_size;
314199767f8SToomas Soome
315199767f8SToomas Soome if (strcmp(mfp->f_type, "kernel") == 0) {
3166fec69aaSToomas Soome cmdline = NULL;
31714ee0d29SToomas Soome error = mb_kernel_cmdline(mfp, rootdev, &cmdline);
3186fec69aaSToomas Soome if (error != 0)
319199767f8SToomas Soome goto error;
320199767f8SToomas Soome } else {
321199767f8SToomas Soome len = strlen(mfp->f_name) + 1;
322199767f8SToomas Soome len += strlen(mfp->f_type) + 5 + 1;
323199767f8SToomas Soome if (mfp->f_args != NULL) {
324199767f8SToomas Soome len += strlen(mfp->f_args) + 1;
325199767f8SToomas Soome }
326199767f8SToomas Soome cmdline = malloc(len);
327199767f8SToomas Soome if (cmdline == NULL) {
328199767f8SToomas Soome error = ENOMEM;
329199767f8SToomas Soome goto error;
330199767f8SToomas Soome }
331199767f8SToomas Soome
332199767f8SToomas Soome if (mfp->f_args != NULL)
333199767f8SToomas Soome snprintf(cmdline, len, "%s type=%s %s",
334199767f8SToomas Soome mfp->f_name, mfp->f_type, mfp->f_args);
335199767f8SToomas Soome else
336199767f8SToomas Soome snprintf(cmdline, len, "%s type=%s",
337199767f8SToomas Soome mfp->f_name, mfp->f_type);
338199767f8SToomas Soome }
339199767f8SToomas Soome
340199767f8SToomas Soome mb_mod[num].cmdline = mb_malloc(strlen(cmdline)+1);
341199767f8SToomas Soome i386_copyin(cmdline, mb_mod[num].cmdline, strlen(cmdline)+1);
342199767f8SToomas Soome free(cmdline);
343199767f8SToomas Soome num++;
344199767f8SToomas Soome }
345199767f8SToomas Soome
346199767f8SToomas Soome mb_info->mods_count = num;
347199767f8SToomas Soome mb_info->mods_addr = VTOP(mb_mod);
348199767f8SToomas Soome mb_info->flags |= MULTIBOOT_INFO_MODS;
349199767f8SToomas Soome
350199767f8SToomas Soome md = file_findmetadata(fp, MODINFOMD_SMAP);
351199767f8SToomas Soome if (md == NULL) {
352199767f8SToomas Soome printf("no memory smap\n");
353199767f8SToomas Soome error = EINVAL;
354199767f8SToomas Soome goto error;
355199767f8SToomas Soome }
356199767f8SToomas Soome
357199767f8SToomas Soome num = md->md_size / sizeof(struct bios_smap); /* number of entries */
358199767f8SToomas Soome mmap = (multiboot_memory_map_t *)PTOV(mb_malloc(sizeof(*mmap) * num));
359199767f8SToomas Soome
360199767f8SToomas Soome mb_info->mmap_length = num * sizeof(*mmap);
361199767f8SToomas Soome smap = (struct bios_smap *)md->md_data;
362199767f8SToomas Soome
363199767f8SToomas Soome for (i = 0; i < num; i++) {
364199767f8SToomas Soome mmap[i].size = sizeof(*smap);
365199767f8SToomas Soome mmap[i].addr = smap[i].base;
366199767f8SToomas Soome mmap[i].len = smap[i].length;
367199767f8SToomas Soome mmap[i].type = smap[i].type;
368199767f8SToomas Soome }
369199767f8SToomas Soome mb_info->mmap_addr = VTOP(mmap);
370199767f8SToomas Soome mb_info->flags |= MULTIBOOT_INFO_MEM_MAP;
371199767f8SToomas Soome
372859472daSToomas Soome if (strstr(getenv("loaddev"), "net") != NULL &&
373f9feecc1SToomas Soome bootp_response != NULL) {
374859472daSToomas Soome mb_info->drives_length = bootp_response_size;
375859472daSToomas Soome mb_info->drives_addr = mb_malloc(bootp_response_size);
376f9feecc1SToomas Soome i386_copyin(bootp_response, mb_info->drives_addr,
377859472daSToomas Soome bootp_response_size);
378199767f8SToomas Soome mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO;
379199767f8SToomas Soome }
380199767f8SToomas Soome /*
381199767f8SToomas Soome * Set the image command line. Need to do this as last thing,
38214ee0d29SToomas Soome * as illumos kernel dboot_startkern will check cmdline
383199767f8SToomas Soome * address as last check to find first free address.
384199767f8SToomas Soome */
385199767f8SToomas Soome if (fp->f_args == NULL) {
386199767f8SToomas Soome if (xen)
387199767f8SToomas Soome cmdline = getenv("xen_cmdline");
388199767f8SToomas Soome else
389199767f8SToomas Soome cmdline = getenv("boot-args");
390199767f8SToomas Soome if (cmdline != NULL) {
391199767f8SToomas Soome fp->f_args = strdup(cmdline);
392199767f8SToomas Soome if (fp->f_args == NULL) {
393199767f8SToomas Soome error = ENOMEM;
394199767f8SToomas Soome goto error;
395199767f8SToomas Soome }
396199767f8SToomas Soome }
397199767f8SToomas Soome }
398199767f8SToomas Soome
399199767f8SToomas Soome /*
40014ee0d29SToomas Soome * If the image is xen, we just use f_name + f_args for commandline
401199767f8SToomas Soome * for unix, we need to add zfs-bootfs.
402199767f8SToomas Soome */
403199767f8SToomas Soome if (xen) {
404199767f8SToomas Soome len = strlen(fp->f_name) + 1;
405199767f8SToomas Soome if (fp->f_args != NULL)
406199767f8SToomas Soome len += strlen(fp->f_args) + 1;
407199767f8SToomas Soome
408199767f8SToomas Soome if (fp->f_args != NULL) {
409199767f8SToomas Soome if((cmdline = malloc(len)) == NULL) {
410199767f8SToomas Soome error = ENOMEM;
411199767f8SToomas Soome goto error;
412199767f8SToomas Soome }
413199767f8SToomas Soome snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
414199767f8SToomas Soome } else {
415199767f8SToomas Soome cmdline = strdup(fp->f_name);
4166fec69aaSToomas Soome if (cmdline == NULL) {
4176fec69aaSToomas Soome error = ENOMEM;
4186fec69aaSToomas Soome goto error;
4196fec69aaSToomas Soome }
420199767f8SToomas Soome }
421199767f8SToomas Soome } else {
4226fec69aaSToomas Soome cmdline = NULL;
42314ee0d29SToomas Soome if ((error = mb_kernel_cmdline(fp, rootdev, &cmdline)) != 0)
4246fec69aaSToomas Soome goto error;
425199767f8SToomas Soome }
426199767f8SToomas Soome
427199767f8SToomas Soome mb_info->cmdline = mb_malloc(strlen(cmdline)+1);
428199767f8SToomas Soome i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1);
429199767f8SToomas Soome mb_info->flags |= MULTIBOOT_INFO_CMDLINE;
430199767f8SToomas Soome free(cmdline);
431199767f8SToomas Soome cmdline = NULL;
432199767f8SToomas Soome
4339890ff83SToomas Soome /* make sure we have text mode */
4349890ff83SToomas Soome bios_set_text_mode(VGA_TEXT_MODE);
4359890ff83SToomas Soome
436199767f8SToomas Soome dev_cleanup();
43714ee0d29SToomas Soome __exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC,
43814ee0d29SToomas Soome (void *)entry, (void *)VTOP(mb_info));
439199767f8SToomas Soome
440199767f8SToomas Soome panic("exec returned");
441199767f8SToomas Soome
442199767f8SToomas Soome error:
4436fec69aaSToomas Soome free(cmdline);
444199767f8SToomas Soome return (error);
445199767f8SToomas Soome }
446199767f8SToomas Soome
447199767f8SToomas Soome static int
multiboot_obj_loadfile(char * filename,u_int64_t dest,struct preloaded_file ** result)448199767f8SToomas Soome multiboot_obj_loadfile(char *filename, u_int64_t dest,
449199767f8SToomas Soome struct preloaded_file **result)
450199767f8SToomas Soome {
451199767f8SToomas Soome struct preloaded_file *mfp, *kfp, *rfp;
452199767f8SToomas Soome int error, mod_num;
453199767f8SToomas Soome
454199767f8SToomas Soome /* See if there's a aout multiboot kernel loaded */
455199767f8SToomas Soome mfp = file_findfile(NULL, "aout multiboot kernel");
456199767f8SToomas Soome if (mfp != NULL) {
457199767f8SToomas Soome /* we have normal kernel loaded, add module */
458199767f8SToomas Soome rfp = file_loadraw(filename, "module", 0, NULL, 0);
459199767f8SToomas Soome if (rfp == NULL) {
460199767f8SToomas Soome printf(
461199767f8SToomas Soome "Unable to load %s as a multiboot payload module\n",
462199767f8SToomas Soome filename);
463199767f8SToomas Soome return (EINVAL);
464199767f8SToomas Soome }
465199767f8SToomas Soome rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
466199767f8SToomas Soome *result = rfp;
467199767f8SToomas Soome return (0);
468199767f8SToomas Soome }
469199767f8SToomas Soome
470199767f8SToomas Soome /* See if there's a multiboot kernel loaded */
471199767f8SToomas Soome mfp = file_findfile(NULL, "elf multiboot kernel");
472199767f8SToomas Soome if (mfp == NULL) {
473199767f8SToomas Soome return (EFTYPE); /* this allows to check other methods */
474199767f8SToomas Soome }
475199767f8SToomas Soome
476199767f8SToomas Soome /*
477199767f8SToomas Soome * We have a multiboot kernel loaded, see if there's a
478199767f8SToomas Soome * kernel loaded also.
479199767f8SToomas Soome */
480199767f8SToomas Soome kfp = file_findfile(NULL, "elf kernel");
481199767f8SToomas Soome if (kfp == NULL) {
482199767f8SToomas Soome /*
483199767f8SToomas Soome * No kernel loaded, this must be it. The kernel has to
484199767f8SToomas Soome * be loaded as a raw file, it will be processed by
485199767f8SToomas Soome * Xen and correctly loaded as an ELF file.
486199767f8SToomas Soome */
487199767f8SToomas Soome rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0);
488199767f8SToomas Soome if (rfp == NULL) {
489199767f8SToomas Soome printf(
490199767f8SToomas Soome "Unable to load %s as a multiboot payload kernel\n",
491199767f8SToomas Soome filename);
492199767f8SToomas Soome return (EINVAL);
493199767f8SToomas Soome }
494199767f8SToomas Soome
495199767f8SToomas Soome /* Load kernel metadata... */
496199767f8SToomas Soome setenv("kernelname", filename, 1);
497199767f8SToomas Soome error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size);
498199767f8SToomas Soome if (error) {
499199767f8SToomas Soome printf("Unable to load kernel %s metadata error: %d\n",
500199767f8SToomas Soome rfp->f_name, error);
501199767f8SToomas Soome return (EINVAL);
502199767f8SToomas Soome }
503199767f8SToomas Soome
504199767f8SToomas Soome /*
505199767f8SToomas Soome * Save space at the end of the kernel in order to place
506199767f8SToomas Soome * the metadata information. We do an approximation of the
507199767f8SToomas Soome * max metadata size, this is not optimal but it's probably
508199767f8SToomas Soome * the best we can do at this point. Once all modules are
509199767f8SToomas Soome * loaded and the size of the metadata is known this
510199767f8SToomas Soome * space will be recovered if not used.
511199767f8SToomas Soome */
512199767f8SToomas Soome mod_num = num_modules(rfp);
513199767f8SToomas Soome rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
514199767f8SToomas Soome rfp->f_size += METADATA_RESV_SIZE(mod_num);
515199767f8SToomas Soome *result = rfp;
516199767f8SToomas Soome } else {
517199767f8SToomas Soome /* The rest should be loaded as regular modules */
518199767f8SToomas Soome error = elf64_obj_loadfile(filename, dest, result);
519199767f8SToomas Soome if (error != 0) {
520199767f8SToomas Soome printf("Unable to load %s as an object file, error: %d",
521199767f8SToomas Soome filename, error);
522199767f8SToomas Soome return (error);
523199767f8SToomas Soome }
524199767f8SToomas Soome }
525199767f8SToomas Soome
526199767f8SToomas Soome return (0);
527199767f8SToomas Soome }
528199767f8SToomas Soome
529199767f8SToomas Soome static int
multiboot_obj_exec(struct preloaded_file * fp __unused)5308eef2ab6SToomas Soome multiboot_obj_exec(struct preloaded_file *fp __unused)
531199767f8SToomas Soome {
532199767f8SToomas Soome
533199767f8SToomas Soome return (EFTYPE);
534199767f8SToomas Soome }
535