Page MenuHomeFreeBSD

D16945.id47472.diff
No OneTemporary

D16945.id47472.diff

Index: stand/userboot/Makefile
===================================================================
--- stand/userboot/Makefile
+++ stand/userboot/Makefile
@@ -1,8 +1,10 @@
# $FreeBSD$
-.include <bsd.own.mk>
+.include <bsd.init.mk>
-SUBDIR= test userboot
+SUBDIR.yes= test
+SUBDIR.${MK_FORTH}+= userboot_4th
+SUBDIR.${MK_LOADER_LUA}+= userboot_lua
.include <bsd.subdir.mk>
Index: stand/userboot/userboot.h
===================================================================
--- stand/userboot/userboot.h
+++ stand/userboot/userboot.h
@@ -41,6 +41,13 @@
*/
#define USERBOOT_VERSION_4 4
+/*
+ * Version 5 added a callback for indicating that the guest
+ * should be restarted with a different interpreter. The callback
+ * structure is still backward compatible.
+ */
+#define USERBOOT_VERSION_5 5
+
/*
* Exit codes from the loader
*/
@@ -210,4 +217,9 @@
int (*vm_set_register)(void *arg, int vcpu, int reg, uint64_t val);
int (*vm_set_desc)(void *arg, int vcpu, int reg, uint64_t base,
u_int limit, u_int access);
+
+ /*
+ * Version 5 addition.
+ */
+ void (*swap_interpreter)(void *arg, const char *interp);
};
Index: stand/userboot/userboot/Makefile
===================================================================
--- stand/userboot/userboot/Makefile
+++ stand/userboot/userboot/Makefile
@@ -5,14 +5,14 @@
LOADER_CD9660_SUPPORT?= no
LOADER_EXT2FS_SUPPORT?= no
PIC=yes
-LOADER_INTERP=4th
.include <bsd.init.mk>
-SHLIB_NAME= userboot.so
+SHLIB_NAME= userboot_${LOADER_INTERP}.so
STRIP=
LIBDIR= /boot
+.PATH: ${.CURDIR}/../userboot
SRCS= autoload.c
SRCS+= bcache.c
SRCS+= biossmap.c
@@ -38,7 +38,12 @@
LDFLAGS+= -nostdlib -Wl,-Bsymbolic
-NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH}
+NEWVERSWHAT= "User boot ${LOADER_INTERP}" ${MACHINE_CPUARCH}
+VERSION_FILE= ${.CURDIR}/../userboot/version
+
+.if ${LOADER_INTERP} == ${LOADER_DEFAULT_INTERP}
+LINKS+= ${BINDIR}/${SHLIB_NAME} ${BINDIR}/userboot.so
+.endif
.if ${MK_ZFS} != "no"
CFLAGS+= -DUSERBOOT_ZFS_SUPPORT
Index: stand/userboot/userboot/main.c
===================================================================
--- stand/userboot/userboot/main.c
+++ stand/userboot/userboot/main.c
@@ -47,6 +47,9 @@
/* Minimum version required */
#define USERBOOT_VERSION USERBOOT_VERSION_3
+#define USERBOOT_PATH "/boot/userboot.so"
+#define USERBOOT_VER_SEARCH "User boot "
+
#define MALLOCSZ (64*1024*1024)
struct loader_callbacks *callbacks;
@@ -57,6 +60,7 @@
struct arch_switch archsw; /* MI/MD interface boundary */
static void extract_currdev(void);
+static void check_interpreter(void);
void
delay(int usec)
@@ -73,6 +77,121 @@
longjmp(jb, 1);
}
+static char *
+grab_str(char *haystack, const char *needle, size_t haystacksz, size_t *rem)
+{
+ size_t nlen;
+ char c, sc;
+
+ c = *needle++;
+ nlen = strlen(needle);
+ do {
+ do {
+ if (haystacksz-- < 1)
+ return (NULL);
+ sc = *haystack++;
+ } while (sc != c);
+ if (nlen > haystacksz)
+ return (NULL);
+ } while (strncmp(haystack, needle, nlen) != 0);
+ haystack--;
+ *rem = ++haystacksz;
+ return (haystack);
+}
+
+/*
+ * Grab the interpreter string from a buffer. The input buffer will be
+ * modified in place...
+ */
+static char *
+grab_interpreter_string(char *haystack, size_t haystacksz)
+{
+ char *verstr, *trailer;
+ size_t searchsz, szleft;
+
+ searchsz = strlen(USERBOOT_VER_SEARCH);
+ szleft = haystacksz;
+ verstr = NULL;
+ /*
+ * Here we have a problem. If we had dlopen, this would be trivial...
+ * We need to grab the version string from the target, so we search for
+ * the start of it. In embedding the string we're searching for, we've
+ * added an additional instance of the string we're searching for, so
+ * we'll need to loop until we find the right one. Here we call the
+ * right one "one with a trailing comma".
+ */
+ while (verstr == NULL) {
+ verstr = grab_str(haystack, USERBOOT_VER_SEARCH, szleft, &szleft);
+ if (verstr == NULL)
+ return (NULL);
+
+ verstr += searchsz;
+ /* Comma immediately follows the interpreter */
+ trailer = strchr(verstr, ',');
+ if (trailer == NULL) {
+ /* Try again, for a later attempt. */
+ haystack = verstr;
+ szleft -= searchsz;
+ verstr = NULL;
+ continue;
+ }
+ }
+
+ *trailer = '\0';
+ return (verstr);
+}
+
+static void
+check_interpreter(void)
+{
+ struct stat st;
+ size_t rdsize;
+ char *buf, *guest_interp, *my_interp, *verstring;
+ int fd;
+
+ /*
+ * If we can't stat(2) or open(2) USERBOOT_PATH, then we'll fail by
+ * simply letting us roll on with whatever interpreter we were compiled
+ * with. This is likely not going to be an issue in reality.
+ */
+ buf = verstring = NULL;
+ if (stat(USERBOOT_PATH, &st) != 0)
+ return;
+ if ((fd = open(USERBOOT_PATH, O_RDONLY)) < 0)
+ return;
+
+ rdsize = st.st_size;
+ buf = malloc(rdsize);
+ if (buf == NULL)
+ goto out;
+ if (read(fd, buf, rdsize) < rdsize)
+ goto out;
+
+ verstring = strdup(bootprog_info);
+ if (verstring == NULL)
+ goto out;
+ my_interp = grab_interpreter_string(verstring, strlen(verstring));
+ guest_interp = grab_interpreter_string(buf, rdsize);
+ /*
+ * The guest interpreter may not have a version of userboot that
+ * specifies the interpreter installed. If that's the case, we'll
+ * assume it's legacy (4th) and request a swap to that if we're
+ * a Lua-userboot.
+ */
+ if (guest_interp == NULL && strcmp(my_interp, "lua") == 0)
+ CALLBACK(swap_interpreter, "4th");
+ else if (guest_interp == NULL)
+ /* We're already right; guest is likely 4th, and we're 4th */
+ goto out;
+ else if (strcmp(my_interp, guest_interp) != 0)
+ CALLBACK(swap_interpreter, guest_interp);
+out:
+ free(verstring);
+ free(buf);
+ close(fd);
+ return;
+}
+
void
loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
{
@@ -137,6 +256,13 @@
(devsw[i]->dv_init)();
extract_currdev();
+ /*
+ * Checking the interpreter isn't worth the overhead unless we
+ * actually have the swap_interpreter callback, so we actually version
+ * check here rather than later on.
+ */
+ if (version >= USERBOOT_VERSION_5)
+ check_interpreter();
if (setjmp(jb))
return;
Index: stand/userboot/userboot/version
===================================================================
--- stand/userboot/userboot/version
+++ stand/userboot/userboot/version
@@ -1,4 +1,5 @@
$FreeBSD$
+1.2: Userboot with lua or forth
1.1: Initial userland boot
Index: stand/userboot/userboot_4th/Makefile
===================================================================
--- /dev/null
+++ stand/userboot/userboot_4th/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+LOADER_INTERP=4th
+
+.include "../userboot/Makefile"
+
Index: stand/userboot/userboot_lua/Makefile
===================================================================
--- /dev/null
+++ stand/userboot/userboot_lua/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+LOADER_INTERP=lua
+
+.include "../userboot/Makefile"
+
Index: usr.sbin/bhyveload/bhyveload.c
===================================================================
--- usr.sbin/bhyveload/bhyveload.c
+++ usr.sbin/bhyveload/bhyveload.c
@@ -86,6 +86,8 @@
#include "userboot.h"
+#define LOADER_MAXNAMELEN 32
+
#define MB (1024 * 1024UL)
#define GB (1024 * 1024 * 1024UL)
#define BSP 0
@@ -97,6 +99,11 @@
static int disk_fd[NDISKS];
static int ndisks;
static int consin_fd, consout_fd;
+static struct loader_callbacks cb;
+
+static void *loader_hdl;
+void (*loader_func)(struct loader_callbacks *, void *, int, int);
+static int explicit_loader;
static char *vmname, *progname;
static struct vmctx *ctx;
@@ -104,6 +111,8 @@
static uint64_t gdtbase, cr3, rsp;
static void cb_exit(void *arg, int v);
+static int setup_loader(const char *interp);
+static int fetch_loader_func(const char *loader);
/*
* Console i/o callbacks
@@ -560,6 +569,34 @@
return (vm_set_desc(ctx, vcpu, reg, base, limit, access));
}
+static void
+cb_swap_interpreter(void *arg, const char *requested_interp)
+{
+
+ /*
+ * If the user specified a loader but we detected a mismatch, we should
+ * not try to pivot to a different loader on them.
+ */
+ if (explicit_loader == 1) {
+ perror("requested loader interpreter does not match guest userboot");
+ cb_exit(NULL, 1);
+ }
+
+ if (requested_interp == NULL || *requested_interp == '\0') {
+ perror("guest failed to request an interpreter");
+ cb_exit(NULL, 1);
+ }
+
+ if (setup_loader(requested_interp) != 0)
+ cb_exit(NULL, 1);
+ loader_func(&cb, NULL, USERBOOT_VERSION_5, ndisks);
+ /*
+ * Never return; that will break things, since we've swapped out the
+ * caller out from under ourselves.
+ */
+ cb_exit(NULL, 1);
+}
+
static struct loader_callbacks cb = {
.getc = cb_getc,
.putc = cb_putc,
@@ -593,6 +630,9 @@
/* Version 4 additions */
.vm_set_register = cb_vm_set_register,
.vm_set_desc = cb_vm_set_desc,
+
+ /* Version 5 additions */
+ .swap_interpreter = cb_swap_interpreter,
};
static int
@@ -658,19 +698,65 @@
exit(1);
}
+static int
+setup_loader(const char *interp)
+{
+ char *loader;
+ int ret;
+
+ if (interp == NULL) {
+ loader = strdup("/boot/userboot.so");
+ if (loader == NULL)
+ err(EX_OSERR, "malloc");
+ } else {
+ loader = malloc(LOADER_MAXNAMELEN);
+ if (loader == NULL)
+ err(EX_OSERR, "malloc");
+ snprintf(loader, LOADER_MAXNAMELEN, "/boot/userboot_%s.so",
+ interp);
+ /*
+ * We've not pivoted to a loader that has been requested
+ * explicitly, though by the guest this time.
+ */
+ explicit_loader = 1;
+ }
+
+ ret = fetch_loader_func(loader);
+ free(loader);
+ return (ret);
+}
+
+static int
+fetch_loader_func(const char *loader)
+{
+
+ if (loader_hdl != NULL)
+ dlclose(loader_hdl);
+
+ loader_hdl = dlopen(loader, RTLD_LOCAL);
+ if (!loader_hdl) {
+ printf("%s\n", dlerror());
+ return (1);
+ }
+
+ loader_func = dlsym(loader_hdl, "loader_main");
+ if (!loader_func) {
+ printf("%s\n", dlerror());
+ return (1);
+ }
+ return (0);
+}
+
int
main(int argc, char** argv)
{
- char *loader;
- void *h;
- void (*func)(struct loader_callbacks *, void *, int, int);
uint64_t mem_size;
+ char *loader;
int opt, error, need_reinit, memflags;
progname = basename(argv[0]);
loader = NULL;
-
memflags = 0;
mem_size = 256 * MB;
@@ -705,6 +791,7 @@
loader = strdup(optarg);
if (loader == NULL)
err(EX_OSERR, "malloc");
+ explicit_loader = 1;
break;
case 'm':
@@ -762,23 +849,11 @@
exit(1);
}
- if (loader == NULL) {
- loader = strdup("/boot/userboot.so");
- if (loader == NULL)
- err(EX_OSERR, "malloc");
- }
- h = dlopen(loader, RTLD_LOCAL);
- if (!h) {
- printf("%s\n", dlerror());
- free(loader);
- return (1);
- }
- func = dlsym(h, "loader_main");
- if (!func) {
- printf("%s\n", dlerror());
- free(loader);
- return (1);
- }
+ if (explicit_loader == 0 && setup_loader(NULL) != 0)
+ exit(1);
+ else if (explicit_loader == 1 && fetch_loader_func(loader) != 0)
+ exit(1);
+ free(loader);
tcgetattr(consout_fd, &term);
oldterm = term;
@@ -790,8 +865,7 @@
addenv("smbios.bios.vendor=BHYVE");
addenv("boot_serial=1");
- func(&cb, NULL, USERBOOT_VERSION_4, ndisks);
+ loader_func(&cb, NULL, USERBOOT_VERSION_5, ndisks);
- free(loader);
return (0);
}

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 19, 8:40 AM (4 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27737850
Default Alt Text
D16945.id47472.diff (10 KB)

Event Timeline