summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith M Wesolowski <wesolows@foobazco.org>2013-11-19 01:12:04 +0000
committerRobert Mustacchi <rm@joyent.com>2015-11-06 22:06:29 -0800
commit0181461b79a0991f2269dad3ef978086e6c70257 (patch)
tree55f870e02664e992272fc66180a908de61a68180
parent99141ac7e1fddf3c8d7a32b9d945448af73e0039 (diff)
downloadillumos-joyent-0181461b79a0991f2269dad3ef978086e6c70257.tar.gz
5886 want ability to provide additional objects at boot
Reviewed by: Robert Mustacchi <rm@joyent.com> Approved by: Gordon Ross <gordon.ross@nexenta.com>
-rw-r--r--usr/src/common/fs/bootfsops.c329
-rw-r--r--usr/src/common/util/string.h3
-rw-r--r--usr/src/common/util/strtolctype.h4
-rw-r--r--usr/src/uts/common/fs/vfs.c2
-rw-r--r--usr/src/uts/common/krtld/bootrd.c83
-rw-r--r--usr/src/uts/common/sys/sunddi.h1
-rw-r--r--usr/src/uts/i86pc/Makefile.rules2
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_startkern.c261
-rw-r--r--usr/src/uts/i86pc/os/fakebop.c49
-rw-r--r--usr/src/uts/i86pc/os/mlsetup.c5
-rw-r--r--usr/src/uts/i86pc/os/startup.c51
-rw-r--r--usr/src/uts/i86pc/sys/fastboot_msg.h1
-rw-r--r--usr/src/uts/intel/Makefile.files3
-rw-r--r--usr/src/uts/intel/sys/bootinfo.h21
-rw-r--r--usr/src/uts/intel/sys/bootvfs.h19
15 files changed, 756 insertions, 78 deletions
diff --git a/usr/src/common/fs/bootfsops.c b/usr/src/common/fs/bootfsops.c
new file mode 100644
index 0000000000..5a693b80e5
--- /dev/null
+++ b/usr/src/common/fs/bootfsops.c
@@ -0,0 +1,329 @@
+/*
+ * 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 2013 Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/bootconf.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/vnode.h>
+#include <sys/fs/ufs_fsdir.h>
+#include <sys/fs/ufs_fs.h>
+#include <sys/fs/ufs_inode.h>
+#include <sys/sysmacros.h>
+#include <sys/bootvfs.h>
+#include <sys/bootinfo.h>
+#include <sys/filep.h>
+
+#ifdef _BOOT
+#include "../common/util.h"
+#else
+#include <sys/sunddi.h>
+#endif
+
+#define MAX_FILES MAX_BOOT_MODULES
+#define MAX_FDS 256
+
+extern void *bkmem_alloc(size_t);
+extern void bkmem_free(void *, size_t);
+
+/*
+ * TODO: Replace these declarations with inclusion of the ordinary userland
+ * bootfs headers once they're available.
+ */
+typedef struct bfile {
+ char bf_name[MAXPATHLEN];
+ caddr_t bf_addr;
+ size_t bf_size;
+ struct bfile *bf_next;
+ uint64_t bf_ino;
+} bfile_t;
+
+typedef struct bf_fd {
+ bfile_t *fd_file;
+ off_t fd_pos;
+} bf_fd_t;
+
+static bfile_t *head;
+static uint_t init_done;
+static bf_fd_t fds[MAX_FDS];
+
+static char cpath[MAXPATHLEN]; /* For canonicalising filenames */
+
+static void bbootfs_closeall(int);
+
+static void
+canonicalise(const char *fn, char *out)
+{
+ const char *p;
+ char *q, *s;
+ char *last;
+ char *oc;
+ int is_slash = 0;
+ static char scratch[MAXPATHLEN];
+
+ if (fn == NULL) {
+ *out = '\0';
+ return;
+ }
+
+ /*
+ * Remove leading slashes and condense all multiple slashes into one.
+ */
+ p = fn;
+ while (*p == '/')
+ ++p;
+
+ for (q = scratch; *p != '\0'; p++) {
+ if (*p == '/' && !is_slash) {
+ *q++ = '/';
+ is_slash = 1;
+ } else if (*p != '/') {
+ *q++ = *p;
+ is_slash = 0;
+ }
+ }
+ *q = '\0';
+
+ if (strncmp(scratch, "system/boot/", 12) == 0 ||
+ strcmp(scratch, "system/boot") == 0) {
+ s = scratch + 12;
+ } else {
+ s = scratch;
+ }
+
+ for (last = strsep(&s, "/"), q = oc = out; last != NULL;
+ last = strsep(&s, "/")) {
+ if (strcmp(last, ".") == 0)
+ continue;
+ if (strcmp(last, "..") == 0) {
+ for (oc = q; oc > out && *oc != '/'; oc--)
+ ;
+ q = oc;
+ continue;
+ }
+ if (q > out)
+ *q++ = '/';
+ q += snprintf(q, MAXPATHLEN - (q - out), "%s", last);
+ }
+
+ *q = '\0';
+}
+
+/* ARGSUSED */
+static int
+bbootfs_mountroot(char *str)
+{
+ return (-1);
+}
+
+static int
+bbootfs_unmountroot(void)
+{
+ return (-1);
+}
+
+static int
+bbootfs_init(void)
+{
+ bfile_t *fp;
+ char propname[32];
+ uint64_t propval;
+ uint_t i;
+
+ for (i = 0; i < MAX_FILES; i++) {
+ (void) snprintf(propname, sizeof (propname),
+ "module-name-%u", i);
+ if (do_bsys_getproplen(NULL, propname) < 0)
+ break;
+
+ if ((fp = bkmem_alloc(sizeof (bfile_t))) == NULL) {
+ bbootfs_closeall(1);
+ return (-1);
+ }
+
+ (void) do_bsys_getprop(NULL, propname, cpath);
+ canonicalise(cpath, fp->bf_name);
+
+ (void) snprintf(propname, sizeof (propname),
+ "module-addr-%u", i);
+ if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) {
+ bkmem_free(fp, sizeof (bfile_t));
+ continue;
+ }
+ (void) do_bsys_getprop(NULL, propname, &propval);
+ fp->bf_addr = (void *)(uintptr_t)propval;
+
+ (void) snprintf(propname, sizeof (propname),
+ "module-size-%u", i);
+ if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) {
+ bkmem_free(fp, sizeof (bfile_t));
+ continue;
+ }
+ (void) do_bsys_getprop(NULL, propname, &propval);
+ fp->bf_size = (size_t)propval;
+ fp->bf_ino = i;
+
+ fp->bf_next = head;
+ head = fp;
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+bbootfs_open(char *fn, int flags)
+{
+ uint_t i;
+ bfile_t *fp;
+
+ if (!init_done) {
+ if (bbootfs_init() != 0)
+ return (-1);
+
+ init_done = 1;
+ }
+
+ canonicalise(fn, cpath);
+
+ for (fp = head; fp != NULL; fp = fp->bf_next) {
+ if (strcmp(fp->bf_name, cpath) == 0)
+ break;
+ }
+
+ if (fp == NULL)
+ return (-1);
+
+ for (i = 0; i < MAX_FDS; i++) {
+ if (fds[i].fd_file == NULL) {
+ fds[i].fd_file = fp;
+ fds[i].fd_pos = 0;
+ return (i);
+ }
+ }
+
+ return (-1);
+}
+
+static int
+bbootfs_close(int fd)
+{
+ if (fds[fd].fd_file == NULL)
+ return (-1);
+
+ fds[fd].fd_file = NULL;
+ fds[fd].fd_pos = 0;
+
+ return (0);
+}
+
+static ssize_t
+bbootfs_read(int fd, caddr_t buf, size_t size)
+{
+ ssize_t len;
+ bf_fd_t *fdp = &fds[fd];
+
+ if (fdp->fd_file == NULL)
+ return (-1);
+
+ if (fdp->fd_pos >= fdp->fd_file->bf_size)
+ return (-1);
+
+ if (fdp->fd_pos + size > fdp->fd_file->bf_size)
+ len = fdp->fd_file->bf_size - fdp->fd_pos;
+ else
+ len = size;
+
+ bcopy(fdp->fd_file->bf_addr + fdp->fd_pos, buf, len);
+
+ fdp->fd_pos += len;
+
+ return (len);
+}
+
+static off_t
+bbootfs_lseek(int fd, off_t addr, int whence)
+{
+ bf_fd_t *fdp = &fds[fd];
+
+ if (fdp->fd_file == NULL)
+ return (-1);
+
+ switch (whence) {
+ case SEEK_CUR:
+ fdp->fd_pos += addr;
+ break;
+ case SEEK_SET:
+ fdp->fd_pos = addr;
+ break;
+ case SEEK_END:
+ fdp->fd_pos = fdp->fd_file->bf_size;
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+bbootfs_fstat(int fd, struct bootstat *bsp)
+{
+ bf_fd_t *fdp = &fds[fd];
+
+ if (fdp->fd_file == NULL)
+ return (-1);
+
+ bsp->st_dev = 1;
+ bsp->st_ino = fdp->fd_file->bf_ino;
+ bsp->st_mode = 0444;
+ bsp->st_nlink = 1;
+ bsp->st_uid = bsp->st_gid = 0;
+ bsp->st_rdev = 0;
+ bsp->st_size = fdp->fd_file->bf_size;
+ bsp->st_blksize = 1;
+ bsp->st_blocks = fdp->fd_file->bf_size;
+ (void) strcpy(bsp->st_fstype, "bootfs");
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+bbootfs_closeall(int flag)
+{
+ bfile_t *fp;
+
+ while (head != NULL) {
+ fp = head;
+ head = head->bf_next;
+
+ bkmem_free(fp, sizeof (bfile_t));
+ }
+
+ init_done = 0;
+}
+
+struct boot_fs_ops bbootfs_ops = {
+ "bootfs",
+ bbootfs_mountroot,
+ bbootfs_unmountroot,
+ bbootfs_open,
+ bbootfs_close,
+ bbootfs_read,
+ bbootfs_lseek,
+ bbootfs_fstat,
+ bbootfs_closeall,
+ NULL
+};
diff --git a/usr/src/common/util/string.h b/usr/src/common/util/string.h
index 052eeab4a4..6a109bf930 100644
--- a/usr/src/common/util/string.h
+++ b/usr/src/common/util/string.h
@@ -27,8 +27,6 @@
#ifndef _COMMON_UTIL_STRING_H
#define _COMMON_UTIL_STRING_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#ifdef __cplusplus
@@ -61,6 +59,7 @@ extern char *strncpy(char *, const char *, size_t);
extern char *strrchr(const char *, int c);
extern char *strstr(const char *, const char *);
extern char *strpbrk(const char *, const char *);
+extern char *strsep(char **, const char *);
extern char *strncat(char *, const char *, size_t);
extern size_t strlcat(char *, const char *, size_t);
extern size_t strlcpy(char *, const char *, size_t);
diff --git a/usr/src/common/util/strtolctype.h b/usr/src/common/util/strtolctype.h
index 5675e42be7..535c014d1f 100644
--- a/usr/src/common/util/strtolctype.h
+++ b/usr/src/common/util/strtolctype.h
@@ -44,7 +44,7 @@ extern "C" {
* safe in probe context.
*/
-#if defined(_KERNEL) && !defined(_BOOT)
+#if defined(_KERNEL) || defined(_BOOT)
#define isalnum(ch) (isalpha(ch) || isdigit(ch))
#define isalpha(ch) (isupper(ch) || islower(ch))
@@ -56,7 +56,7 @@ extern "C" {
#define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
((ch) >= 'A' && (ch) <= 'F'))
-#endif /* _KERNEL && !_BOOT */
+#endif /* _KERNEL || _BOOT */
#define DIGIT(x) \
(isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c
index 1c19c8bfe2..794ec23968 100644
--- a/usr/src/uts/common/fs/vfs.c
+++ b/usr/src/uts/common/fs/vfs.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
diff --git a/usr/src/uts/common/krtld/bootrd.c b/usr/src/uts/common/krtld/bootrd.c
index 08e5d98c09..35ad67da96 100644
--- a/usr/src/uts/common/krtld/bootrd.c
+++ b/usr/src/uts/common/krtld/bootrd.c
@@ -21,6 +21,7 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Joyent, Inc. All rights reserved.
*/
@@ -36,17 +37,95 @@
extern void (*_kobj_printf)(void *, const char *fmt, ...);
extern int get_weakish_int(int *);
extern struct bootops *ops;
-extern struct boot_fs_ops bufs_ops, bhsfs_ops;
+extern struct boot_fs_ops bufs_ops, bhsfs_ops, bbootfs_ops;
extern int kmem_ready;
static uint64_t rd_start, rd_end;
struct boot_fs_ops *bfs_ops;
-struct boot_fs_ops *bfs_tab[] = {&bufs_ops, &bhsfs_ops, NULL};
+struct boot_fs_ops *bfs_tab[] = {&bufs_ops, &bhsfs_ops, &bbootfs_ops, NULL};
static uintptr_t scratch_max = 0;
#define _kmem_ready get_weakish_int(&kmem_ready)
+int
+BRD_MOUNTROOT(struct boot_fs_ops *ops, char *str)
+{
+ return (ops->fsw_mountroot(str));
+}
+
+int
+BRD_UNMOUNTROOT(struct boot_fs_ops *ops)
+{
+ if (bfs_ops != &bbootfs_ops)
+ bbootfs_ops.fsw_closeall(1);
+
+ return (ops->fsw_unmountroot());
+}
+
+int
+BRD_OPEN(struct boot_fs_ops *ops, char *file, int flags)
+{
+ int len = strlen(SYSTEM_BOOT_PATH);
+ int fd;
+
+ /*
+ * Our policy is that we try bootfs first. If bootfs is the only
+ * filesystem, that's the end of it. Otherwise we will fall back to
+ * the normal root (i.e., ramdisk) filesystem at this point and try
+ * again if the file does not exist in bootfs.
+ */
+ fd = bbootfs_ops.fsw_open(file, flags);
+
+ if (bfs_ops == &bbootfs_ops)
+ return (fd);
+
+ if (strncmp(file, SYSTEM_BOOT_PATH, len) == 0 || fd >= 0)
+ return ((fd < 0) ? fd : (fd | BFD_F_SYSTEM_BOOT));
+
+ return (ops->fsw_open(file, flags));
+}
+
+int
+BRD_CLOSE(struct boot_fs_ops *ops, int fd)
+{
+ if (fd & BFD_F_SYSTEM_BOOT)
+ return (bbootfs_ops.fsw_close(fd & ~BFD_F_SYSTEM_BOOT));
+
+ return (ops->fsw_close(fd));
+}
+
+ssize_t
+BRD_READ(struct boot_fs_ops *ops, int fd, caddr_t buf, size_t len)
+{
+ if (fd & BFD_F_SYSTEM_BOOT) {
+ return (bbootfs_ops.fsw_read(fd & ~BFD_F_SYSTEM_BOOT,
+ buf, len));
+ }
+
+ return (ops->fsw_read(fd, buf, len));
+}
+
+off_t
+BRD_SEEK(struct boot_fs_ops *ops, int fd, off_t addr, int whence)
+{
+ if (fd & BFD_F_SYSTEM_BOOT) {
+ return (bbootfs_ops.fsw_lseek(fd & ~BFD_F_SYSTEM_BOOT,
+ addr, whence));
+ }
+
+ return (ops->fsw_lseek(fd, addr, whence));
+}
+
+int
+BRD_FSTAT(struct boot_fs_ops *ops, int fd, struct bootstat *bsp)
+{
+ if (fd & BFD_F_SYSTEM_BOOT)
+ return (bbootfs_ops.fsw_fstat(fd & ~BFD_F_SYSTEM_BOOT, bsp));
+
+ return (ops->fsw_fstat(fd, bsp));
+}
+
/*
* This one reads the ramdisk. If fi_memp is set, we copy the
* ramdisk content to the designated buffer. Otherwise, we
diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h
index bb063c23db..3338ce7a60 100644
--- a/usr/src/uts/common/sys/sunddi.h
+++ b/usr/src/uts/common/sys/sunddi.h
@@ -462,6 +462,7 @@ extern size_t strlcat(char *, const char *, size_t);
extern size_t strlcpy(char *, const char *, size_t);
extern size_t strspn(const char *, const char *);
extern size_t strcspn(const char *, const char *);
+extern char *strsep(char **, const char *);
extern int bcmp(const void *, const void *, size_t) __PURE;
extern int stoi(char **);
extern void numtos(ulong_t, char *);
diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules
index ff68c02eba..cc30fd647a 100644
--- a/usr/src/uts/i86pc/Makefile.rules
+++ b/usr/src/uts/i86pc/Makefile.rules
@@ -221,7 +221,7 @@ DBOOT_DEFS = -D_BOOT $(DBOOT_MACH_$(CLASS))
DBOOT_DEFS += -D_MACHDEP -D_KMEMUSER -U_KERNEL -D_I32LPx
DBOOT_FLAGS = $(CCVERBOSE) $(CERRWARN) $(CCNOAUTOINLINE)
-DBOOT_CC_INCL = -I$(SRC)/common $(INCLUDE_PATH)
+DBOOT_CC_INCL = -I$(SRC)/common -I$(SRC)/common/util $(INCLUDE_PATH)
DBOOT_AS_INCL = $(AS_INC_PATH)
DBOOT_AS = $(ONBLD_TOOLS)/bin/$(MACH)/aw
diff --git a/usr/src/uts/i86pc/dboot/dboot_startkern.c b/usr/src/uts/i86pc/dboot/dboot_startkern.c
index f5f8f95682..7fc43e27bd 100644
--- a/usr/src/uts/i86pc/dboot/dboot_startkern.c
+++ b/usr/src/uts/i86pc/dboot/dboot_startkern.c
@@ -23,7 +23,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2012 Joyent, Inc. All rights reserved.
+ * Copyright 2013 Joyent, Inc. All rights reserved.
*/
@@ -34,6 +34,8 @@
#include <sys/mach_mmu.h>
#include <sys/multiboot.h>
#include <sys/sha1.h>
+#include <util/string.h>
+#include <util/strtolctype.h>
#if defined(__xpv)
@@ -162,8 +164,12 @@ uint_t pcimemlists_used = 0;
struct boot_memlist rsvdmemlists[MAX_MEMLIST];
uint_t rsvdmemlists_used = 0;
-#define MAX_MODULES (10)
-struct boot_modules modules[MAX_MODULES];
+/*
+ * This should match what's in the bootloader. It's arbitrary, but GRUB
+ * in particular has limitations on how much space it can use before it
+ * stops working properly. This should be enough.
+ */
+struct boot_modules modules[MAX_BOOT_MODULES];
uint_t modules_used = 0;
/*
@@ -172,6 +178,8 @@ uint_t modules_used = 0;
uint_t prom_debug = 0;
uint_t map_debug = 0;
+static char noname[2] = "-";
+
/*
* Either hypervisor-specific or grub-specific code builds the initial
* memlists. This code does the sort/merge/link for final use.
@@ -805,13 +813,20 @@ digest_a2h(const char *ascii, uint8_t *digest)
* 4 GB, which should not be a problem.
*/
static int
-check_image_hash(const char *ascii, const void *image, size_t len)
+check_image_hash(uint_t midx)
{
+ const char *ascii;
+ const void *image;
+ size_t len;
SHA1_CTX ctx;
uint8_t digest[SHA1_DIGEST_LENGTH];
uint8_t baseline[SHA1_DIGEST_LENGTH];
unsigned int i;
+ ascii = (const char *)(uintptr_t)modules[midx].bm_hash;
+ image = (const void *)(uintptr_t)modules[midx].bm_addr;
+ len = (size_t)modules[midx].bm_size;
+
digest_a2h(ascii, baseline);
SHA1Init(&ctx);
@@ -826,16 +841,80 @@ check_image_hash(const char *ascii, const void *image, size_t len)
return (0);
}
+static const char *
+type_to_str(boot_module_type_t type)
+{
+ switch (type) {
+ case BMT_ROOTFS:
+ return ("rootfs");
+ case BMT_FILE:
+ return ("file");
+ case BMT_HASH:
+ return ("hash");
+ default:
+ return ("unknown");
+ }
+}
+
static void
check_images(void)
{
- int i;
- char *hashes;
- mb_module_t *mod, *hashmod;
- char *hash;
+ uint_t i;
char displayhash[SHA1_ASCII_LENGTH + 1];
- size_t hashlen;
- size_t len;
+
+ for (i = 0; i < modules_used; i++) {
+ if (prom_debug) {
+ dboot_printf("module #%d: name %s type %s "
+ "addr %lx size %lx\n",
+ i, (char *)(uintptr_t)modules[i].bm_name,
+ type_to_str(modules[i].bm_type),
+ (ulong_t)modules[i].bm_addr,
+ (ulong_t)modules[i].bm_size);
+ }
+
+ if (modules[i].bm_type == BMT_HASH ||
+ modules[i].bm_hash == NULL) {
+ DBG_MSG("module has no hash; skipping check\n");
+ continue;
+ }
+ (void) memcpy(displayhash,
+ (void *)(uintptr_t)modules[i].bm_hash,
+ SHA1_ASCII_LENGTH);
+ displayhash[SHA1_ASCII_LENGTH] = '\0';
+ if (prom_debug) {
+ dboot_printf("checking expected hash [%s]: ",
+ displayhash);
+ }
+
+ if (check_image_hash(i) != 0)
+ dboot_panic("hash mismatch!\n");
+ else
+ DBG_MSG("OK\n");
+ }
+}
+
+/*
+ * Determine the module's starting address, size, name, and type, and fill the
+ * boot_modules structure. This structure is used by the bop code, except for
+ * hashes which are checked prior to transferring control to the kernel.
+ */
+static void
+process_module(mb_module_t *mod)
+{
+ int midx = modules_used++;
+ char *p, *q;
+
+ if (prom_debug) {
+ dboot_printf("\tmodule #%d: '%s' at 0x%lx, end 0x%lx\n",
+ midx, (char *)(mod->mod_name),
+ (ulong_t)mod->mod_start, (ulong_t)mod->mod_end);
+ }
+
+ if (mod->mod_start > mod->mod_end) {
+ dboot_panic("module #%d: module start address 0x%lx greater "
+ "than end address 0x%lx", midx,
+ (ulong_t)mod->mod_start, (ulong_t)mod->mod_end);
+ }
/*
* A brief note on lengths and sizes: GRUB, for reasons unknown, passes
@@ -851,47 +930,128 @@ check_images(void)
* we'll just cope with the bug. That means we won't actually hash the
* byte at mod_end, and we will expect that mod_end for the hash file
* itself is one greater than some multiple of 41 (40 bytes of ASCII
- * hash plus a newline for each module).
+ * hash plus a newline for each module). We set bm_size to the true
+ * correct number of bytes in each module, achieving exactly this.
*/
- if (mb_info->mods_count > 1) {
- mod = (mb_module_t *)mb_info->mods_addr;
- hashmod = mod + (mb_info->mods_count - 1);
- hashes = (char *)hashmod->mod_start;
- hashlen = (size_t)(hashmod->mod_end - hashmod->mod_start);
- hash = hashes;
- if (prom_debug) {
- dboot_printf("Hash module found at %lx size %lx\n",
- (ulong_t)hashes, (ulong_t)hashlen);
- }
- } else {
- DBG_MSG("Skipping hash check; no hash module found.\n");
+ modules[midx].bm_addr = mod->mod_start;
+ modules[midx].bm_size = mod->mod_end - mod->mod_start;
+ modules[midx].bm_name = mod->mod_name;
+ modules[midx].bm_hash = NULL;
+ modules[midx].bm_type = BMT_FILE;
+
+ if (mod->mod_name == NULL) {
+ modules[midx].bm_name = (native_ptr_t)(uintptr_t)noname;
return;
}
- for (mod = (mb_module_t *)(mb_info->mods_addr), i = 0;
- i < mb_info->mods_count - 1; ++mod, ++i) {
- if ((hash - hashes) + SHA1_ASCII_LENGTH + 1 > hashlen) {
- dboot_printf("Short hash module of length 0x%lx bytes; "
- "skipping hash checks\n", (ulong_t)hashlen);
- break;
+ p = (char *)(uintptr_t)mod->mod_name;
+ modules[midx].bm_name =
+ (native_ptr_t)(uintptr_t)strsep(&p, " \t\f\n\r");
+
+ while (p != NULL) {
+ q = strsep(&p, " \t\f\n\r");
+ if (strncmp(q, "name=", 5) == 0) {
+ if (q[5] != '\0' && !isspace(q[5])) {
+ modules[midx].bm_name =
+ (native_ptr_t)(uintptr_t)(q + 5);
+ }
+ continue;
}
- (void) memcpy(displayhash, hash, SHA1_ASCII_LENGTH);
- displayhash[SHA1_ASCII_LENGTH] = '\0';
- if (prom_debug) {
- dboot_printf("Checking hash for module %d [%s]: ",
- i, displayhash);
+ if (strncmp(q, "type=", 5) == 0) {
+ if (q[5] == '\0' || isspace(q[5]))
+ continue;
+ q += 5;
+ if (strcmp(q, "rootfs") == 0) {
+ modules[midx].bm_type = BMT_ROOTFS;
+ } else if (strcmp(q, "hash") == 0) {
+ modules[midx].bm_type = BMT_HASH;
+ } else if (strcmp(q, "file") != 0) {
+ dboot_printf("\tmodule #%d: unknown module "
+ "type '%s'; defaulting to 'file'",
+ midx, q);
+ }
+ continue;
}
- len = mod->mod_end - mod->mod_start; /* see above */
- if (check_image_hash(hash, (void *)mod->mod_start, len) != 0) {
- dboot_panic("SHA-1 hash mismatch on %s; expected %s\n",
- (char *)mod->mod_name, displayhash);
- } else {
- DBG_MSG("OK\n");
+ if (strncmp(q, "hash=", 5) == 0) {
+ if (q[5] != '\0' && !isspace(q[5])) {
+ modules[midx].bm_hash =
+ (native_ptr_t)(uintptr_t)(q + 5);
+ }
+ continue;
+ }
+
+ dboot_printf("ignoring unknown option '%s'\n", q);
+ }
+}
+
+/*
+ * Backward compatibility: if there are exactly one or two modules, both
+ * of type 'file' and neither with an embedded hash value, we have been
+ * given the legacy style modules. In this case we need to treat the first
+ * module as a rootfs and the second as a hash referencing that module.
+ * Otherwise, even if the configuration is invalid, we assume that the
+ * operator knows what he's doing or at least isn't being bitten by this
+ * interface change.
+ */
+static void
+fixup_modules(void)
+{
+ if (modules_used == 0 || modules_used > 2)
+ return;
+
+ if (modules[0].bm_type != BMT_FILE ||
+ modules_used > 1 && modules[1].bm_type != BMT_FILE) {
+ return;
+ }
+
+ if (modules[0].bm_hash != NULL ||
+ modules_used > 1 && modules[1].bm_hash != NULL) {
+ return;
+ }
+
+ modules[0].bm_type = BMT_ROOTFS;
+ if (modules_used > 1) {
+ modules[1].bm_type = BMT_HASH;
+ modules[1].bm_name = modules[0].bm_name;
+ }
+}
+
+/*
+ * For modules that do not have assigned hashes but have a separate hash module,
+ * find the assigned hash module and set the primary module's bm_hash to point
+ * to the hash data from that module. We will then ignore modules of type
+ * BMT_HASH from this point forward.
+ */
+static void
+assign_module_hashes(void)
+{
+ uint_t i, j;
+
+ for (i = 0; i < modules_used; i++) {
+ if (modules[i].bm_type == BMT_HASH ||
+ modules[i].bm_hash != NULL) {
+ continue;
+ }
+
+ for (j = 0; j < modules_used; j++) {
+ if (modules[j].bm_type != BMT_HASH ||
+ strcmp((char *)(uintptr_t)modules[j].bm_name,
+ (char *)(uintptr_t)modules[i].bm_name) != 0) {
+ continue;
+ }
+
+ if (modules[j].bm_size < SHA1_ASCII_LENGTH) {
+ dboot_printf("Short hash module of length "
+ "0x%lx bytes; ignoring\n",
+ (ulong_t)modules[j].bm_size);
+ } else {
+ modules[i].bm_hash = modules[j].bm_addr;
+ }
+ break;
}
- hash += SHA1_ASCII_LENGTH + 1;
}
}
@@ -927,9 +1087,9 @@ init_mem_alloc(void)
DBG_MSG("Entered init_mem_alloc()\n");
DBG((uintptr_t)mb_info);
- if (mb_info->mods_count > MAX_MODULES) {
+ if (mb_info->mods_count > MAX_BOOT_MODULES) {
dboot_panic("Too many modules (%d) -- the maximum is %d.",
- mb_info->mods_count, MAX_MODULES);
+ mb_info->mods_count, MAX_BOOT_MODULES);
}
/*
* search the modules to find the last used address
@@ -940,18 +1100,7 @@ init_mem_alloc(void)
for (mod = (mb_module_t *)(mb_info->mods_addr), i = 0;
i < mb_info->mods_count;
++mod, ++i) {
- if (prom_debug) {
- dboot_printf("\tmodule #%d: %s at: 0x%lx, end 0x%lx\n",
- i, (char *)(mod->mod_name),
- (ulong_t)mod->mod_start, (ulong_t)mod->mod_end);
- }
- modules[i].bm_addr = mod->mod_start;
- if (mod->mod_start > mod->mod_end) {
- dboot_panic("module[%d]: Invalid module start address "
- "(0x%llx)", i, (uint64_t)mod->mod_start);
- }
- modules[i].bm_size = mod->mod_end - mod->mod_start;
-
+ process_module(mod);
check_higher(mod->mod_end);
}
bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
@@ -959,6 +1108,8 @@ init_mem_alloc(void)
bi->bi_module_cnt = mb_info->mods_count;
DBG(bi->bi_module_cnt);
+ fixup_modules();
+ assign_module_hashes();
check_images();
/*
diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c
index d38bcb046f..50690ae67d 100644
--- a/usr/src/uts/i86pc/os/fakebop.c
+++ b/usr/src/uts/i86pc/os/fakebop.c
@@ -22,10 +22,11 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- */
-/*
+ *
* Copyright (c) 2010, Intel Corporation.
* All rights reserved.
+ *
+ * Copyright 2013 Joyent, Inc. All rights reserved.
*/
/*
@@ -66,6 +67,7 @@
#include <sys/kobj.h>
#include <sys/kobj_lex.h>
#include <sys/pci_cfgspace_impl.h>
+#include <sys/fastboot_impl.h>
#include "acpi_fw.h"
static int have_console = 0; /* set once primitive console is initialized */
@@ -664,7 +666,7 @@ boot_prop_finish(void)
}
done:
if (fd >= 0)
- BRD_CLOSE(bfs_ops, fd);
+ (void) BRD_CLOSE(bfs_ops, fd);
/*
* Check if we have to limit the boot time allocator
@@ -1164,10 +1166,12 @@ build_boot_properties(void)
int name_len;
char *value;
int value_len;
- struct boot_modules *bm;
+ struct boot_modules *bm, *rdbm;
char *propbuf;
int quoted = 0;
int boot_arg_len;
+ uint_t i, midx;
+ char modid[32];
#ifndef __xpv
static int stdout_val = 0;
uchar_t boot_device;
@@ -1185,9 +1189,40 @@ build_boot_properties(void)
DBG((uintptr_t)propbuf);
if (xbootp->bi_module_cnt > 0) {
bm = xbootp->bi_modules;
- bsetprop64("ramdisk_start", (uint64_t)(uintptr_t)bm->bm_addr);
- bsetprop64("ramdisk_end", (uint64_t)(uintptr_t)bm->bm_addr +
- bm->bm_size);
+ rdbm = NULL;
+ for (midx = i = 0; i < xbootp->bi_module_cnt; i++) {
+ if (bm[i].bm_type == BMT_ROOTFS) {
+ rdbm = &bm[i];
+ continue;
+ }
+ if (bm[i].bm_type == BMT_HASH || bm[i].bm_name == NULL)
+ continue;
+
+ (void) snprintf(modid, sizeof (modid),
+ "module-name-%u", midx);
+ bsetprops(modid, (char *)bm[i].bm_name);
+ (void) snprintf(modid, sizeof (modid),
+ "module-addr-%u", midx);
+ bsetprop64(modid, (uint64_t)(uintptr_t)bm[i].bm_addr);
+ (void) snprintf(modid, sizeof (modid),
+ "module-size-%u", midx);
+ bsetprop64(modid, (uint64_t)bm[i].bm_size);
+ ++midx;
+ }
+ if (rdbm != NULL) {
+ bsetprop64("ramdisk_start",
+ (uint64_t)(uintptr_t)rdbm->bm_addr);
+ bsetprop64("ramdisk_end",
+ (uint64_t)(uintptr_t)rdbm->bm_addr + rdbm->bm_size);
+ }
+ }
+
+ /*
+ * If there are any boot time modules or hashes present, then disable
+ * fast reboot.
+ */
+ if (xbootp->bi_module_cnt > 1) {
+ fastreboot_disable(FBNS_BOOTMOD);
}
DBG_MSG("Parsing command line for boot properties\n");
diff --git a/usr/src/uts/i86pc/os/mlsetup.c b/usr/src/uts/i86pc/os/mlsetup.c
index 0fd3ec3dfb..8cb56d9682 100644
--- a/usr/src/uts/i86pc/os/mlsetup.c
+++ b/usr/src/uts/i86pc/os/mlsetup.c
@@ -60,6 +60,7 @@
#include <sys/archsystm.h>
#include <sys/promif.h>
#include <sys/pci_cfgspace.h>
+#include <sys/bootvfs.h>
#ifdef __xpv
#include <sys/hypervisor.h>
#else
@@ -479,6 +480,10 @@ mach_modpath(char *path, const char *filename)
const char isastr[] = "/amd64";
size_t isalen = strlen(isastr);
+ len = strlen(SYSTEM_BOOT_PATH "/kernel");
+ (void) strcpy(path, SYSTEM_BOOT_PATH "/kernel ");
+ path += len + 1;
+
if ((p = strrchr(filename, '/')) == NULL)
return;
diff --git a/usr/src/uts/i86pc/os/startup.c b/usr/src/uts/i86pc/os/startup.c
index 277614b536..700b3456ae 100644
--- a/usr/src/uts/i86pc/os/startup.c
+++ b/usr/src/uts/i86pc/os/startup.c
@@ -22,6 +22,7 @@
* Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2013 Joyent, Inc. All rights reserved.
*/
/*
* Copyright (c) 2010, Intel Corporation.
@@ -121,6 +122,7 @@
#include <sys/ddi_periodic.h>
#include <sys/systeminfo.h>
#include <sys/multiboot.h>
+#include <sys/ramdisk.h>
#ifdef __xpv
@@ -2348,6 +2350,20 @@ pp_in_range(page_t *pp, uint64_t low_addr, uint64_t high_addr)
(pp->p_pagenum < btopr(high_addr)));
}
+static int
+pp_in_module(page_t *pp, const rd_existing_t *modranges)
+{
+ uint_t i;
+
+ for (i = 0; modranges[i].phys != 0; i++) {
+ if (pp_in_range(pp, modranges[i].phys,
+ modranges[i].phys + modranges[i].size))
+ return (1);
+ }
+
+ return (0);
+}
+
void
release_bootstrap(void)
{
@@ -2355,10 +2371,40 @@ release_bootstrap(void)
page_t *pp;
extern void kobj_boot_unmountroot(void);
extern dev_t rootdev;
+ uint_t i;
+ char propname[32];
+ rd_existing_t *modranges;
#if !defined(__xpv)
pfn_t pfn;
#endif
+ /*
+ * Save the bootfs module ranges so that we can reserve them below
+ * for the real bootfs.
+ */
+ modranges = kmem_alloc(sizeof (rd_existing_t) * MAX_BOOT_MODULES,
+ KM_SLEEP);
+ for (i = 0; ; i++) {
+ uint64_t start, size;
+
+ modranges[i].phys = 0;
+
+ (void) snprintf(propname, sizeof (propname),
+ "module-addr-%u", i);
+ if (do_bsys_getproplen(NULL, propname) <= 0)
+ break;
+ (void) do_bsys_getprop(NULL, propname, &start);
+
+ (void) snprintf(propname, sizeof (propname),
+ "module-size-%u", i);
+ if (do_bsys_getproplen(NULL, propname) <= 0)
+ break;
+ (void) do_bsys_getprop(NULL, propname, &size);
+
+ modranges[i].phys = start;
+ modranges[i].size = size;
+ }
+
/* unmount boot ramdisk and release kmem usage */
kobj_boot_unmountroot();
@@ -2399,9 +2445,8 @@ release_bootstrap(void)
continue;
}
-
if (root_is_ramdisk && pp_in_range(pp, ramdisk_start,
- ramdisk_end)) {
+ ramdisk_end) || pp_in_module(pp, modranges)) {
pp->p_next = rd_pages;
rd_pages = pp;
continue;
@@ -2413,6 +2458,8 @@ release_bootstrap(void)
}
PRM_POINT("Boot pages released");
+ kmem_free(modranges, sizeof (rd_existing_t) * 99);
+
#if !defined(__xpv)
/* XXPV -- note this following bunch of code needs to be revisited in Xen 3.0 */
/*
diff --git a/usr/src/uts/i86pc/sys/fastboot_msg.h b/usr/src/uts/i86pc/sys/fastboot_msg.h
index 4c7ee7f8b5..9a1c9bd878 100644
--- a/usr/src/uts/i86pc/sys/fastboot_msg.h
+++ b/usr/src/uts/i86pc/sys/fastboot_msg.h
@@ -46,6 +46,7 @@ fastboot_nosup_msg(FBNS_DEFAULT, "")
fastboot_nosup_msg(FBNS_SUSPEND, " after suspend/resume")
fastboot_nosup_msg(FBNS_FMAHWERR, " due to FMA recovery from hardware error")
fastboot_nosup_msg(FBNS_HOTPLUG, " after DR operations")
+fastboot_nosup_msg(FBNS_BOOTMOD, " due to presence of boot-time modules")
/*
* Should ALWAYS be the last one.
diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files
index 01147a5314..b1f80b2409 100644
--- a/usr/src/uts/intel/Makefile.files
+++ b/usr/src/uts/intel/Makefile.files
@@ -21,7 +21,7 @@
#
# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+# Copyright (c) 2013, Joyent, Inc. All rights reserved.
#
#
@@ -167,6 +167,7 @@ VGATEXT_OBJS += vgatext.o vgasubr.o
# Kernel linker
#
KRTLD_OBJS += \
+ bootfsops.o \
bootrd.o \
ufsops.o \
hsfs.o \
diff --git a/usr/src/uts/intel/sys/bootinfo.h b/usr/src/uts/intel/sys/bootinfo.h
index 08ff9c3ca0..3adce64fc4 100644
--- a/usr/src/uts/intel/sys/bootinfo.h
+++ b/usr/src/uts/intel/sys/bootinfo.h
@@ -32,6 +32,13 @@ extern "C" {
#endif
/*
+ * This is used by bootfs and dboot. It should be at least as large as the
+ * number of modules that bootloaders (e.g., grub) can support. This figure
+ * has been chosen to match grub's value exactly.
+ */
+#define MAX_BOOT_MODULES 99
+
+/*
* The 32-bit kernel loader code needs to build several structures that the
* kernel is expecting. They will contain native sized pointers for the
* target kernel.
@@ -51,6 +58,12 @@ typedef void *native_ptr_t;
#endif
+typedef enum boot_module_type {
+ BMT_ROOTFS,
+ BMT_FILE,
+ BMT_HASH
+} boot_module_type_t;
+
struct boot_memlist {
uint64_t addr;
uint64_t size;
@@ -62,9 +75,11 @@ struct boot_memlist {
* The kernel needs to know how to find its modules.
*/
struct boot_modules {
- native_ptr_t bm_addr;
- uint32_t bm_size;
- uint32_t bm_padding;
+ native_ptr_t bm_addr;
+ native_ptr_t bm_name;
+ native_ptr_t bm_hash;
+ uint32_t bm_size;
+ boot_module_type_t bm_type;
};
/*
diff --git a/usr/src/uts/intel/sys/bootvfs.h b/usr/src/uts/intel/sys/bootvfs.h
index 63696395da..5120a6733e 100644
--- a/usr/src/uts/intel/sys/bootvfs.h
+++ b/usr/src/uts/intel/sys/bootvfs.h
@@ -26,8 +26,6 @@
#ifndef _SYS_BOOTVFS_H
#define _SYS_BOOTVFS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -69,6 +67,18 @@ struct boot_fs_ops {
extern struct boot_fs_ops *bfs_ops;
+#ifdef _KERNEL
+
+extern int BRD_MOUNTROOT(struct boot_fs_ops *, char *);
+extern int BRD_UNMOUNTROOT(struct boot_fs_ops *);
+extern int BRD_OPEN(struct boot_fs_ops *, char *, int);
+extern int BRD_CLOSE(struct boot_fs_ops *, int);
+extern ssize_t BRD_READ(struct boot_fs_ops *, int, caddr_t, size_t);
+extern off_t BRD_SEEK(struct boot_fs_ops *, int, off_t, int);
+extern int BRD_FSTAT(struct boot_fs_ops *, int, struct bootstat *);
+
+#else
+
#define BRD_MOUNTROOT(ops, str) ((ops)->fsw_mountroot)(str)
#define BRD_UNMOUNTROOT(ops) ((ops)->fsw_unmountroot)()
#define BRD_OPEN(ops, file, flag) ((ops)->fsw_open)(file, flag)
@@ -77,6 +87,11 @@ extern struct boot_fs_ops *bfs_ops;
#define BRD_SEEK(ops, fd, addr, w) ((ops)->fsw_lseek)(fd, addr, w)
#define BRD_FSTAT(ops, fd, stp) ((ops)->fsw_fstat)(fd, stp)
+#endif
+
+#define SYSTEM_BOOT_PATH "/system/boot"
+#define BFD_F_SYSTEM_BOOT 0x40000000
+
#ifdef _BOOT
extern int mountroot(char *str);