xref: /titanic_51/usr/src/boot/sys/boot/i386/libi386/multiboot.c (revision 7b2a1233f92b2b3cb858f2fdb69378a9ab0a42f1)
14a5d661aSToomas Soome /*-
24a5d661aSToomas Soome  * Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
34a5d661aSToomas Soome  * All rights reserved.
44a5d661aSToomas Soome  *
54a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
64a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
74a5d661aSToomas Soome  * are met:
84a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
94a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
104a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
114a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
124a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
134a5d661aSToomas Soome  *
144a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244a5d661aSToomas Soome  * SUCH DAMAGE.
254a5d661aSToomas Soome  */
264a5d661aSToomas Soome 
274a5d661aSToomas Soome /*
284a5d661aSToomas Soome  * This multiboot implementation only implements a subset of the full
294a5d661aSToomas Soome  * multiboot specification in order to be able to boot Xen and a
304a5d661aSToomas Soome  * FreeBSD Dom0. Trying to use it to boot other multiboot compliant
314a5d661aSToomas Soome  * kernels will most surely fail.
324a5d661aSToomas Soome  *
334a5d661aSToomas Soome  * The full multiboot specification can be found here:
344a5d661aSToomas Soome  * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
354a5d661aSToomas Soome  */
364a5d661aSToomas Soome 
374a5d661aSToomas Soome #include <sys/cdefs.h>
384a5d661aSToomas Soome 
394a5d661aSToomas Soome #include <sys/param.h>
404a5d661aSToomas Soome #include <sys/exec.h>
414a5d661aSToomas Soome #include <sys/linker.h>
424a5d661aSToomas Soome #include <sys/module.h>
434a5d661aSToomas Soome #include <sys/stdint.h>
444a5d661aSToomas Soome #define _MACHINE_ELF_WANT_32BIT
454a5d661aSToomas Soome #include <machine/elf.h>
464a5d661aSToomas Soome #include <machine/metadata.h>
474a5d661aSToomas Soome #include <machine/pc/bios.h>
484a5d661aSToomas Soome #include <string.h>
494a5d661aSToomas Soome #include <stand.h>
504a5d661aSToomas Soome 
514a5d661aSToomas Soome #include "bootstrap.h"
524a5d661aSToomas Soome #include "multiboot.h"
534a5d661aSToomas Soome #include "../zfs/libzfs.h"
544a5d661aSToomas Soome #include "../i386/libi386/libi386.h"
554a5d661aSToomas Soome #include "../i386/btx/lib/btxv86.h"
564a5d661aSToomas Soome 
5759dfa57dSToomas Soome #define	SUPPORT_DHCP
5859dfa57dSToomas Soome #include <bootp.h>
5959dfa57dSToomas Soome 
604a5d661aSToomas Soome #define MULTIBOOT_SUPPORTED_FLAGS \
614a5d661aSToomas Soome 	(MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
624a5d661aSToomas Soome #define METADATA_FIXED_SIZE	(PAGE_SIZE*4)
634a5d661aSToomas Soome #define METADATA_MODULE_SIZE	PAGE_SIZE
644a5d661aSToomas Soome 
654a5d661aSToomas Soome #define METADATA_RESV_SIZE(mod_num) \
664a5d661aSToomas Soome 	roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE)
674a5d661aSToomas Soome 
684a5d661aSToomas Soome /* MB data heap pointer */
694a5d661aSToomas Soome static vm_offset_t last_addr;
706feb9af9SToomas Soome extern char bootprog_info[];
714a5d661aSToomas Soome 
724a5d661aSToomas Soome static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **);
734a5d661aSToomas Soome static int multiboot_exec(struct preloaded_file *);
744a5d661aSToomas Soome 
754a5d661aSToomas Soome static int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **);
764a5d661aSToomas Soome static int multiboot_obj_exec(struct preloaded_file *fp);
774a5d661aSToomas Soome 
784a5d661aSToomas Soome struct file_format multiboot = { multiboot_loadfile, multiboot_exec };
794a5d661aSToomas Soome struct file_format multiboot_obj =
804a5d661aSToomas Soome     { multiboot_obj_loadfile, multiboot_obj_exec };
814a5d661aSToomas Soome 
824a5d661aSToomas Soome static int
834a5d661aSToomas Soome num_modules(struct preloaded_file *kfp)
844a5d661aSToomas Soome {
854a5d661aSToomas Soome 	struct kernel_module	*kmp;
864a5d661aSToomas Soome 	int			 mod_num = 0;
874a5d661aSToomas Soome 
884a5d661aSToomas Soome 	for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next)
894a5d661aSToomas Soome 		mod_num++;
904a5d661aSToomas Soome 
914a5d661aSToomas Soome 	return (mod_num);
924a5d661aSToomas Soome }
934a5d661aSToomas Soome 
944a5d661aSToomas Soome static vm_offset_t
954a5d661aSToomas Soome max_addr(void)
964a5d661aSToomas Soome {
974a5d661aSToomas Soome 	struct preloaded_file	*fp;
984a5d661aSToomas Soome 	vm_offset_t		 addr = 0;
994a5d661aSToomas Soome 
1004a5d661aSToomas Soome 	for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
1014a5d661aSToomas Soome 		if (addr < (fp->f_addr + fp->f_size))
1024a5d661aSToomas Soome 			addr = fp->f_addr + fp->f_size;
1034a5d661aSToomas Soome 	}
1044a5d661aSToomas Soome 
1054a5d661aSToomas Soome 	return (addr);
1064a5d661aSToomas Soome }
1074a5d661aSToomas Soome 
1084a5d661aSToomas Soome static int
1094a5d661aSToomas Soome multiboot_loadfile(char *filename, u_int64_t dest,
1104a5d661aSToomas Soome     struct preloaded_file **result)
1114a5d661aSToomas Soome {
1124a5d661aSToomas Soome 	uint32_t		*magic;
1134a5d661aSToomas Soome 	int			 i, error;
1144a5d661aSToomas Soome 	caddr_t			 header_search;
1154a5d661aSToomas Soome 	ssize_t			 search_size;
1164a5d661aSToomas Soome 	int			 fd;
1174a5d661aSToomas Soome 	struct multiboot_header	*header;
1184a5d661aSToomas Soome 	struct preloaded_file	*fp;
1194a5d661aSToomas Soome 
1204a5d661aSToomas Soome 	if (filename == NULL)
1214a5d661aSToomas Soome 		return (EFTYPE);
1224a5d661aSToomas Soome 
1234a5d661aSToomas Soome 	/* is kernel already loaded? */
1244a5d661aSToomas Soome 	fp = file_findfile(NULL, NULL);
1254a5d661aSToomas Soome 	if (fp != NULL) {
1264a5d661aSToomas Soome 		return (EFTYPE);
1274a5d661aSToomas Soome 	}
1284a5d661aSToomas Soome 
1294a5d661aSToomas Soome 	if ((fd = open(filename, O_RDONLY)) == -1)
1304a5d661aSToomas Soome 		return (errno);
1314a5d661aSToomas Soome 
1324a5d661aSToomas Soome 	/*
1334a5d661aSToomas Soome 	 * Read MULTIBOOT_SEARCH size in order to search for the
1344a5d661aSToomas Soome 	 * multiboot magic header.
1354a5d661aSToomas Soome 	 */
1364a5d661aSToomas Soome 	header_search = malloc(MULTIBOOT_SEARCH);
1374a5d661aSToomas Soome 	if (header_search == NULL) {
1384a5d661aSToomas Soome 		close(fd);
1394a5d661aSToomas Soome 		return (ENOMEM);
1404a5d661aSToomas Soome 	}
1414a5d661aSToomas Soome 
1424a5d661aSToomas Soome 	search_size = read(fd, header_search, MULTIBOOT_SEARCH);
1434a5d661aSToomas Soome 	magic = (uint32_t *)header_search;
1444a5d661aSToomas Soome 
1454a5d661aSToomas Soome 	header = NULL;
1464a5d661aSToomas Soome 	for (i = 0; i < (search_size / sizeof(uint32_t)); i++) {
1474a5d661aSToomas Soome 		if (magic[i] == MULTIBOOT_HEADER_MAGIC) {
1484a5d661aSToomas Soome 			header = (struct multiboot_header *)&magic[i];
1494a5d661aSToomas Soome 			break;
1504a5d661aSToomas Soome 		}
1514a5d661aSToomas Soome 	}
1524a5d661aSToomas Soome 
1534a5d661aSToomas Soome 	if (header == NULL) {
1544a5d661aSToomas Soome 		error = EFTYPE;
1554a5d661aSToomas Soome 		goto out;
1564a5d661aSToomas Soome 	}
1574a5d661aSToomas Soome 
1584a5d661aSToomas Soome 	/* Valid multiboot header has been found, validate checksum */
1594a5d661aSToomas Soome 	if (header->magic + header->flags + header->checksum != 0) {
1604a5d661aSToomas Soome 		printf(
1614a5d661aSToomas Soome 	"Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n",
1624a5d661aSToomas Soome 	header->magic, header->flags, header->checksum);
1634a5d661aSToomas Soome 		error = EFTYPE;
1644a5d661aSToomas Soome 		goto out;
1654a5d661aSToomas Soome 	}
1664a5d661aSToomas Soome 
1674a5d661aSToomas Soome 	if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) {
1684a5d661aSToomas Soome 		printf("Unsupported multiboot flags found: 0x%x\n",
1694a5d661aSToomas Soome 		    header->flags);
1704a5d661aSToomas Soome 		error = EFTYPE;
1714a5d661aSToomas Soome 		goto out;
1724a5d661aSToomas Soome 	}
1734a5d661aSToomas Soome 	/* AOUT KLUDGE means we just load entire flat file as blob */
1744a5d661aSToomas Soome 	if (header->flags & MULTIBOOT_AOUT_KLUDGE) {
1754a5d661aSToomas Soome 		vm_offset_t laddr;
1764a5d661aSToomas Soome 		int got;
1774a5d661aSToomas Soome 
1784a5d661aSToomas Soome 		dest = header->load_addr;
1794a5d661aSToomas Soome 		if (lseek(fd, 0, SEEK_SET) == -1) {
1804a5d661aSToomas Soome 			printf("lseek failed\n");
1814a5d661aSToomas Soome 			error = EIO;
1824a5d661aSToomas Soome 			goto out;
1834a5d661aSToomas Soome 		}
1844a5d661aSToomas Soome 		laddr = dest;
1854a5d661aSToomas Soome 		for (;;) {
1864a5d661aSToomas Soome 			got = archsw.arch_readin(fd, laddr, 4096);
1874a5d661aSToomas Soome 			if (got == 0)
1884a5d661aSToomas Soome 				break;
1894a5d661aSToomas Soome 			if (got < 0) {
1904a5d661aSToomas Soome 				printf("error reading: %s", strerror(errno));
1914a5d661aSToomas Soome 				error = EIO;
1924a5d661aSToomas Soome 				goto out;
1934a5d661aSToomas Soome 			}
1944a5d661aSToomas Soome 			laddr += got;
1954a5d661aSToomas Soome 		}
1964a5d661aSToomas Soome 
1974a5d661aSToomas Soome 		fp = file_alloc();
1984a5d661aSToomas Soome 		if (fp == NULL) {
1994a5d661aSToomas Soome 			error = ENOMEM;
2004a5d661aSToomas Soome 			goto out;
2014a5d661aSToomas Soome 		}
2024a5d661aSToomas Soome 		fp->f_name = strdup(filename);
2034a5d661aSToomas Soome 		fp->f_type = strdup("aout multiboot kernel");
2044a5d661aSToomas Soome 		fp->f_addr = header->entry_addr;
2054a5d661aSToomas Soome 		fp->f_size = laddr - dest;
2064a5d661aSToomas Soome 		if (fp->f_size == 0) {
2074a5d661aSToomas Soome 			file_discard(fp);
2084a5d661aSToomas Soome 			error = EIO;
2094a5d661aSToomas Soome 			goto out;
2104a5d661aSToomas Soome 		}
2114a5d661aSToomas Soome 		fp->f_metadata = NULL;
2124a5d661aSToomas Soome 		error = 0;
2134a5d661aSToomas Soome 	} else {
2146feb9af9SToomas Soome 		error = elf32_loadfile_raw(filename, dest, &fp, 1);
2154a5d661aSToomas Soome 		if (error != 0) {
2164a5d661aSToomas Soome 			printf("elf32_loadfile_raw failed: %d unable to "
2174a5d661aSToomas Soome 			    "load multiboot kernel\n", error);
2184a5d661aSToomas Soome 			goto out;
2194a5d661aSToomas Soome 		}
2204a5d661aSToomas Soome 	}
2214a5d661aSToomas Soome 
2226feb9af9SToomas Soome 	setenv("kernelname", fp->f_name, 1);
2236feb9af9SToomas Soome 	bios_addsmapdata(fp);
2246feb9af9SToomas Soome 	*result = fp;
2254a5d661aSToomas Soome out:
2264a5d661aSToomas Soome 	free(header_search);
2274a5d661aSToomas Soome 	close(fd);
2284a5d661aSToomas Soome 	return (error);
2294a5d661aSToomas Soome }
2304a5d661aSToomas Soome 
2314a5d661aSToomas Soome /*
2324a5d661aSToomas Soome  * returns allocated virtual address from MB info area
2334a5d661aSToomas Soome  */
2344a5d661aSToomas Soome static vm_offset_t
2354a5d661aSToomas Soome mb_malloc(size_t n)
2364a5d661aSToomas Soome {
2374a5d661aSToomas Soome 	vm_offset_t ptr = last_addr;
2384a5d661aSToomas Soome 	if (ptr + n >= high_heap_base)
2394a5d661aSToomas Soome 		return (0);
2404a5d661aSToomas Soome 	last_addr = roundup(last_addr + n, MULTIBOOT_INFO_ALIGN);
2414a5d661aSToomas Soome 	return (ptr);
2424a5d661aSToomas Soome }
2434a5d661aSToomas Soome 
2444a5d661aSToomas Soome static int
2454a5d661aSToomas Soome multiboot_exec(struct preloaded_file *fp)
2464a5d661aSToomas Soome {
2474a5d661aSToomas Soome 	struct preloaded_file		*mfp;
2484a5d661aSToomas Soome 	vm_offset_t			 module_start, metadata_size;
2494a5d661aSToomas Soome 	vm_offset_t			 modulep, kernend, entry;
2504a5d661aSToomas Soome 	struct file_metadata		*md;
2514a5d661aSToomas Soome 	struct multiboot_info		*mb_info = NULL;
2524a5d661aSToomas Soome 	struct multiboot_mod_list	*mb_mod = NULL;
2534a5d661aSToomas Soome 	multiboot_memory_map_t		*mmap;
2544a5d661aSToomas Soome 	struct bios_smap		*smap;
2556feb9af9SToomas Soome 	struct devdesc			*rootdev;
2564a5d661aSToomas Soome 	char				*cmdline = NULL;
2574a5d661aSToomas Soome 	size_t				 len;
2584a5d661aSToomas Soome 	int				 error, num, i;
2594a5d661aSToomas Soome 	int				 rootfs = 0;	/* flag for rootfs */
2604a5d661aSToomas Soome 	int				 xen = 0;	/* flag for xen */
2614a5d661aSToomas Soome 	int				 kernel = 0;	/* flag for kernel */
2624a5d661aSToomas Soome 
2636feb9af9SToomas Soome 	/* Set up base for mb_malloc. */
2644a5d661aSToomas Soome 	for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);
2654a5d661aSToomas Soome 
2666feb9af9SToomas Soome 	/* Start info block from new page. */
2674a5d661aSToomas Soome 	last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);
2684a5d661aSToomas Soome 
2694a5d661aSToomas Soome 	/* Allocate the multiboot struct and fill the basic details. */
2704a5d661aSToomas Soome 	mb_info = (struct multiboot_info *)PTOV(mb_malloc(sizeof (*mb_info)));
2714a5d661aSToomas Soome 
2724a5d661aSToomas Soome 	bzero(mb_info, sizeof(struct multiboot_info));
2734a5d661aSToomas Soome 	mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME;
2744a5d661aSToomas Soome 	mb_info->mem_lower = bios_basemem / 1024;
2754a5d661aSToomas Soome 	mb_info->mem_upper = bios_extmem / 1024;
2766feb9af9SToomas Soome 	mb_info->boot_loader_name = mb_malloc(strlen(bootprog_info) + 1);
2774a5d661aSToomas Soome 
2786feb9af9SToomas Soome 	i386_copyin(bootprog_info, mb_info->boot_loader_name,
2796feb9af9SToomas Soome 	    strlen(bootprog_info) + 1);
2804a5d661aSToomas Soome 
2814a5d661aSToomas Soome 	i386_getdev((void **)(&rootdev), NULL, NULL);
2824a5d661aSToomas Soome 	if (rootdev == NULL) {
2834a5d661aSToomas Soome 		printf("can't determine root device\n");
2844a5d661aSToomas Soome 		error = EINVAL;
2854a5d661aSToomas Soome 		goto error;
2864a5d661aSToomas Soome 	}
2874a5d661aSToomas Soome 
2884a5d661aSToomas Soome 	/*
2896feb9af9SToomas Soome 	 * Boot image command line. If args were not provided, we need to set
2904a5d661aSToomas Soome 	 * args here, and that depends on image type...
2916feb9af9SToomas Soome 	 * Fortunately we only have following options:
2926feb9af9SToomas Soome 	 * 64 or 32 bit unix or xen. So we just check if f_name has unix.
2934a5d661aSToomas Soome 	 */
2946feb9af9SToomas Soome 	/* Do we boot xen? */
2954a5d661aSToomas Soome 	if (strstr(fp->f_name, "unix") == NULL)
2964a5d661aSToomas Soome 		xen = 1;
2974a5d661aSToomas Soome 
2984a5d661aSToomas Soome 	entry = fp->f_addr;
2994a5d661aSToomas Soome 
3004a5d661aSToomas Soome 	num = 0;
3014a5d661aSToomas Soome 	for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
3024a5d661aSToomas Soome 		num++;
3034a5d661aSToomas Soome 		if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
3044a5d661aSToomas Soome 			rootfs++;
3054a5d661aSToomas Soome 		if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0)
3064a5d661aSToomas Soome 			kernel++;
3074a5d661aSToomas Soome 	}
3084a5d661aSToomas Soome 
3094a5d661aSToomas Soome 	if (num == 0 || rootfs == 0) {
3106feb9af9SToomas Soome 		/* We need at least one module - rootfs. */
3114a5d661aSToomas Soome 		printf("No rootfs module provided, aborting\n");
3124a5d661aSToomas Soome 		error = EINVAL;
3134a5d661aSToomas Soome 		goto error;
3144a5d661aSToomas Soome 	}
3154a5d661aSToomas Soome 	if (xen == 1 && kernel == 0) {
3164a5d661aSToomas Soome 		printf("No kernel module provided for xen, aborting\n");
3174a5d661aSToomas Soome 		error = EINVAL;
3184a5d661aSToomas Soome 		goto error;
3194a5d661aSToomas Soome 	}
3204a5d661aSToomas Soome 	mb_mod = (struct multiboot_mod_list *) PTOV(last_addr);
3214a5d661aSToomas Soome 	last_addr += roundup(sizeof(*mb_mod) * num, MULTIBOOT_INFO_ALIGN);
3224a5d661aSToomas Soome 
3234a5d661aSToomas Soome 	bzero(mb_mod, sizeof(*mb_mod) * num);
3244a5d661aSToomas Soome 
3254a5d661aSToomas Soome 	num = 0;
3264a5d661aSToomas Soome 	for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
3274a5d661aSToomas Soome 		mb_mod[num].mod_start = mfp->f_addr;
3284a5d661aSToomas Soome 		mb_mod[num].mod_end = mfp->f_addr + mfp->f_size;
3294a5d661aSToomas Soome 
3304a5d661aSToomas Soome 		if (strcmp(mfp->f_type, "kernel") == 0) {
3311c871975SToomas Soome 			cmdline = NULL;
3326feb9af9SToomas Soome 			error = mb_kernel_cmdline(mfp, rootdev, &cmdline);
3331c871975SToomas Soome 			if (error != 0)
3344a5d661aSToomas Soome 				goto error;
3354a5d661aSToomas Soome 		} else {
3364a5d661aSToomas Soome 			len = strlen(mfp->f_name) + 1;
3374a5d661aSToomas Soome 			len += strlen(mfp->f_type) + 5 + 1;
3384a5d661aSToomas Soome 			if (mfp->f_args != NULL) {
3394a5d661aSToomas Soome 				len += strlen(mfp->f_args) + 1;
3404a5d661aSToomas Soome 			}
3414a5d661aSToomas Soome 			cmdline = malloc(len);
3424a5d661aSToomas Soome 			if (cmdline == NULL) {
3434a5d661aSToomas Soome 				error = ENOMEM;
3444a5d661aSToomas Soome 				goto error;
3454a5d661aSToomas Soome 			}
3464a5d661aSToomas Soome 
3474a5d661aSToomas Soome 			if (mfp->f_args != NULL)
3484a5d661aSToomas Soome 				snprintf(cmdline, len, "%s type=%s %s",
3494a5d661aSToomas Soome 				    mfp->f_name, mfp->f_type, mfp->f_args);
3504a5d661aSToomas Soome 			else
3514a5d661aSToomas Soome 				snprintf(cmdline, len, "%s type=%s",
3524a5d661aSToomas Soome 				    mfp->f_name, mfp->f_type);
3534a5d661aSToomas Soome 		}
3544a5d661aSToomas Soome 
3554a5d661aSToomas Soome 		mb_mod[num].cmdline = mb_malloc(strlen(cmdline)+1);
3564a5d661aSToomas Soome 		i386_copyin(cmdline, mb_mod[num].cmdline, strlen(cmdline)+1);
3574a5d661aSToomas Soome 		free(cmdline);
3584a5d661aSToomas Soome 		num++;
3594a5d661aSToomas Soome 	}
3604a5d661aSToomas Soome 
3614a5d661aSToomas Soome 	mb_info->mods_count = num;
3624a5d661aSToomas Soome 	mb_info->mods_addr = VTOP(mb_mod);
3634a5d661aSToomas Soome 	mb_info->flags |= MULTIBOOT_INFO_MODS;
3644a5d661aSToomas Soome 
3654a5d661aSToomas Soome 	md = file_findmetadata(fp, MODINFOMD_SMAP);
3664a5d661aSToomas Soome 	if (md == NULL) {
3674a5d661aSToomas Soome 		printf("no memory smap\n");
3684a5d661aSToomas Soome 		error = EINVAL;
3694a5d661aSToomas Soome 		goto error;
3704a5d661aSToomas Soome 	}
3714a5d661aSToomas Soome 
3724a5d661aSToomas Soome 	num = md->md_size / sizeof(struct bios_smap); /* number of entries */
3734a5d661aSToomas Soome 	mmap = (multiboot_memory_map_t *)PTOV(mb_malloc(sizeof(*mmap) * num));
3744a5d661aSToomas Soome 
3754a5d661aSToomas Soome 	mb_info->mmap_length = num * sizeof(*mmap);
3764a5d661aSToomas Soome 	smap = (struct bios_smap *)md->md_data;
3774a5d661aSToomas Soome 
3784a5d661aSToomas Soome 	for (i = 0; i < num; i++) {
3794a5d661aSToomas Soome 		mmap[i].size = sizeof(*smap);
3804a5d661aSToomas Soome 		mmap[i].addr = smap[i].base;
3814a5d661aSToomas Soome 		mmap[i].len = smap[i].length;
3824a5d661aSToomas Soome 		mmap[i].type = smap[i].type;
3834a5d661aSToomas Soome 	}
3844a5d661aSToomas Soome 	mb_info->mmap_addr = VTOP(mmap);
3854a5d661aSToomas Soome 	mb_info->flags |= MULTIBOOT_INFO_MEM_MAP;
3864a5d661aSToomas Soome 
387*7b2a1233SToomas Soome 	if (strstr(getenv("loaddev"), "net") != NULL &&
38859dfa57dSToomas Soome 	    bootp_response != NULL) {
389*7b2a1233SToomas Soome 		mb_info->drives_length = bootp_response_size;
390*7b2a1233SToomas Soome 		mb_info->drives_addr = mb_malloc(bootp_response_size);
39159dfa57dSToomas Soome 		i386_copyin(bootp_response, mb_info->drives_addr,
392*7b2a1233SToomas Soome 		    bootp_response_size);
3934a5d661aSToomas Soome 		mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO;
3944a5d661aSToomas Soome 	}
3954a5d661aSToomas Soome 	/*
3964a5d661aSToomas Soome 	 * Set the image command line. Need to do this as last thing,
3976feb9af9SToomas Soome 	 * as illumos kernel dboot_startkern will check cmdline
3984a5d661aSToomas Soome 	 * address as last check to find first free address.
3994a5d661aSToomas Soome 	 */
4004a5d661aSToomas Soome 	if (fp->f_args == NULL) {
4014a5d661aSToomas Soome 		if (xen)
4024a5d661aSToomas Soome 			cmdline = getenv("xen_cmdline");
4034a5d661aSToomas Soome 		else
4044a5d661aSToomas Soome 			cmdline = getenv("boot-args");
4054a5d661aSToomas Soome 		if (cmdline != NULL) {
4064a5d661aSToomas Soome 			fp->f_args = strdup(cmdline);
4074a5d661aSToomas Soome 			if (fp->f_args == NULL) {
4084a5d661aSToomas Soome 				error = ENOMEM;
4094a5d661aSToomas Soome 				goto error;
4104a5d661aSToomas Soome 			}
4114a5d661aSToomas Soome 		}
4124a5d661aSToomas Soome 	}
4134a5d661aSToomas Soome 
4144a5d661aSToomas Soome 	/*
4156feb9af9SToomas Soome 	 * If the image is xen, we just use f_name + f_args for commandline
4164a5d661aSToomas Soome 	 * for unix, we need to add zfs-bootfs.
4174a5d661aSToomas Soome 	 */
4184a5d661aSToomas Soome 	if (xen) {
4194a5d661aSToomas Soome 		len = strlen(fp->f_name) + 1;
4204a5d661aSToomas Soome 		if (fp->f_args != NULL)
4214a5d661aSToomas Soome 			len += strlen(fp->f_args) + 1;
4224a5d661aSToomas Soome 
4234a5d661aSToomas Soome 		if (fp->f_args != NULL) {
4244a5d661aSToomas Soome 			if((cmdline = malloc(len)) == NULL) {
4254a5d661aSToomas Soome 				error = ENOMEM;
4264a5d661aSToomas Soome 				goto error;
4274a5d661aSToomas Soome 			}
4284a5d661aSToomas Soome 			snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
4294a5d661aSToomas Soome 		} else {
4304a5d661aSToomas Soome 			cmdline = strdup(fp->f_name);
4314a5d661aSToomas Soome 			if (cmdline == NULL) {
4324a5d661aSToomas Soome 				error = ENOMEM;
4334a5d661aSToomas Soome 				goto error;
4344a5d661aSToomas Soome 			}
4351c871975SToomas Soome 		}
4361c871975SToomas Soome 	} else {
4371c871975SToomas Soome 		cmdline = NULL;
4386feb9af9SToomas Soome 		if ((error = mb_kernel_cmdline(fp, rootdev, &cmdline)) != 0)
4391c871975SToomas Soome 			goto error;
4401c871975SToomas Soome 	}
4414a5d661aSToomas Soome 
4424a5d661aSToomas Soome 	mb_info->cmdline = mb_malloc(strlen(cmdline)+1);
4434a5d661aSToomas Soome 	i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1);
4444a5d661aSToomas Soome 	mb_info->flags |= MULTIBOOT_INFO_CMDLINE;
4454a5d661aSToomas Soome 	free(cmdline);
4464a5d661aSToomas Soome 	cmdline = NULL;
4474a5d661aSToomas Soome 
4484a5d661aSToomas Soome 	dev_cleanup();
4496feb9af9SToomas Soome 	__exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC,
4506feb9af9SToomas Soome 	    (void *)entry, (void *)VTOP(mb_info));
4514a5d661aSToomas Soome 
4524a5d661aSToomas Soome 	panic("exec returned");
4534a5d661aSToomas Soome 
4544a5d661aSToomas Soome error:
4551c871975SToomas Soome 	free(cmdline);
4564a5d661aSToomas Soome 	return (error);
4574a5d661aSToomas Soome }
4584a5d661aSToomas Soome 
4594a5d661aSToomas Soome static int
4604a5d661aSToomas Soome multiboot_obj_loadfile(char *filename, u_int64_t dest,
4614a5d661aSToomas Soome     struct preloaded_file **result)
4624a5d661aSToomas Soome {
4634a5d661aSToomas Soome 	struct preloaded_file	*mfp, *kfp, *rfp;
4644a5d661aSToomas Soome 	struct kernel_module	*kmp;
4654a5d661aSToomas Soome 	int			 error, mod_num;
4664a5d661aSToomas Soome 
4674a5d661aSToomas Soome 	/* See if there's a aout multiboot kernel loaded */
4684a5d661aSToomas Soome 	mfp = file_findfile(NULL, "aout multiboot kernel");
4694a5d661aSToomas Soome 	if (mfp != NULL) {
4704a5d661aSToomas Soome 		/* we have normal kernel loaded, add module */
4714a5d661aSToomas Soome 		rfp = file_loadraw(filename, "module", 0, NULL, 0);
4724a5d661aSToomas Soome 		if (rfp == NULL) {
4734a5d661aSToomas Soome 			printf(
4744a5d661aSToomas Soome 			"Unable to load %s as a multiboot payload module\n",
4754a5d661aSToomas Soome 			filename);
4764a5d661aSToomas Soome 			return (EINVAL);
4774a5d661aSToomas Soome 		}
4784a5d661aSToomas Soome 		rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
4794a5d661aSToomas Soome 		*result = rfp;
4804a5d661aSToomas Soome 		return (0);
4814a5d661aSToomas Soome 	}
4824a5d661aSToomas Soome 
4834a5d661aSToomas Soome 	/* See if there's a multiboot kernel loaded */
4844a5d661aSToomas Soome 	mfp = file_findfile(NULL, "elf multiboot kernel");
4854a5d661aSToomas Soome 	if (mfp == NULL) {
4864a5d661aSToomas Soome 		return (EFTYPE);	/* this allows to check other methods */
4874a5d661aSToomas Soome 	}
4884a5d661aSToomas Soome 
4894a5d661aSToomas Soome 	/*
4904a5d661aSToomas Soome 	 * We have a multiboot kernel loaded, see if there's a
4914a5d661aSToomas Soome 	 * kernel loaded also.
4924a5d661aSToomas Soome 	 */
4934a5d661aSToomas Soome 	kfp = file_findfile(NULL, "elf kernel");
4944a5d661aSToomas Soome 	if (kfp == NULL) {
4954a5d661aSToomas Soome 		/*
4964a5d661aSToomas Soome 		 * No kernel loaded, this must be it. The kernel has to
4974a5d661aSToomas Soome 		 * be loaded as a raw file, it will be processed by
4984a5d661aSToomas Soome 		 * Xen and correctly loaded as an ELF file.
4994a5d661aSToomas Soome 		 */
5004a5d661aSToomas Soome 		rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0);
5014a5d661aSToomas Soome 		if (rfp == NULL) {
5024a5d661aSToomas Soome 			printf(
5034a5d661aSToomas Soome 			"Unable to load %s as a multiboot payload kernel\n",
5044a5d661aSToomas Soome 			filename);
5054a5d661aSToomas Soome 			return (EINVAL);
5064a5d661aSToomas Soome 		}
5074a5d661aSToomas Soome 
5084a5d661aSToomas Soome 		/* Load kernel metadata... */
5094a5d661aSToomas Soome 		setenv("kernelname", filename, 1);
5104a5d661aSToomas Soome 		error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size);
5114a5d661aSToomas Soome 		if (error) {
5124a5d661aSToomas Soome 			printf("Unable to load kernel %s metadata error: %d\n",
5134a5d661aSToomas Soome 			    rfp->f_name, error);
5144a5d661aSToomas Soome 			return (EINVAL);
5154a5d661aSToomas Soome 		}
5164a5d661aSToomas Soome 
5174a5d661aSToomas Soome 		/*
5184a5d661aSToomas Soome 		 * Save space at the end of the kernel in order to place
5194a5d661aSToomas Soome 		 * the metadata information. We do an approximation of the
5204a5d661aSToomas Soome 		 * max metadata size, this is not optimal but it's probably
5214a5d661aSToomas Soome 		 * the best we can do at this point. Once all modules are
5224a5d661aSToomas Soome 		 * loaded and the size of the metadata is known this
5234a5d661aSToomas Soome 		 * space will be recovered if not used.
5244a5d661aSToomas Soome 		 */
5254a5d661aSToomas Soome 		mod_num = num_modules(rfp);
5264a5d661aSToomas Soome 		rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
5274a5d661aSToomas Soome 		rfp->f_size += METADATA_RESV_SIZE(mod_num);
5284a5d661aSToomas Soome 		*result = rfp;
5294a5d661aSToomas Soome 	} else {
5304a5d661aSToomas Soome 		/* The rest should be loaded as regular modules */
5314a5d661aSToomas Soome 		error = elf64_obj_loadfile(filename, dest, result);
5324a5d661aSToomas Soome 		if (error != 0) {
5334a5d661aSToomas Soome 			printf("Unable to load %s as an object file, error: %d",
5344a5d661aSToomas Soome 			    filename, error);
5354a5d661aSToomas Soome 			return (error);
5364a5d661aSToomas Soome 		}
5374a5d661aSToomas Soome 	}
5384a5d661aSToomas Soome 
5394a5d661aSToomas Soome 	return (0);
5404a5d661aSToomas Soome }
5414a5d661aSToomas Soome 
5424a5d661aSToomas Soome static int
5434a5d661aSToomas Soome multiboot_obj_exec(struct preloaded_file *fp)
5444a5d661aSToomas Soome {
5454a5d661aSToomas Soome 
5464a5d661aSToomas Soome 	return (EFTYPE);
5474a5d661aSToomas Soome }
548