199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms, with or without
199767f8919635c4928607450d9e0abb932109ceToomas Soome * modification, are permitted provided that the following conditions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 1. Redistributions of source code must retain the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * documentation and/or other materials provided with the distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199767f8919635c4928607450d9e0abb932109ceToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
199767f8919635c4928607450d9e0abb932109ceToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
199767f8919635c4928607450d9e0abb932109ceToomas Soome * SUCH DAMAGE.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * This multiboot implementation only implements a subset of the full
199767f8919635c4928607450d9e0abb932109ceToomas Soome * multiboot specification in order to be able to boot Xen and a
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FreeBSD Dom0. Trying to use it to boot other multiboot compliant
199767f8919635c4928607450d9e0abb932109ceToomas Soome * kernels will most surely fail.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * The full multiboot specification can be found here:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
199767f8919635c4928607450d9e0abb932109ceToomas Soome (MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
199767f8919635c4928607450d9e0abb932109ceToomas Soome roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* MB data heap pointer */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern int elf32_loadfile_raw(char *filename, u_int64_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file **result, int multiboot);
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern int elf64_load_modmetadata(struct preloaded_file *fp, u_int64_t dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern int elf64_obj_loadfile(char *filename, u_int64_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_exec(struct preloaded_file *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_obj_exec(struct preloaded_file *fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct file_format multiboot = { multiboot_loadfile, multiboot_exec };
199767f8919635c4928607450d9e0abb932109ceToomas Soome { multiboot_obj_loadfile, multiboot_obj_exec };
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic const char mbl_name[] = "illumos Loader";
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next)
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soomemultiboot_loadfile(char *filename, u_int64_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* is kernel already loaded? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Read MULTIBOOT_SEARCH size in order to search for the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * multiboot magic header.
199767f8919635c4928607450d9e0abb932109ceToomas Soome search_size = read(fd, header_search, MULTIBOOT_SEARCH);
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < (search_size / sizeof(uint32_t)); i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Valid multiboot header has been found, validate checksum */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (header->magic + header->flags + header->checksum != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome header->magic, header->flags, header->checksum);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Unsupported multiboot flags found: 0x%x\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* AOUT KLUDGE means we just load entire flat file as blob */
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = elf32_loadfile_raw(filename, dest, result, 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("elf32_loadfile_raw failed: %d unable to "
199767f8919635c4928607450d9e0abb932109ceToomas Soome * returns allocated virtual address from MB info area
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_addr = roundup(last_addr + n, MULTIBOOT_INFO_ALIGN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Since for now we have no way to pass the environment to the kernel other than
199767f8919635c4928607450d9e0abb932109ceToomas Soome * through arguments, we need to take care of console setup.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If the console is in mirror mode, set the kernel console from $os_console.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If it's unset, use first item from $console.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If $console is "ttyX", also pass $ttyX-mode, since it may have been set by
199767f8919635c4928607450d9e0abb932109ceToomas Soome * In case of memory allocation errors, just return original command line,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * so we have chance of booting.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * On success, cl will be freed and a new, allocated command line string is
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(mode, sizeof (mode), "%s-mode", os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * if console is not present, add it
199767f8919635c4928607450d9e0abb932109ceToomas Soome * if console is ttyX, add ttymode
199767f8919635c4928607450d9e0abb932109ceToomas Soome "%s -B console=%s,%s-mode=\"%s\"",
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* console is set, do we need tty mode? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else { /* nope */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "%s,%s=\"%s\"", cl, mode, ttymode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * no -B, so we need to add " -B console=%s[,ttyX-mode=\"%s\"]"
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "%s -B console=%s,%s-mode=\"%s\"", cl,
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "%s -B console=%s", cl, os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomekernel_cmdline(struct preloaded_file *fp, struct i386_devdesc *rootdev)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s %s -B %s", fp->f_name,
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* set up base for mb_malloc */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* start info block from new page */
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Allocate the multiboot struct and fill the basic details. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info = (struct multiboot_info *)PTOV(mb_malloc(sizeof (*mb_info)));
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->boot_loader_name = mb_malloc(strlen(mbl_name) + 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome i386_copyin(mbl_name, mb_info->boot_loader_name, strlen(mbl_name)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * boot image command line. if args were not provided, we need to set
199767f8919635c4928607450d9e0abb932109ceToomas Soome * args here, and that depends on image type...
199767f8919635c4928607450d9e0abb932109ceToomas Soome * fortunately we only have following options:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 64 or 32 bit unix or xen. so we just check if f_name has unix.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* do we boot xen? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* need at least one module - rootfs */
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("No rootfs module provided, aborting\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("No kernel module provided for xen, aborting\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_mod = (struct multiboot_mod_list *) PTOV(last_addr);
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_addr += roundup(sizeof(*mb_mod) * num, MULTIBOOT_INFO_ALIGN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_mod[num].mod_end = mfp->f_addr + mfp->f_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_mod[num].cmdline = mb_malloc(strlen(cmdline)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome i386_copyin(cmdline, mb_mod[num].cmdline, strlen(cmdline)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome num = md->md_size / sizeof(struct bios_smap); /* number of entries */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mmap = (multiboot_memory_map_t *)PTOV(mb_malloc(sizeof(*mmap) * num));
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < num; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strstr(getenv("loaddev"), "pxe") != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->drives_addr = mb_malloc(mb_info->drives_length);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Set the image command line. Need to do this as last thing,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * as Illumos kernel dboot_startkern will check cmdline
199767f8919635c4928607450d9e0abb932109ceToomas Soome * address as last check to find first free address.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * if image is xen, we just use f_name + f_args for commandline
199767f8919635c4928607450d9e0abb932109ceToomas Soome * for unix, we need to add zfs-bootfs.
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->cmdline = mb_malloc(strlen(cmdline)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome __exec((void *)VTOP(multiboot_tramp), (void *)entry,
199767f8919635c4928607450d9e0abb932109ceToomas Soomemultiboot_obj_loadfile(char *filename, u_int64_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* See if there's a aout multiboot kernel loaded */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mfp = file_findfile(NULL, "aout multiboot kernel");
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* we have normal kernel loaded, add module */
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp = file_loadraw(filename, "module", 0, NULL, 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Unable to load %s as a multiboot payload module\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* See if there's a multiboot kernel loaded */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mfp = file_findfile(NULL, "elf multiboot kernel");
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EFTYPE); /* this allows to check other methods */
199767f8919635c4928607450d9e0abb932109ceToomas Soome * We have a multiboot kernel loaded, see if there's a
199767f8919635c4928607450d9e0abb932109ceToomas Soome * kernel loaded also.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * No kernel loaded, this must be it. The kernel has to
199767f8919635c4928607450d9e0abb932109ceToomas Soome * be loaded as a raw file, it will be processed by
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Xen and correctly loaded as an ELF file.
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Unable to load %s as a multiboot payload kernel\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Load kernel metadata... */
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Unable to load kernel %s metadata error: %d\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Save space at the end of the kernel in order to place
199767f8919635c4928607450d9e0abb932109ceToomas Soome * the metadata information. We do an approximation of the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * max metadata size, this is not optimal but it's probably
199767f8919635c4928607450d9e0abb932109ceToomas Soome * the best we can do at this point. Once all modules are
199767f8919635c4928607450d9e0abb932109ceToomas Soome * loaded and the size of the metadata is known this
199767f8919635c4928607450d9e0abb932109ceToomas Soome * space will be recovered if not used.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* The rest should be loaded as regular modules */
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = elf64_obj_loadfile(filename, dest, result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Unable to load %s as an object file, error: %d",