multiboot.c revision 199767f8919635c4928607450d9e0abb932109ce
/*-
* Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* This multiboot implementation only implements a subset of the full
* multiboot specification in order to be able to boot Xen and a
* FreeBSD Dom0. Trying to use it to boot other multiboot compliant
* kernels will most surely fail.
*
* The full multiboot specification can be found here:
*/
#define _MACHINE_ELF_WANT_32BIT
#include <machine/metadata.h>
#include <string.h>
#include <stand.h>
#include "bootstrap.h"
#include "multiboot.h"
#include "pxe.h"
#define MULTIBOOT_SUPPORTED_FLAGS \
#define NUM_MODULES 2
#define METADATA_MODULE_SIZE PAGE_SIZE
#define METADATA_RESV_SIZE(mod_num) \
/* MB data heap pointer */
static vm_offset_t last_addr;
struct preloaded_file **result);
static int multiboot_exec(struct preloaded_file *);
struct file_format multiboot_obj =
extern void multiboot_tramp();
static const char mbl_name[] = "illumos Loader";
static int
{
struct kernel_module *kmp;
int mod_num = 0;
mod_num++;
return (mod_num);
}
static vm_offset_t
max_addr(void)
{
struct preloaded_file *fp;
vm_offset_t addr = 0;
}
return (addr);
}
static int
struct preloaded_file **result)
{
int i, error;
int fd;
struct multiboot_header *header;
char *cmdline;
struct preloaded_file *fp;
return (EFTYPE);
/* is kernel already loaded? */
return (EFTYPE);
}
return (errno);
/*
* Read MULTIBOOT_SEARCH size in order to search for the
* multiboot magic header.
*/
if (header_search == NULL) {
return (ENOMEM);
}
for (i = 0; i < (search_size / sizeof(uint32_t)); i++) {
if (magic[i] == MULTIBOOT_HEADER_MAGIC) {
break;
}
}
goto out;
}
/* Valid multiboot header has been found, validate checksum */
"Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n",
goto out;
}
printf("Unsupported multiboot flags found: 0x%x\n",
goto out;
}
/* AOUT KLUDGE means we just load entire flat file as blob */
int got;
printf("lseek failed\n");
goto out;
}
for (;;) {
if (got == 0)
break;
if (got < 0) {
goto out;
}
}
fp = file_alloc();
goto out;
}
goto out;
}
error = 0;
} else {
if (error != 0) {
printf("elf32_loadfile_raw failed: %d unable to "
"load multiboot kernel\n", error);
goto out;
}
}
out:
return (error);
}
/*
* returns allocated virtual address from MB info area
*/
static vm_offset_t
{
if (ptr + n >= high_heap_base)
return (0);
return (ptr);
}
/*
* Since for now we have no way to pass the environment to the kernel other than
* through arguments, we need to take care of console setup.
*
* If the console is in mirror mode, set the kernel console from $os_console.
* If it's unset, use first item from $console.
* If $console is "ttyX", also pass $ttyX-mode, since it may have been set by
* the user.
*
* In case of memory allocation errors, just return original command line,
* so we have chance of booting.
*
* On success, cl will be freed and a new, allocated command line string is
* returned.
*/
static char *
update_cmdline(char *cl)
{
char mode[10];
char *tmp;
int len;
if (os_console == NULL) {
} else
if (os_console == NULL)
return (cl);
}
/*
* if console is not present, add it
* if console is ttyX, add ttymode
*/
}
return (cl);
}
"%s -B console=%s,%s-mode=\"%s\"",
else
cl, os_console);
} else {
/* console is set, do we need tty mode? */
tmp += 8;
} else { /* nope */
return (cl);
}
return (cl);
}
}
} else {
/*
* no -B, so we need to add " -B console=%s[,ttyX-mode=\"%s\"]"
*/
}
return (cl);
}
else
}
return (tmp);
}
static char *
{
return (cmdline);
else
else
return (update_cmdline(cmdline));
}
static int
{
struct preloaded_file *mfp;
struct file_metadata *md;
struct i386_devdesc *rootdev;
int rootfs = 0; /* flag for rootfs */
int xen = 0; /* flag for xen */
int kernel = 0; /* flag for kernel */
/* set up base for mb_malloc */
/* start info block from new page */
/* Allocate the multiboot struct and fill the basic details. */
printf("can't determine root device\n");
goto error;
}
/*
* boot image command line. if args were not provided, we need to set
* args here, and that depends on image type...
* fortunately we only have following options:
* 64 or 32 bit unix or xen. so we just check if f_name has unix.
*/
/* do we boot xen? */
xen = 1;
num = 0;
num++;
rootfs++;
kernel++;
}
/* need at least one module - rootfs */
printf("No rootfs module provided, aborting\n");
goto error;
}
printf("No kernel module provided for xen, aborting\n");
goto error;
}
num = 0;
goto error;
}
} else {
}
goto error;
}
else
}
num++;
}
printf("no memory smap\n");
goto error;
}
for (i = 0; i < num; i++) {
}
}
/*
* Set the image command line. Need to do this as last thing,
* as Illumos kernel dboot_startkern will check cmdline
* address as last check to find first free address.
*/
if (xen)
else
goto error;
}
}
}
/*
* if image is xen, we just use f_name + f_args for commandline
* for unix, we need to add zfs-bootfs.
*/
if (xen) {
goto error;
}
} else {
}
} else {
}
goto error;
}
dev_cleanup();
panic("exec returned");
return (error);
}
static int
struct preloaded_file **result)
{
struct kernel_module *kmp;
/* See if there's a aout multiboot kernel loaded */
/* we have normal kernel loaded, add module */
"Unable to load %s as a multiboot payload module\n",
filename);
return (EINVAL);
}
return (0);
}
/* See if there's a multiboot kernel loaded */
return (EFTYPE); /* this allows to check other methods */
}
/*
* We have a multiboot kernel loaded, see if there's a
* kernel loaded also.
*/
/*
* No kernel loaded, this must be it. The kernel has to
* be loaded as a raw file, it will be processed by
* Xen and correctly loaded as an ELF file.
*/
"Unable to load %s as a multiboot payload kernel\n",
filename);
return (EINVAL);
}
/* Load kernel metadata... */
if (error) {
printf("Unable to load kernel %s metadata error: %d\n",
return (EINVAL);
}
/*
* Save space at the end of the kernel in order to place
* the metadata information. We do an approximation of the
* max metadata size, this is not optimal but it's probably
* the best we can do at this point. Once all modules are
* loaded and the size of the metadata is known this
* space will be recovered if not used.
*/
} else {
/* The rest should be loaded as regular modules */
if (error != 0) {
printf("Unable to load %s as an object file, error: %d",
return (error);
}
}
return (0);
}
static int
{
return (EFTYPE);
}