diff options
| author | Toomas Soome <tsoome@me.com> | 2016-10-09 17:07:43 +0300 |
|---|---|---|
| committer | Joshua M. Clulow <josh@sysmgr.org> | 2017-04-21 20:09:34 -0700 |
| commit | 14ee0d29c415966483c8c602b05bf27669c29497 (patch) | |
| tree | 129b7f033dc41ba23e386e4c48f7374d7292e190 | |
| parent | 1738dd6ec94e36a9828d13a6e52ac7fb68cb52ed (diff) | |
| download | illumos-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.version | 2 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/common/bootstrap.h | 10 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/common/load_elf.c | 14 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/common/module.c | 26 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/common/multiboot2.c | 891 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/biosacpi.c | 2 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/multiboot.c | 319 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S | 9 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/i386/loader/Makefile | 11 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/i386/loader/conf.c | 2 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/i386/loader/main.c | 15 |
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 |
