summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2016-10-09 17:07:43 +0300
committerJoshua M. Clulow <josh@sysmgr.org>2017-04-21 20:09:34 -0700
commit14ee0d29c415966483c8c602b05bf27669c29497 (patch)
tree129b7f033dc41ba23e386e4c48f7374d7292e190
parent1738dd6ec94e36a9828d13a6e52ac7fb68cb52ed (diff)
downloadillumos-joyent-14ee0d29c415966483c8c602b05bf27669c29497.tar.gz
7462 loader should support multiboot2 protocol
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Approved by: Joshua M. Clulow <josh@sysmgr.org>
-rw-r--r--usr/src/boot/Makefile.version2
-rw-r--r--usr/src/boot/sys/boot/common/bootstrap.h10
-rw-r--r--usr/src/boot/sys/boot/common/load_elf.c14
-rw-r--r--usr/src/boot/sys/boot/common/module.c26
-rw-r--r--usr/src/boot/sys/boot/common/multiboot2.c891
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/biosacpi.c2
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/multiboot.c319
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S9
-rw-r--r--usr/src/boot/sys/boot/i386/loader/Makefile11
-rw-r--r--usr/src/boot/sys/boot/i386/loader/conf.c2
-rw-r--r--usr/src/boot/sys/boot/i386/loader/main.c15
11 files changed, 987 insertions, 314 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version
index 6e85cbfb08..047f9d7f10 100644
--- a/usr/src/boot/Makefile.version
+++ b/usr/src/boot/Makefile.version
@@ -33,4 +33,4 @@ LOADER_VERSION = 1.1
# Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
# The version is processed from left to right, the version number can only
# be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2017.4.1.1
+BOOT_VERSION = $(LOADER_VERSION)-2017.4.5.1
diff --git a/usr/src/boot/sys/boot/common/bootstrap.h b/usr/src/boot/sys/boot/common/bootstrap.h
index d228875f7f..978eba42bc 100644
--- a/usr/src/boot/sys/boot/common/bootstrap.h
+++ b/usr/src/boot/sys/boot/common/bootstrap.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _BOOTSTRAP_H_
@@ -306,7 +304,13 @@ struct arch_switch
*/
uint64_t (*arch_loadaddr)(u_int type, void *data, uint64_t addr);
#define LOAD_ELF 1 /* data points to the ELF header. */
-#define LOAD_RAW 2 /* data points to the file name. */
+#define LOAD_RAW 2 /* data points to the module file name. */
+#define LOAD_KERN 3 /* data points to the kernel file name. */
+#define LOAD_MEM 4 /* data points to int for buffer size. */
+ /*
+ * Interface to release the load address.
+ */
+ void (*arch_free_loadaddr)(uint64_t addr, uint64_t pages);
/*
* Interface to inform MD code about a loaded (ELF) segment. This
diff --git a/usr/src/boot/sys/boot/common/load_elf.c b/usr/src/boot/sys/boot/common/load_elf.c
index 287bfac56a..b7fc4bea09 100644
--- a/usr/src/boot/sys/boot/common/load_elf.c
+++ b/usr/src/boot/sys/boot/common/load_elf.c
@@ -251,11 +251,15 @@ __elfN(loadfile_raw)(char *filename, u_int64_t dest,
if (ef.kernel == 1 && multiboot == 0)
setenv("kernelname", filename, 1);
fp->f_name = strdup(filename);
- if (multiboot == 0)
- fp->f_type = strdup(ef.kernel ?
- __elfN(kerneltype) : __elfN(moduletype));
- else
- fp->f_type = strdup("elf multiboot kernel");
+ if (multiboot == 0) {
+ fp->f_type = strdup(ef.kernel ?
+ __elfN(kerneltype) : __elfN(moduletype));
+ } else {
+ if (multiboot == 1)
+ fp->f_type = strdup("elf multiboot kernel");
+ else
+ fp->f_type = strdup("elf multiboot2 kernel");
+ }
#ifdef ELF_VERBOSE
if (ef.kernel)
diff --git a/usr/src/boot/sys/boot/common/module.c b/usr/src/boot/sys/boot/common/module.c
index b091cf23b6..1af4d08f56 100644
--- a/usr/src/boot/sys/boot/common/module.c
+++ b/usr/src/boot/sys/boot/common/module.c
@@ -413,6 +413,7 @@ file_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
char *name;
int fd, got;
vm_offset_t laddr;
+ struct stat st;
/* We can't load first */
if ((file_findfile(NULL, NULL)) == NULL) {
@@ -434,12 +435,25 @@ file_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
free(name);
return(NULL);
}
+ if (fstat(fd, &st) < 0) {
+ close(fd);
+ snprintf(command_errbuf, sizeof (command_errbuf),
+ "stat error '%s': %s", name, strerror(errno));
+ free(name);
+ return(NULL);
+ }
if (archsw.arch_loadaddr != NULL)
loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
+ if (loadaddr == 0) {
+ close(fd);
+ snprintf(command_errbuf, sizeof (command_errbuf),
+ "no memory to load %s", name);
+ free(name);
+ return(NULL);
+ }
- laddr = roundup(loadaddr, PAGE_SIZE);
- loadaddr = laddr;
+ laddr = loadaddr;
for (;;) {
/* read in 4k chunks; size is not really important */
got = archsw.arch_readin(fd, laddr, 4096);
@@ -450,6 +464,9 @@ file_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
"error reading '%s': %s", name, strerror(errno));
free(name);
close(fd);
+ if (archsw.arch_free_loadaddr != NULL)
+ archsw.arch_free_loadaddr(loadaddr,
+ (uint64_t)(roundup2(st.st_size, PAGE_SIZE) >> 12));
return(NULL);
}
laddr += got;
@@ -893,6 +910,11 @@ file_discard(struct preloaded_file *fp)
struct kernel_module *mp, *mp1;
if (fp == NULL)
return;
+
+ if (archsw.arch_free_loadaddr != NULL && fp->f_addr)
+ archsw.arch_free_loadaddr(fp->f_addr,
+ (uint64_t)(roundup2(fp->f_size, PAGE_SIZE) >> 12));
+
md = fp->f_metadata;
while (md) {
md1 = md;
diff --git a/usr/src/boot/sys/boot/common/multiboot2.c b/usr/src/boot/sys/boot/common/multiboot2.c
new file mode 100644
index 0000000000..dd13d5fee5
--- /dev/null
+++ b/usr/src/boot/sys/boot/common/multiboot2.c
@@ -0,0 +1,891 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Toomas Soome <tsoome@me.com>
+ */
+
+/*
+ * This module adds support for loading and booting illumos multiboot2
+ * kernel. This code is only built to support the illumos kernel, it does
+ * not support xen.
+ */
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/stdint.h>
+#include <sys/multiboot2.h>
+#include <stand.h>
+#include <stdbool.h>
+#include "libzfs.h"
+
+#include "bootstrap.h"
+
+#include <machine/metadata.h>
+#include <machine/pc/bios.h>
+
+#include "../i386/libi386/libi386.h"
+#include "../i386/btx/lib/btxv86.h"
+#include "pxe.h"
+
+extern BOOTPLAYER bootplayer; /* dhcp info */
+extern void multiboot_tramp();
+
+#include "platform/acfreebsd.h"
+#include "acconfig.h"
+#define ACPI_SYSTEM_XFACE
+#include "actypes.h"
+#include "actbl.h"
+
+extern ACPI_TABLE_RSDP *rsdp;
+
+/* MB data heap pointer. */
+static vm_offset_t last_addr;
+extern char bootprog_info[];
+
+extern int elf32_loadfile_raw(char *filename, u_int64_t dest,
+ struct preloaded_file **result, int multiboot);
+static int multiboot2_loadfile(char *, u_int64_t, struct preloaded_file **);
+static int multiboot2_exec(struct preloaded_file *);
+
+struct file_format multiboot2 = { multiboot2_loadfile, multiboot2_exec };
+static bool keep_bs = false;
+static bool have_framebuffer = false;
+static vm_offset_t load_addr;
+static vm_offset_t entry_addr;
+
+/*
+ * Validate tags in info request. This function is provided just to
+ * recognize the current tag list and only serves as a limited
+ * safe guard against possibly corrupt information.
+ */
+static bool
+is_info_request_valid(multiboot_header_tag_information_request_t *rtag)
+{
+ int i;
+
+ /*
+ * If the tag is optional and we do not support it, we do not
+ * have to do anything special, so we skip optional tags.
+ */
+ if (rtag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)
+ return (true);
+
+ for (i = 0; i < (rtag->mbh_size - sizeof (*rtag)) /
+ sizeof (rtag->mbh_requests[0]); i++)
+ switch (rtag->mbh_requests[i]) {
+ case MULTIBOOT_TAG_TYPE_END:
+ case MULTIBOOT_TAG_TYPE_CMDLINE:
+ case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
+ case MULTIBOOT_TAG_TYPE_MODULE:
+ case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
+ case MULTIBOOT_TAG_TYPE_BOOTDEV:
+ case MULTIBOOT_TAG_TYPE_MMAP:
+ case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
+ case MULTIBOOT_TAG_TYPE_VBE:
+ case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
+ case MULTIBOOT_TAG_TYPE_APM:
+ case MULTIBOOT_TAG_TYPE_EFI32:
+ case MULTIBOOT_TAG_TYPE_EFI64:
+ case MULTIBOOT_TAG_TYPE_ACPI_OLD:
+ case MULTIBOOT_TAG_TYPE_ACPI_NEW:
+ case MULTIBOOT_TAG_TYPE_NETWORK:
+ case MULTIBOOT_TAG_TYPE_EFI_MMAP:
+ case MULTIBOOT_TAG_TYPE_EFI_BS:
+ case MULTIBOOT_TAG_TYPE_EFI32_IH:
+ case MULTIBOOT_TAG_TYPE_EFI64_IH:
+ case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
+ break;
+ default:
+ printf("unsupported information tag: 0x%x\n",
+ rtag->mbh_requests[i]);
+ return (false);
+ }
+ return (true);
+}
+
+static int
+multiboot2_loadfile(char *filename, u_int64_t dest,
+ struct preloaded_file **result)
+{
+ int fd, error;
+ uint32_t i;
+ struct stat st;
+ caddr_t header_search;
+ multiboot2_header_t *header;
+ multiboot_header_tag_t *tag;
+ multiboot_header_tag_address_t *addr_tag = NULL;
+ multiboot_header_tag_entry_address_t *entry_tag = NULL;
+ struct preloaded_file *fp;
+
+ /* This allows to check other file formats from file_formats array. */
+ error = EFTYPE;
+ if (filename == NULL)
+ return (error);
+
+ /* is kernel already loaded? */
+ fp = file_findfile(NULL, NULL);
+ if (fp != NULL)
+ return (error);
+
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ return (errno);
+
+ /*
+ * Read MULTIBOOT_SEARCH size in order to search for the
+ * multiboot magic header.
+ */
+ header_search = malloc(MULTIBOOT_SEARCH);
+ if (header_search == NULL) {
+ close(fd);
+ return (ENOMEM);
+ }
+
+ if (read(fd, header_search, MULTIBOOT_SEARCH) != MULTIBOOT_SEARCH)
+ goto out;
+
+ header = NULL;
+ for (i = 0; i <= (MULTIBOOT_SEARCH - sizeof (multiboot2_header_t));
+ i += MULTIBOOT_HEADER_ALIGN) {
+ header = (multiboot2_header_t *)(header_search + i);
+
+ /* Do we have match on magic? */
+ if (header->mb2_magic != MULTIBOOT2_HEADER_MAGIC) {
+ header = NULL;
+ continue;
+ }
+ /*
+ * Validate checksum, the sum of magic + architecture +
+ * header_length + checksum must equal 0.
+ */
+ if (header->mb2_magic + header->mb2_architecture +
+ header->mb2_header_length + header->mb2_checksum != 0) {
+ header = NULL;
+ continue;
+ }
+ /*
+ * Finally, the entire header must fit within MULTIBOOT_SEARCH.
+ */
+ if (i + header->mb2_header_length > MULTIBOOT_SEARCH) {
+ header = NULL;
+ continue;
+ }
+ break;
+ }
+
+ if (header == NULL)
+ goto out;
+
+ for (tag = header->mb2_tags; tag->mbh_type != MULTIBOOT_TAG_TYPE_END;
+ tag = (multiboot_header_tag_t *)((uintptr_t)tag +
+ roundup2(tag->mbh_size, MULTIBOOT_TAG_ALIGN))) {
+ switch (tag->mbh_type) {
+ case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST:
+ if (is_info_request_valid((void*)tag) == false)
+ goto out;
+ break;
+ case MULTIBOOT_HEADER_TAG_ADDRESS:
+ addr_tag = (multiboot_header_tag_address_t *)tag;
+ break;
+ case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS:
+ entry_tag =
+ (multiboot_header_tag_entry_address_t *)tag;
+ break;
+ case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
+ break;
+ case MULTIBOOT_HEADER_TAG_FRAMEBUFFER:
+ have_framebuffer = true;
+ break;
+ case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
+ /* we always align modules */
+ break;
+ case MULTIBOOT_HEADER_TAG_EFI_BS:
+ keep_bs = true;
+ break;
+ default:
+ if (!(tag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) {
+ printf("unsupported tag: 0x%x\n",
+ tag->mbh_type);
+ goto out;
+ }
+ }
+ }
+
+ /*
+ * We must have addr_tag and entry_tag to load a 64-bit kernel.
+ * If these tags are missing, we either have a 32-bit kernel, or
+ * this is not our kernel at all.
+ */
+ if (addr_tag != NULL && entry_tag != NULL) {
+ fp = file_alloc();
+ if (fp == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ printf("lseek failed\n");
+ error = EIO;
+ file_discard(fp);
+ goto out;
+ }
+ if (fstat(fd, &st) < 0) {
+ printf("fstat failed\n");
+ error = EIO;
+ file_discard(fp);
+ goto out;
+ }
+
+ load_addr = addr_tag->mbh_load_addr;
+ entry_addr = entry_tag->mbh_entry_addr;
+ fp->f_addr = archsw.arch_loadaddr(LOAD_KERN, filename,
+ addr_tag->mbh_load_addr);
+ if (fp->f_addr == 0) {
+ error = ENOMEM;
+ file_discard(fp);
+ goto out;
+ }
+ fp->f_size = archsw.arch_readin(fd, fp->f_addr, st.st_size);
+
+ if (fp->f_size != st.st_size) {
+ printf("error reading: %s", strerror(errno));
+ file_discard(fp);
+ error = EIO;
+ goto out;
+ }
+
+ fp->f_name = strdup(filename);
+ fp->f_type = strdup("aout multiboot2 kernel");
+ if (fp->f_name == NULL || fp->f_type == NULL) {
+ error = ENOMEM;
+ file_discard(fp);
+ goto out;
+ }
+
+ fp->f_metadata = NULL;
+ error = 0;
+ } else {
+ /* elf32_loadfile_raw will fill the attributes in fp. */
+ error = elf32_loadfile_raw(filename, dest, &fp, 2);
+ if (error != 0) {
+ printf("elf32_loadfile_raw failed: %d unable to "
+ "load multiboot2 kernel\n", error);
+ goto out;
+ }
+ entry_addr = fp->f_addr;
+ /*
+ * We want the load_addr to have some legal value,
+ * so we set it same as the entry_addr.
+ * The distinction is important with UEFI, but not
+ * with BIOS version, because BIOS version does not use
+ * staging area.
+ */
+ load_addr = fp->f_addr;
+ }
+
+ setenv("kernelname", fp->f_name, 1);
+ bios_addsmapdata(fp);
+ *result = fp;
+out:
+ free(header_search);
+ close(fd);
+ return (error);
+}
+
+/*
+ * 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 the original command line
+ * so we have a 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 *os_console = getenv("os_console");
+ char *ttymode = NULL;
+ char mode[10];
+ char *tmp;
+ int len;
+
+ if (os_console == NULL) {
+ tmp = strdup(getenv("console"));
+ os_console = strsep(&tmp, ", ");
+ } else {
+ os_console = strdup(os_console);
+ }
+
+ if (os_console == NULL)
+ return (cl);
+
+ if (strncmp(os_console, "tty", 3) == 0) {
+ snprintf(mode, sizeof (mode), "%s-mode", os_console);
+ ttymode = getenv(mode); /* We will never get NULL. */
+ }
+
+ if (strstr(cl, "-B") != NULL) {
+ len = strlen(cl) + 1;
+ /*
+ * If console is not present, add it.
+ * If console is ttyX, add ttymode.
+ */
+ tmp = strstr(cl, "console");
+ if (tmp == NULL) {
+ len += 12; /* " -B console=" */
+ len += strlen(os_console);
+ if (ttymode != NULL) {
+ len += 13; /* ",ttyX-mode=\"\"" */
+ len += strlen(ttymode);
+ }
+ tmp = malloc(len);
+ if (tmp == NULL) {
+ free(os_console);
+ return (cl);
+ }
+ if (ttymode != NULL) {
+ snprintf(tmp, len,
+ "%s -B console=%s,%s-mode=\"%s\"",
+ cl, os_console, os_console, ttymode);
+ } else {
+ snprintf(tmp, len, "%s -B console=%s",
+ cl, os_console);
+ }
+ } else {
+ /* console is set, do we need tty mode? */
+ tmp += 8;
+ if (strstr(tmp, "tty") == tmp) {
+ strncpy(mode, tmp, 4);
+ mode[4] = '\0';
+ strncat(mode, "-mode", 5);
+ ttymode = getenv(mode);
+ } else { /* nope */
+ free(os_console);
+ return (cl);
+ }
+ len = strlen(cl) + 1;
+ len += 13; /* ",ttyX-mode=\"\"" */
+ len += strlen(ttymode);
+ tmp = malloc(len);
+ if (tmp == NULL) {
+ free(os_console);
+ return (cl);
+ }
+ snprintf(tmp, len, "%s,%s=\"%s\"", cl, mode, ttymode);
+ }
+ } else {
+ /*
+ * no -B, so we need to add " -B console=%s[,ttyX-mode=\"%s\"]"
+ */
+ len = strlen(cl) + 1;
+ len += 12; /* " -B console=" */
+ len += strlen(os_console);
+ if (ttymode != NULL) {
+ len += 13; /* ",ttyX-mode=\"\"" */
+ len += strlen(ttymode);
+ }
+ tmp = malloc(len);
+ if (tmp == NULL) {
+ free(os_console);
+ return (cl);
+ }
+ if (ttymode != NULL) {
+ snprintf(tmp, len, "%s -B console=%s,%s-mode=\"%s\"",
+ cl, os_console, os_console, ttymode);
+ } else {
+ snprintf(tmp, len, "%s -B console=%s", cl, os_console);
+ }
+ }
+ free(os_console);
+ free(cl);
+ return (tmp);
+}
+
+/*
+ * Search the command line for named property.
+ *
+ * Return codes:
+ * 0 The name is found, we return the data in value and len.
+ * ENOENT The name is not found.
+ * EINVAL The provided command line is badly formed.
+ */
+static int
+find_property_value(const char *cmd, const char *name, const char **value,
+ size_t *len)
+{
+ const char *namep, *valuep;
+ size_t name_len, value_len;
+ int quoted;
+
+ *value = NULL;
+ *len = 0;
+
+ if (cmd == NULL)
+ return (ENOENT);
+
+ while (*cmd != '\0') {
+ if (cmd[0] != '-' || cmd[1] != 'B') {
+ cmd++;
+ continue;
+ }
+ cmd += 2; /* Skip -B */
+ while (cmd[0] == ' ' || cmd[0] == '\t')
+ cmd++; /* Skip whitespaces. */
+ while (*cmd != '\0' && cmd[0] != ' ' && cmd[0] != '\t') {
+ namep = cmd;
+ valuep = strchr(cmd, '=');
+ if (valuep == NULL)
+ break;
+ name_len = valuep - namep;
+ valuep++;
+ value_len = 0;
+ quoted = 0;
+ for (; ; ++value_len) {
+ if (valuep[value_len] == '\0')
+ break;
+
+ /* Is this value quoted? */
+ if (value_len == 0 &&
+ (valuep[0] == '\'' || valuep[0] == '"')) {
+ quoted = valuep[0];
+ ++value_len;
+ }
+
+ /*
+ * In the quote accept any character,
+ * but look for ending quote.
+ */
+ if (quoted != 0) {
+ if (valuep[value_len] == quoted)
+ quoted = 0;
+ continue;
+ }
+
+ /* A comma or white space ends the value. */
+ if (valuep[value_len] == ',' ||
+ valuep[value_len] == ' ' ||
+ valuep[value_len] == '\t')
+ break;
+ }
+ if (quoted != 0) {
+ printf("Missing closing '%c' in \"%s\"\n",
+ quoted, valuep);
+ return (EINVAL);
+ }
+ if (value_len != 0) {
+ if (strncmp(namep, name, name_len) == 0) {
+ *value = valuep;
+ *len = value_len;
+ return (0);
+ }
+ }
+ cmd = valuep + value_len;
+ while (*cmd == ',')
+ cmd++;
+ }
+ }
+ return (ENOENT);
+}
+
+/*
+ * Build the kernel command line. Shared function between MB1 and MB2.
+ */
+int
+mb_kernel_cmdline(struct preloaded_file *fp, struct devdesc *rootdev,
+ char **line)
+{
+ const char *fs = getenv("fstype");
+ char *cmdline = NULL;
+ size_t len;
+ bool zfs_root = false;
+ int rv = 0;
+
+ if (rootdev->d_type == DEVT_ZFS)
+ zfs_root = true;
+
+ /* If we have fstype set in env, reset zfs_root if needed. */
+ if (fs != NULL && strcmp(fs, "zfs") != 0)
+ zfs_root = false;
+
+ /*
+ * If we have fstype set on the command line,
+ * reset zfs_root if needed.
+ */
+ rv = find_property_value(fp->f_args, "fstype", &fs, &len);
+ switch (rv) {
+ case EINVAL: /* invalid command line */
+ default:
+ return (rv);
+ case ENOENT: /* fall through */
+ case 0:
+ break;
+ }
+
+ if (fs != NULL && strncmp(fs, "zfs", len) != 0)
+ zfs_root = false;
+
+ len = strlen(fp->f_name) + 1;
+
+ if (fp->f_args != NULL)
+ len += strlen(fp->f_args) + 1;
+
+ if (zfs_root == true)
+ len += 3 + strlen(zfs_bootfs(rootdev)) + 1;
+
+ cmdline = malloc(len);
+ if (cmdline == NULL)
+ return (ENOMEM);
+
+ if (zfs_root == true) {
+ if (fp->f_args != NULL) {
+ snprintf(cmdline, len, "%s %s -B %s", fp->f_name,
+ fp->f_args, zfs_bootfs(rootdev));
+ } else {
+ snprintf(cmdline, len, "%s -B %s", fp->f_name,
+ zfs_bootfs(rootdev));
+ }
+ } else if (fp->f_args != NULL)
+ snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
+ else
+ snprintf(cmdline, len, "%s", fp->f_name);
+
+ *line = update_cmdline(cmdline);
+ return (0);
+}
+
+/*
+ * Returns allocated virtual address from MB info area.
+ */
+static vm_offset_t
+mb_malloc(size_t n)
+{
+ vm_offset_t ptr = last_addr;
+ last_addr = roundup(last_addr + n, MULTIBOOT_TAG_ALIGN);
+ return (ptr);
+}
+
+/*
+ * Calculate size for module tag list.
+ */
+static size_t
+module_size(struct preloaded_file *fp)
+{
+ size_t len, size;
+ struct preloaded_file *mfp;
+
+ size = 0;
+ for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
+ len = strlen(mfp->f_name) + 1;
+ len += strlen(mfp->f_type) + 5 + 1; /* 5 is for "type=" */
+ if (mfp->f_args != NULL)
+ len += strlen(mfp->f_args) + 1;
+ size += sizeof (multiboot_tag_module_t) + len;
+ size = roundup(size, MULTIBOOT_TAG_ALIGN);
+ }
+ return (size);
+}
+
+/*
+ * Calculate size for bios smap tag.
+ */
+static size_t
+biossmap_size(struct preloaded_file *fp)
+{
+ int num;
+ struct file_metadata *md;
+
+ md = file_findmetadata(fp, MODINFOMD_SMAP);
+ if (md == NULL)
+ return (0);
+
+ num = md->md_size / sizeof(struct bios_smap); /* number of entries */
+ return (sizeof (multiboot_tag_mmap_t) +
+ num * sizeof (multiboot_mmap_entry_t));
+}
+
+static size_t
+mbi_size(struct preloaded_file *fp, char *cmdline)
+{
+ size_t size;
+
+ size = sizeof (uint32_t) * 2; /* first 2 fields from MBI header */
+ size += sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+ size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+ size += sizeof (multiboot_tag_basic_meminfo_t);
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+ size += module_size(fp);
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+ size += biossmap_size(fp);
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+
+ if (strstr(getenv("loaddev"), "pxe") != NULL) {
+ size += sizeof(multiboot_tag_network_t) + sizeof (BOOTPLAYER);
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+ }
+
+ if (rsdp != NULL) {
+ if (rsdp->Revision == 0) {
+ size += sizeof (multiboot_tag_old_acpi_t) +
+ sizeof(ACPI_RSDP_COMMON);
+ } else {
+ size += sizeof (multiboot_tag_new_acpi_t) +
+ rsdp->Length;
+ }
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+ }
+ size += sizeof(multiboot_tag_t);
+
+ return (size);
+}
+
+static int
+multiboot2_exec(struct preloaded_file *fp)
+{
+ struct preloaded_file *mfp;
+ multiboot2_info_header_t *mbi;
+ char *cmdline = NULL;
+ struct devdesc *rootdev;
+ struct file_metadata *md;
+ int i, error, num;
+ int rootfs = 0;
+ size_t size;
+ struct bios_smap *smap;
+ vm_offset_t tmp;
+ i386_getdev((void **)(&rootdev), NULL, NULL);
+
+ error = EINVAL;
+ if (rootdev == NULL) {
+ printf("can't determine root device\n");
+ goto error;
+ }
+
+ /*
+ * Set the image command line.
+ */
+ if (fp->f_args == NULL) {
+ cmdline = getenv("boot-args");
+ if (cmdline != NULL) {
+ fp->f_args = strdup(cmdline);
+ if (fp->f_args == NULL) {
+ error = ENOMEM;
+ goto error;
+ }
+ }
+ }
+
+ error = mb_kernel_cmdline(fp, rootdev, &cmdline);
+ if (error != 0)
+ goto error;
+
+ size = mbi_size(fp, cmdline); /* Get the size for MBI. */
+
+ /* Set up the base for mb_malloc. */
+ for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);
+
+ /* Start info block from the new page. */
+ last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);
+
+ /* Do we have space for multiboot info? */
+ if (last_addr + size >= memtop_copyin) {
+ error = ENOMEM;
+ goto error;
+ }
+
+ mbi = (multiboot2_info_header_t *)PTOV(last_addr);
+ last_addr = (vm_offset_t)mbi->mbi_tags;
+
+ {
+ multiboot_tag_string_t *tag;
+ i = sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
+ tag = (multiboot_tag_string_t *) mb_malloc(i);
+
+ tag->mb_type = MULTIBOOT_TAG_TYPE_CMDLINE;
+ tag->mb_size = i;
+ memcpy(tag->mb_string, cmdline, strlen(cmdline) + 1);
+ free(cmdline);
+ cmdline = NULL;
+ }
+
+ {
+ multiboot_tag_string_t *tag;
+ i = sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
+ tag = (multiboot_tag_string_t *) mb_malloc(i);
+
+ tag->mb_type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;
+ tag->mb_size = i;
+ memcpy(tag->mb_string, bootprog_info,
+ strlen(bootprog_info) + 1);
+ }
+
+ {
+ multiboot_tag_basic_meminfo_t *tag;
+ tag = (multiboot_tag_basic_meminfo_t *)
+ mb_malloc(sizeof (*tag));
+
+ tag->mb_type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO;
+ tag->mb_size = sizeof (*tag);
+ tag->mb_mem_lower = bios_basemem / 1024;
+ tag->mb_mem_upper = bios_extmem / 1024;
+ }
+
+ num = 0;
+ for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
+ num++;
+ if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
+ rootfs++;
+ }
+
+ if (num == 0 || rootfs == 0) {
+ /* We need at least one module - rootfs. */
+ printf("No rootfs module provided, aborting\n");
+ error = EINVAL;
+ goto error;
+ }
+
+ /*
+ * Set the stage for physical memory layout:
+ * - We have kernel at load_addr.
+ * - Modules are aligned to page boundary.
+ * - MBI is aligned to page boundary.
+ * - Set the tmp to point to physical address of the first module.
+ */
+ tmp = roundup2(load_addr + fp->f_size, MULTIBOOT_MOD_ALIGN);
+
+ for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
+ multiboot_tag_module_t *tag;
+
+ num = strlen(mfp->f_name) + 1;
+ num += strlen(mfp->f_type) + 5 + 1;
+ if (mfp->f_args != NULL) {
+ num += strlen(mfp->f_args) + 1;
+ }
+ cmdline = malloc(num);
+ if (cmdline == NULL) {
+ error = ENOMEM;
+ goto error;
+ }
+
+ if (mfp->f_args != NULL)
+ snprintf(cmdline, num, "%s type=%s %s",
+ mfp->f_name, mfp->f_type, mfp->f_args);
+ else
+ snprintf(cmdline, num, "%s type=%s",
+ mfp->f_name, mfp->f_type);
+
+ tag = (multiboot_tag_module_t *)mb_malloc(sizeof (*tag) + num);
+
+ tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE;
+ tag->mb_size = sizeof (*tag) + num;
+ tag->mb_mod_start = tmp;
+ tag->mb_mod_end = tmp + mfp->f_size;
+ tmp = roundup2(tag->mb_mod_end, MULTIBOOT_MOD_ALIGN);
+ memcpy(tag->mb_cmdline, cmdline, num);
+ free(cmdline);
+ cmdline = NULL;
+ }
+
+ md = file_findmetadata(fp, MODINFOMD_SMAP);
+ if (md == NULL) {
+ printf("no memory smap\n");
+ error = EINVAL;
+ goto error;
+ }
+
+ smap = (struct bios_smap *)md->md_data;
+ num = md->md_size / sizeof(struct bios_smap); /* number of entries */
+
+ {
+ multiboot_tag_mmap_t *tag;
+ multiboot_mmap_entry_t *mmap_entry;
+
+ tag = (multiboot_tag_mmap_t *)
+ mb_malloc(sizeof (*tag) +
+ num * sizeof (multiboot_mmap_entry_t));
+
+ tag->mb_type = MULTIBOOT_TAG_TYPE_MMAP;
+ tag->mb_size = sizeof (*tag) +
+ num * sizeof (multiboot_mmap_entry_t);
+ tag->mb_entry_size = sizeof (multiboot_mmap_entry_t);
+ tag->mb_entry_version = 0;
+ mmap_entry = (multiboot_mmap_entry_t *)tag->mb_entries;
+
+ for (i = 0; i < num; i++) {
+ mmap_entry[i].mmap_addr = smap[i].base;
+ mmap_entry[i].mmap_len = smap[i].length;
+ mmap_entry[i].mmap_type = smap[i].type;
+ mmap_entry[i].mmap_reserved = 0;
+ }
+ }
+
+ if (strstr(getenv("loaddev"), "pxe") != NULL) {
+ multiboot_tag_network_t *tag;
+ tag = (multiboot_tag_network_t *)
+ mb_malloc(sizeof(*tag) + sizeof (BOOTPLAYER));
+
+ tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK;
+ tag->mb_size = sizeof(*tag) + sizeof (BOOTPLAYER);
+ memcpy(tag->mb_dhcpack, &bootplayer, sizeof (BOOTPLAYER));
+ }
+
+ if (rsdp != NULL) {
+ multiboot_tag_new_acpi_t *ntag;
+ multiboot_tag_old_acpi_t *otag;
+ int size;
+
+ if (rsdp->Revision == 0) {
+ size = sizeof (*otag) + rsdp->Length;
+ otag = (multiboot_tag_old_acpi_t *)mb_malloc(size);
+ otag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_OLD;
+ otag->mb_size = size;
+ memcpy(otag->mb_rsdp, rsdp, sizeof (ACPI_RSDP_COMMON));
+ } else {
+ size = sizeof (*ntag) + rsdp->Length;
+ ntag = (multiboot_tag_new_acpi_t *)mb_malloc(size);
+ ntag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_NEW;
+ ntag->mb_size = size;
+ memcpy(ntag->mb_rsdp, rsdp, rsdp->Length);
+ }
+ }
+
+ /*
+ * MB tag list end marker.
+ */
+ {
+ multiboot_tag_t *tag = (multiboot_tag_t *)
+ mb_malloc(sizeof(*tag));
+ tag->mb_type = MULTIBOOT_TAG_TYPE_END;
+ tag->mb_size = sizeof(*tag);
+ }
+
+ mbi->mbi_total_size = last_addr - (vm_offset_t)mbi;
+ mbi->mbi_reserved = 0;
+
+ dev_cleanup();
+ __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC,
+ (void *)entry_addr, (void *)VTOP(mbi));
+ panic("exec returned");
+
+error:
+ if (cmdline != NULL)
+ free(cmdline);
+ return (error);
+}
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosacpi.c b/usr/src/boot/sys/boot/i386/libi386/biosacpi.c
index 18f8050783..a82862dd3f 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biosacpi.c
+++ b/usr/src/boot/sys/boot/i386/libi386/biosacpi.c
@@ -43,6 +43,7 @@
* environment.
*/
+ACPI_TABLE_RSDP *rsdp;
static ACPI_TABLE_RSDP *biosacpi_find_rsdp(void);
static ACPI_TABLE_RSDP *biosacpi_search_rsdp(char *base, int length);
@@ -51,7 +52,6 @@ static ACPI_TABLE_RSDP *biosacpi_search_rsdp(char *base, int length);
void
biosacpi_detect(void)
{
- ACPI_TABLE_RSDP *rsdp;
char buf[24];
int revision;
diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot.c b/usr/src/boot/sys/boot/i386/libi386/multiboot.c
index 899f75bca6..32e4fe3b07 100644
--- a/usr/src/boot/sys/boot/i386/libi386/multiboot.c
+++ b/usr/src/boot/sys/boot/i386/libi386/multiboot.c
@@ -41,7 +41,6 @@
#include <sys/linker.h>
#include <sys/module.h>
#include <sys/stdint.h>
-#include <stdbool.h>
#define _MACHINE_ELF_WANT_32BIT
#include <machine/elf.h>
#include <machine/metadata.h>
@@ -58,7 +57,6 @@
#define MULTIBOOT_SUPPORTED_FLAGS \
(MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
-#define NUM_MODULES 2
#define METADATA_FIXED_SIZE (PAGE_SIZE*4)
#define METADATA_MODULE_SIZE PAGE_SIZE
@@ -67,12 +65,17 @@
/* MB data heap pointer */
static vm_offset_t last_addr;
+extern char bootprog_info[];
extern int elf32_loadfile_raw(char *filename, u_int64_t dest,
struct preloaded_file **result, int multiboot);
extern int elf64_load_modmetadata(struct preloaded_file *fp, u_int64_t dest);
extern int elf64_obj_loadfile(char *filename, u_int64_t dest,
struct preloaded_file **result);
+extern int mb_kernel_cmdline(struct preloaded_file *, struct devdesc *,
+ char **);
+
+extern void multiboot_tramp();
static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **);
static int multiboot_exec(struct preloaded_file *);
@@ -84,10 +87,6 @@ struct file_format multiboot = { multiboot_loadfile, multiboot_exec };
struct file_format multiboot_obj =
{ multiboot_obj_loadfile, multiboot_obj_exec };
-extern void multiboot_tramp();
-
-static const char mbl_name[] = "illumos Loader";
-
static int
num_modules(struct preloaded_file *kfp)
{
@@ -124,7 +123,6 @@ multiboot_loadfile(char *filename, u_int64_t dest,
ssize_t search_size;
int fd;
struct multiboot_header *header;
- char *cmdline;
struct preloaded_file *fp;
if (filename == NULL)
@@ -219,12 +217,9 @@ multiboot_loadfile(char *filename, u_int64_t dest,
goto out;
}
fp->f_metadata = NULL;
-
- *result = fp;
error = 0;
} else {
-
- error = elf32_loadfile_raw(filename, dest, result, 1);
+ error = elf32_loadfile_raw(filename, dest, &fp, 1);
if (error != 0) {
printf("elf32_loadfile_raw failed: %d unable to "
"load multiboot kernel\n", error);
@@ -232,8 +227,9 @@ multiboot_loadfile(char *filename, u_int64_t dest,
}
}
- setenv("kernelname", (*result)->f_name, 1);
- bios_addsmapdata(*result);
+ setenv("kernelname", fp->f_name, 1);
+ bios_addsmapdata(fp);
+ *result = fp;
out:
free(header_search);
close(fd);
@@ -253,267 +249,6 @@ mb_malloc(size_t n)
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 *os_console = getenv("os_console");
- char *ttymode = NULL;
- char mode[10];
- char *tmp;
- int len;
-
- if (os_console == NULL) {
- tmp = strdup(getenv("console"));
- os_console = strsep(&tmp, ", ");
- } else
- os_console = strdup(os_console);
-
- if (os_console == NULL)
- return (cl);
-
- if (strncmp(os_console, "tty", 3) == 0) {
- snprintf(mode, sizeof (mode), "%s-mode", os_console);
- ttymode = getenv(mode); /* never NULL */
- }
-
- if (strstr(cl, "-B") != NULL) {
- len = strlen(cl) + 1;
- /*
- * if console is not present, add it
- * if console is ttyX, add ttymode
- */
- tmp = strstr(cl, "console");
- if (tmp == NULL) {
- len += 12; /* " -B console=" */
- len += strlen(os_console);
- if (ttymode != NULL) {
- len += 13; /* ",ttyX-mode=\"\"" */
- len += strlen(ttymode);
- }
- tmp = malloc(len);
- if (tmp == NULL) {
- free(os_console);
- return (cl);
- }
- if (ttymode != NULL)
- sprintf(tmp,
- "%s -B console=%s,%s-mode=\"%s\"",
- cl, os_console, os_console, ttymode);
- else
- sprintf(tmp, "%s -B console=%s",
- cl, os_console);
- } else {
- /* console is set, do we need tty mode? */
- tmp += 8;
- if (strstr(tmp, "tty") == tmp) {
- strncpy(mode, tmp, 4);
- mode[4] = '\0';
- strcat(mode, "-mode");
- ttymode = getenv(mode); /* never NULL */
- } else { /* nope */
- free(os_console);
- return (cl);
- }
- len = strlen(cl) + 1;
- len += 13; /* ",ttyX-mode=\"\"" */
- len += strlen(ttymode);
- tmp = malloc(len);
- if (tmp == NULL) {
- free(os_console);
- return (cl);
- }
- sprintf(tmp, "%s,%s=\"%s\"", cl, mode, ttymode);
- }
- } else {
- /*
- * no -B, so we need to add " -B console=%s[,ttyX-mode=\"%s\"]"
- */
- len = strlen(cl) + 1;
- len += 12; /* " -B console=" */
- len += strlen(os_console);
- if (ttymode != NULL) {
- len += 13; /* ",ttyX-mode=\"\"" */
- len += strlen(ttymode);
- }
- tmp = malloc(len);
- if (tmp == NULL) {
- free(os_console);
- return (cl);
- }
- if (ttymode != NULL)
- sprintf(tmp, "%s -B console=%s,%s-mode=\"%s\"", cl,
- os_console, os_console, ttymode);
- else
- sprintf(tmp, "%s -B console=%s", cl, os_console);
- }
- free(os_console);
- free(cl);
- return (tmp);
-}
-
-/*
- * Search the command line for named property.
- *
- * Return codes:
- * 0 The name is found, we return the data in value and len.
- * ENOENT The name is not found.
- * EINVAL The provided command line is badly formed.
- */
-static int
-find_property_value(const char *cmd, const char *name, const char **value,
- size_t *len)
-{
- const char *namep, *valuep;
- size_t name_len, value_len;
- int quoted;
-
- *value = NULL;
- *len = 0;
-
- if (cmd == NULL)
- return (ENOENT);
-
- while (*cmd != '\0') {
- if (cmd[0] != '-' || cmd[1] != 'B') {
- cmd++;
- continue;
- }
- cmd += 2; /* Skip -B */
- while (cmd[0] == ' ' || cmd[0] == '\t')
- cmd++; /* Skip whitespaces. */
- while (*cmd != '\0' && cmd[0] != ' ' && cmd[0] != '\t') {
- namep = cmd;
- valuep = strchr(cmd, '=');
- if (valuep == NULL)
- break;
- name_len = valuep - namep;
- valuep++;
- value_len = 0;
- quoted = 0;
- for (; ; ++value_len) {
- if (valuep[value_len] == '\0')
- break;
-
- /* Is this value quoted? */
- if (value_len == 0 &&
- (valuep[0] == '\'' || valuep[0] == '"')) {
- quoted = valuep[0];
- ++value_len;
- }
-
- /*
- * In the quote accept any character,
- * but look for ending quote.
- */
- if (quoted != 0) {
- if (valuep[value_len] == quoted)
- quoted = 0;
- continue;
- }
-
- /* A comma or white space ends the value. */
- if (valuep[value_len] == ',' ||
- valuep[value_len] == ' ' ||
- valuep[value_len] == '\t')
- break;
- }
- if (quoted != 0) {
- printf("Missing closing '%c' in \"%s\"\n",
- quoted, valuep);
- return (EINVAL);
- }
-
- if (value_len != 0) {
- if (strncmp(namep, name, name_len) == 0) {
- *value = valuep;
- *len = value_len;
- return (0);
- }
- }
- cmd = valuep + value_len;
- while (*cmd == ',')
- cmd++;
- }
- }
- return (ENOENT);
-}
-
-static int
-kernel_cmdline(struct preloaded_file *fp, struct i386_devdesc *rootdev,
- char **line)
-{
- const char *fs = getenv("fstype");
- char *cmdline = NULL;
- size_t len;
- bool zfs_root = false;
- int rv = 0;
-
- if (rootdev->d_type == DEVT_ZFS)
- zfs_root = true;
-
- /* If we have fstype set in env, reset zfs_root if needed. */
- if (fs != NULL && strcmp(fs, "zfs") != 0)
- zfs_root = false;
-
- /*
- * If we have fstype set on the command line,
- * reset zfs_root if needed.
- */
- rv = find_property_value(fp->f_args, "fstype", &fs, &len);
- switch (rv) {
- case EINVAL: /* invalid command line */
- return (rv);
- case ENOENT: /* fall through */
- case 0:
- break;
- }
-
- if (fs != NULL && strncmp(fs, "zfs", len) != 0)
- zfs_root = false;
-
- len = strlen(fp->f_name) + 1;
-
- if (fp->f_args != NULL)
- len += strlen(fp->f_args) + 1;
-
- if (zfs_root == true)
- len += 3 + strlen(zfs_bootfs(rootdev)) + 1;
-
- cmdline = malloc(len);
- if (cmdline == NULL)
- return (ENOMEM);
-
- if (zfs_root == true) {
- if (fp->f_args != NULL)
- snprintf(cmdline, len, "%s %s -B %s", fp->f_name,
- fp->f_args, zfs_bootfs(rootdev));
- else
- snprintf(cmdline, len, "%s -B %s", fp->f_name,
- zfs_bootfs(rootdev));
- } else if (fp->f_args != NULL)
- snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
- else
- snprintf(cmdline, len, "%s", fp->f_name);
-
- *line = update_cmdline(cmdline);
- return (0);
-}
-
static int
multiboot_exec(struct preloaded_file *fp)
{
@@ -521,13 +256,12 @@ multiboot_exec(struct preloaded_file *fp)
vm_offset_t module_start, metadata_size;
vm_offset_t modulep, kernend, entry;
struct file_metadata *md;
- Elf_Ehdr *ehdr;
struct multiboot_info *mb_info = NULL;
struct multiboot_mod_list *mb_mod = NULL;
multiboot_memory_map_t *mmap;
struct bios_smap *smap;
- struct i386_devdesc *rootdev;
- extern BOOTPLAYER bootplayer; /* dhcp info */
+ struct devdesc *rootdev;
+ extern BOOTPLAYER bootplayer; /* dhcp info */
char *cmdline = NULL;
size_t len;
int error, num, i;
@@ -535,10 +269,10 @@ multiboot_exec(struct preloaded_file *fp)
int xen = 0; /* flag for xen */
int kernel = 0; /* flag for kernel */
- /* set up base for mb_malloc */
+ /* Set up base for mb_malloc. */
for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);
- /* start info block from new page */
+ /* Start info block from new page. */
last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);
/* Allocate the multiboot struct and fill the basic details. */
@@ -548,9 +282,10 @@ multiboot_exec(struct preloaded_file *fp)
mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME;
mb_info->mem_lower = bios_basemem / 1024;
mb_info->mem_upper = bios_extmem / 1024;
- mb_info->boot_loader_name = mb_malloc(strlen(mbl_name) + 1);
+ mb_info->boot_loader_name = mb_malloc(strlen(bootprog_info) + 1);
- i386_copyin(mbl_name, mb_info->boot_loader_name, strlen(mbl_name)+1);
+ i386_copyin(bootprog_info, mb_info->boot_loader_name,
+ strlen(bootprog_info) + 1);
i386_getdev((void **)(&rootdev), NULL, NULL);
if (rootdev == NULL) {
@@ -560,12 +295,12 @@ multiboot_exec(struct preloaded_file *fp)
}
/*
- * boot image command line. if args were not provided, we need to set
+ * 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.
+ * 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? */
+ /* Do we boot xen? */
if (strstr(fp->f_name, "unix") == NULL)
xen = 1;
@@ -581,7 +316,7 @@ multiboot_exec(struct preloaded_file *fp)
}
if (num == 0 || rootfs == 0) {
- /* need at least one module - rootfs */
+ /* We need at least one module - rootfs. */
printf("No rootfs module provided, aborting\n");
error = EINVAL;
goto error;
@@ -603,7 +338,7 @@ multiboot_exec(struct preloaded_file *fp)
if (strcmp(mfp->f_type, "kernel") == 0) {
cmdline = NULL;
- error = kernel_cmdline(mfp, rootdev, &cmdline);
+ error = mb_kernel_cmdline(mfp, rootdev, &cmdline);
if (error != 0)
goto error;
} else {
@@ -667,7 +402,7 @@ multiboot_exec(struct preloaded_file *fp)
}
/*
* Set the image command line. Need to do this as last thing,
- * as Illumos kernel dboot_startkern will check cmdline
+ * as illumos kernel dboot_startkern will check cmdline
* address as last check to find first free address.
*/
if (fp->f_args == NULL) {
@@ -685,7 +420,7 @@ multiboot_exec(struct preloaded_file *fp)
}
/*
- * if image is xen, we just use f_name + f_args for commandline
+ * If the image is xen, we just use f_name + f_args for commandline
* for unix, we need to add zfs-bootfs.
*/
if (xen) {
@@ -708,7 +443,7 @@ multiboot_exec(struct preloaded_file *fp)
}
} else {
cmdline = NULL;
- if ((error = kernel_cmdline(fp, rootdev, &cmdline)) != 0)
+ if ((error = mb_kernel_cmdline(fp, rootdev, &cmdline)) != 0)
goto error;
}
@@ -719,8 +454,8 @@ multiboot_exec(struct preloaded_file *fp)
cmdline = NULL;
dev_cleanup();
- __exec((void *)VTOP(multiboot_tramp), (void *)entry,
- (void *)VTOP(mb_info));
+ __exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC,
+ (void *)entry, (void *)VTOP(mb_info));
panic("exec returned");
diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S b/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S
index 0bd604365f..452a86bbb8 100644
--- a/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S
+++ b/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S
@@ -26,9 +26,6 @@
* $FreeBSD$
*/
-#define ASM_FILE
-#include "multiboot.h"
-
/*
* The multiboot specification requires the executable to be launched
* with %cs set to a flat read/execute segment with offset 0 and limit
@@ -43,9 +40,9 @@ multiboot_tramp:
/* Be sure that interrupts are disabled. */
cli
- movl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
+ movl 4(%esp), %eax /* bootloader magic */
/* Get the entry point and address of the multiboot_info parameter. */
- movl 8(%esp), %ebx
- movl 4(%esp), %ecx
+ movl 12(%esp), %ebx /* multiboot_info */
+ movl 8(%esp), %ecx /* entry */
call *%ecx
diff --git a/usr/src/boot/sys/boot/i386/loader/Makefile b/usr/src/boot/sys/boot/i386/loader/Makefile
index f2dac3bfc9..1275085c18 100644
--- a/usr/src/boot/sys/boot/i386/loader/Makefile
+++ b/usr/src/boot/sys/boot/i386/loader/Makefile
@@ -17,8 +17,9 @@
include $(SRC)/Makefile.master
include $(SRC)/boot/Makefile.version
-CFLAGS= -O2
-CPPFLAGS= -DSTAND -nostdinc -I../../../../include -I../../..
+CFLAGS= -O2
+CPPFLAGS= -DSTAND -nostdinc -I../../../../include -I../../..
+CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi
LOADER= zfsloader
NEWVERSWHAT= "ZFS enabled bootstrap loader" x86
MAN=
@@ -63,7 +64,7 @@ LIBFICL= ../../ficl/i386/libficl.a
# Always add MI sources
SRCS += boot.c commands.c console.c devopen.c interp.c
SRCS += interp_backslash.c interp_parse.c ls.c misc.c
-SRCS += module.c panic.c linenoise.c
+SRCS += module.c panic.c linenoise.c multiboot2.c
SRCS += load_elf32.c load_elf32_obj.c reloc_elf32.c
SRCS += load_elf64.c load_elf64_obj.c reloc_elf64.c
@@ -107,6 +108,9 @@ CPPFLAGS += -I../btx/lib
include ../Makefile.inc
+# For multiboot2.h, must be last, to avoid conflicts
+CPPFLAGS += -I$(SRC)/uts/common
+
vers.c: ../../common/newvers.sh $(SRC)/boot/Makefile.version
$(SH) ../../common/newvers.sh ${LOADER_VERSION} ${NEWVERSWHAT}
@@ -135,7 +139,6 @@ DPADD= ${LIBFICL} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
LDADD= ${LIBFICL} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
CLEANFILES += machine x86
-CFLAGS += -DLOADER_PREFER_AMD64
machine:
$(RM) machine
diff --git a/usr/src/boot/sys/boot/i386/loader/conf.c b/usr/src/boot/sys/boot/i386/loader/conf.c
index b47c9219e8..d99c3a4b49 100644
--- a/usr/src/boot/sys/boot/i386/loader/conf.c
+++ b/usr/src/boot/sys/boot/i386/loader/conf.c
@@ -101,10 +101,12 @@ extern struct file_format amd64_elf;
extern struct file_format amd64_elf_obj;
extern struct file_format multiboot;
extern struct file_format multiboot_obj;
+extern struct file_format multiboot2;
extern struct file_format linux;
extern struct file_format linux_initrd;
struct file_format *file_formats[] = {
+ &multiboot2,
&multiboot,
&multiboot_obj,
&amd64_elf,
diff --git a/usr/src/boot/sys/boot/i386/loader/main.c b/usr/src/boot/sys/boot/i386/loader/main.c
index be092c552f..02d4ad6d7d 100644
--- a/usr/src/boot/sys/boot/i386/loader/main.c
+++ b/usr/src/boot/sys/boot/i386/loader/main.c
@@ -38,7 +38,9 @@
#include <machine/cpufunc.h>
#include <machine/psl.h>
#include <sys/disk.h>
+#include <sys/param.h>
#include <sys/reboot.h>
+#include <sys/multiboot2.h>
#include "bootstrap.h"
#include "common/bootargs.h"
@@ -81,6 +83,18 @@ extern char end[];
static void *heap_top;
static void *heap_bottom;
+static uint64_t
+i386_loadaddr(u_int type, void *data, uint64_t addr)
+{
+ /*
+ * Our modules are page aligned.
+ */
+ if (type == LOAD_RAW)
+ return (roundup2(addr, MULTIBOOT_MOD_ALIGN));
+
+ return (addr);
+}
+
int
main(void)
{
@@ -162,6 +176,7 @@ main(void)
archsw.arch_readin = i386_readin;
archsw.arch_isainb = isa_inb;
archsw.arch_isaoutb = isa_outb;
+ archsw.arch_loadaddr = i386_loadaddr;
#ifdef LOADER_ZFS_SUPPORT
archsw.arch_zfs_probe = i386_zfs_probe;
#endif