199767f8919635c4928607450d9e0abb932109ceToomas Soome/*-
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
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 * are met:
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 *
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
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 *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * The full multiboot specification can be found here:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/cdefs.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/param.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/exec.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/linker.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/module.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/stdint.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define _MACHINE_ELF_WANT_32BIT
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <machine/elf.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <machine/metadata.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <machine/pc/bios.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <string.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <stand.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "bootstrap.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "multiboot.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "pxe.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "../zfs/libzfs.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "../i386/libi386/libi386.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "../i386/btx/lib/btxv86.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define MULTIBOOT_SUPPORTED_FLAGS \
199767f8919635c4928607450d9e0abb932109ceToomas Soome (MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define NUM_MODULES 2
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define METADATA_FIXED_SIZE (PAGE_SIZE*4)
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define METADATA_MODULE_SIZE PAGE_SIZE
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define METADATA_RESV_SIZE(mod_num) \
199767f8919635c4928607450d9e0abb932109ceToomas Soome roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* MB data heap pointer */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic vm_offset_t last_addr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
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 Soome struct preloaded_file **result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_exec(struct preloaded_file *);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int multiboot_obj_exec(struct preloaded_file *fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct file_format multiboot = { multiboot_loadfile, multiboot_exec };
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct file_format multiboot_obj =
199767f8919635c4928607450d9e0abb932109ceToomas Soome { multiboot_obj_loadfile, multiboot_obj_exec };
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern void multiboot_tramp();
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic const char mbl_name[] = "illumos Loader";
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomenum_modules(struct preloaded_file *kfp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *kmp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int mod_num = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next)
199767f8919635c4928607450d9e0abb932109ceToomas Soome mod_num++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (mod_num);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic vm_offset_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomemax_addr(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome vm_offset_t addr = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (addr < (fp->f_addr + fp->f_size))
199767f8919635c4928607450d9e0abb932109ceToomas Soome addr = fp->f_addr + fp->f_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (addr);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomemultiboot_loadfile(char *filename, u_int64_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file **result)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint32_t *magic;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int i, error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome caddr_t header_search;
199767f8919635c4928607450d9e0abb932109ceToomas Soome ssize_t search_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int fd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct multiboot_header *header;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *cmdline;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (filename == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EFTYPE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* is kernel already loaded? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = file_findfile(NULL, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EFTYPE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((fd = open(filename, O_RDONLY)) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (errno);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Read MULTIBOOT_SEARCH size in order to search for the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * multiboot magic header.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome header_search = malloc(MULTIBOOT_SEARCH);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (header_search == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENOMEM);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome search_size = read(fd, header_search, MULTIBOOT_SEARCH);
199767f8919635c4928607450d9e0abb932109ceToomas Soome magic = (uint32_t *)header_search;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome header = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < (search_size / sizeof(uint32_t)); i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (magic[i] == MULTIBOOT_HEADER_MAGIC) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome header = (struct multiboot_header *)&magic[i];
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (header == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EFTYPE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Valid multiboot header has been found, validate checksum */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (header->magic + header->flags + header->checksum != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf(
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 error = EFTYPE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Unsupported multiboot flags found: 0x%x\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome header->flags);
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EFTYPE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* AOUT KLUDGE means we just load entire flat file as blob */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (header->flags & MULTIBOOT_AOUT_KLUDGE) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome vm_offset_t laddr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int got;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dest = header->load_addr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (lseek(fd, 0, SEEK_SET) == -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("lseek failed\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EIO;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome laddr = dest;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (;;) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome got = archsw.arch_readin(fd, laddr, 4096);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (got == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (got < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("error reading: %s", strerror(errno));
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EIO;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome laddr += got;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = file_alloc();
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_name = strdup(filename);
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_type = strdup("aout multiboot kernel");
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_addr = header->entry_addr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_size = laddr - dest;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_size == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome file_discard(fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EIO;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_metadata = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome *result = fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = elf32_loadfile_raw(filename, dest, result, 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("elf32_loadfile_raw failed: %d unable to "
199767f8919635c4928607450d9e0abb932109ceToomas Soome "load multiboot kernel\n", error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome setenv("kernelname", (*result)->f_name, 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bios_addsmapdata(*result);
199767f8919635c4928607450d9e0abb932109ceToomas Soomeout:
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(header_search);
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * returns allocated virtual address from MB info area
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic vm_offset_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomemb_malloc(size_t n)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome vm_offset_t ptr = last_addr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ptr + n >= high_heap_base)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_addr = roundup(last_addr + n, MULTIBOOT_INFO_ALIGN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ptr);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
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 *
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 * the user.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * In case of memory allocation errors, just return original command line,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * so we have chance of booting.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * On success, cl will be freed and a new, allocated command line string is
199767f8919635c4928607450d9e0abb932109ceToomas Soome * returned.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomeupdate_cmdline(char *cl)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *os_console = getenv("os_console");
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *ttymode = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char mode[10];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *tmp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (os_console == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome tmp = strdup(getenv("console"));
199767f8919635c4928607450d9e0abb932109ceToomas Soome os_console = strsep(&tmp, ", ");
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else
199767f8919635c4928607450d9e0abb932109ceToomas Soome os_console = strdup(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (os_console == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cl);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strncmp(os_console, "tty", 3) == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(mode, sizeof (mode), "%s-mode", os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome ttymode = getenv(mode); /* never NULL */
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strstr(cl, "-B") != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = strlen(cl) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * if console is not present, add it
199767f8919635c4928607450d9e0abb932109ceToomas Soome * if console is ttyX, add ttymode
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome tmp = strstr(cl, "console");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tmp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += 12; /* " -B console=" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ttymode != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += 13; /* ",ttyX-mode=\"\"" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(ttymode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome tmp = malloc(len);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tmp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cl);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ttymode != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp,
199767f8919635c4928607450d9e0abb932109ceToomas Soome "%s -B console=%s,%s-mode=\"%s\"",
199767f8919635c4928607450d9e0abb932109ceToomas Soome cl, os_console, os_console, ttymode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "%s -B console=%s",
199767f8919635c4928607450d9e0abb932109ceToomas Soome cl, os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* console is set, do we need tty mode? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome tmp += 8;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strstr(tmp, "tty") == tmp) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome strncpy(mode, tmp, 4);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mode[4] = '\0';
199767f8919635c4928607450d9e0abb932109ceToomas Soome strcat(mode, "-mode");
199767f8919635c4928607450d9e0abb932109ceToomas Soome ttymode = getenv(mode); /* never NULL */
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else { /* nope */
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cl);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = strlen(cl) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += 13; /* ",ttyX-mode=\"\"" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(ttymode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome tmp = malloc(len);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tmp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cl);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "%s,%s=\"%s\"", cl, mode, ttymode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * no -B, so we need to add " -B console=%s[,ttyX-mode=\"%s\"]"
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = strlen(cl) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += 12; /* " -B console=" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ttymode != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += 13; /* ",ttyX-mode=\"\"" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(ttymode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome tmp = malloc(len);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (tmp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cl);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ttymode != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "%s -B console=%s,%s-mode=\"%s\"", cl,
199767f8919635c4928607450d9e0abb932109ceToomas Soome os_console, os_console, ttymode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "%s -B console=%s", cl, os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(os_console);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(cl);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (tmp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomekernel_cmdline(struct preloaded_file *fp, struct i386_devdesc *rootdev)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *cmdline = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_args = getenv("boot-args");
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = strlen(fp->f_name) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(fp->f_args) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rootdev->d_type == DEVT_ZFS)
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += 3 + strlen(zfs_bootfs(rootdev)) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = malloc(len);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cmdline == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cmdline);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rootdev->d_type == DEVT_ZFS) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s %s -B %s", fp->f_name,
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_args, zfs_bootfs(rootdev));
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s -B %s", fp->f_name,
199767f8919635c4928607450d9e0abb932109ceToomas Soome zfs_bootfs(rootdev));
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else if (fp->f_args != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s", fp->f_name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (update_cmdline(cmdline));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomemultiboot_exec(struct preloaded_file *fp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *mfp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome vm_offset_t module_start, metadata_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome vm_offset_t modulep, kernend, entry;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct file_metadata *md;
199767f8919635c4928607450d9e0abb932109ceToomas Soome Elf_Ehdr *ehdr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct multiboot_info *mb_info = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct multiboot_mod_list *mb_mod = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome multiboot_memory_map_t *mmap;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bios_smap *smap;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct i386_devdesc *rootdev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome extern BOOTPLAYER bootplayer; /* dhcp info */
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *cmdline = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error, num, i;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int rootfs = 0; /* flag for rootfs */
199767f8919635c4928607450d9e0abb932109ceToomas Soome int xen = 0; /* flag for xen */
199767f8919635c4928607450d9e0abb932109ceToomas Soome int kernel = 0; /* flag for kernel */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* set up base for mb_malloc */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* start info block from new page */
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
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
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(mb_info, sizeof(struct multiboot_info));
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->mem_lower = bios_basemem / 1024;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->mem_upper = bios_extmem / 1024;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->boot_loader_name = mb_malloc(strlen(mbl_name) + 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome i386_copyin(mbl_name, mb_info->boot_loader_name, strlen(mbl_name)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome i386_getdev((void **)(&rootdev), NULL, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rootdev == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("can't determine root device\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* do we boot xen? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strstr(fp->f_name, "unix") == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome xen = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome entry = fp->f_addr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome num = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome num++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome rootfs++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome kernel++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (num == 0 || rootfs == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* need at least one module - rootfs */
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("No rootfs module provided, aborting\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (xen == 1 && kernel == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("No kernel module provided for xen, aborting\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
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
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(mb_mod, sizeof(*mb_mod) * num);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome num = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_mod[num].mod_start = mfp->f_addr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_mod[num].mod_end = mfp->f_addr + mfp->f_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strcmp(mfp->f_type, "kernel") == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = kernel_cmdline(mfp, rootdev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cmdline == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = strlen(mfp->f_name) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(mfp->f_type) + 5 + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp->f_args != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(mfp->f_args) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = malloc(len);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cmdline == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp->f_args != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s type=%s %s",
199767f8919635c4928607450d9e0abb932109ceToomas Soome mfp->f_name, mfp->f_type, mfp->f_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s type=%s",
199767f8919635c4928607450d9e0abb932109ceToomas Soome mfp->f_name, mfp->f_type);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
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 free(cmdline);
199767f8919635c4928607450d9e0abb932109ceToomas Soome num++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->mods_count = num;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->mods_addr = VTOP(mb_mod);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->flags |= MULTIBOOT_INFO_MODS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome md = file_findmetadata(fp, MODINFOMD_SMAP);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (md == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("no memory smap\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
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
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->mmap_length = num * sizeof(*mmap);
199767f8919635c4928607450d9e0abb932109ceToomas Soome smap = (struct bios_smap *)md->md_data;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < num; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mmap[i].size = sizeof(*smap);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mmap[i].addr = smap[i].base;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mmap[i].len = smap[i].length;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mmap[i].type = smap[i].type;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->mmap_addr = VTOP(mmap);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->flags |= MULTIBOOT_INFO_MEM_MAP;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strstr(getenv("loaddev"), "pxe") != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->drives_length = sizeof (BOOTPLAYER);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->drives_addr = mb_malloc(mb_info->drives_length);
199767f8919635c4928607450d9e0abb932109ceToomas Soome i386_copyin(&bootplayer, mb_info->drives_addr,
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->drives_length);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (xen)
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = getenv("xen_cmdline");
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = getenv("boot-args");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cmdline != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_args = strdup(cmdline);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (xen) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = strlen(fp->f_name) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome len += strlen(fp->f_args) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if((cmdline = malloc(len)) == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = strdup(fp->f_name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = kernel_cmdline(fp, rootdev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cmdline == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = ENOMEM;
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->cmdline = mb_malloc(strlen(cmdline)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mb_info->flags |= MULTIBOOT_INFO_CMDLINE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(cmdline);
199767f8919635c4928607450d9e0abb932109ceToomas Soome cmdline = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev_cleanup();
199767f8919635c4928607450d9e0abb932109ceToomas Soome __exec((void *)VTOP(multiboot_tramp), (void *)entry,
199767f8919635c4928607450d9e0abb932109ceToomas Soome (void *)VTOP(mb_info));
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome panic("exec returned");
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomeerror:
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomemultiboot_obj_loadfile(char *filename, u_int64_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file **result)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *mfp, *kfp, *rfp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *kmp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error, mod_num;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* See if there's a aout multiboot kernel loaded */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mfp = file_findfile(NULL, "aout multiboot kernel");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* we have normal kernel loaded, add module */
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp = file_loadraw(filename, "module", 0, NULL, 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rfp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf(
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Unable to load %s as a multiboot payload module\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome filename);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome *result = rfp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* See if there's a multiboot kernel loaded */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mfp = file_findfile(NULL, "elf multiboot kernel");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mfp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EFTYPE); /* this allows to check other methods */
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * We have a multiboot kernel loaded, see if there's a
199767f8919635c4928607450d9e0abb932109ceToomas Soome * kernel loaded also.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome kfp = file_findfile(NULL, "elf kernel");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (kfp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rfp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf(
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Unable to load %s as a multiboot payload kernel\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome filename);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Load kernel metadata... */
199767f8919635c4928607450d9e0abb932109ceToomas Soome setenv("kernelname", filename, 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Unable to load kernel %s metadata error: %d\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp->f_name, error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mod_num = num_modules(rfp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome rfp->f_size += METADATA_RESV_SIZE(mod_num);
199767f8919635c4928607450d9e0abb932109ceToomas Soome *result = rfp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* The rest should be loaded as regular modules */
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = elf64_obj_loadfile(filename, dest, result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Unable to load %s as an object file, error: %d",
199767f8919635c4928607450d9e0abb932109ceToomas Soome filename, error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomemultiboot_obj_exec(struct preloaded_file *fp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EFTYPE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}