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