summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/arch/powerpc64/stand/Makefile7
-rw-r--r--sys/arch/powerpc64/stand/Makefile.inc44
-rw-r--r--sys/arch/powerpc64/stand/boot/Makefile39
-rw-r--r--sys/arch/powerpc64/stand/rdboot/Makefile19
-rw-r--r--sys/arch/powerpc64/stand/rdboot/cmd.c507
-rw-r--r--sys/arch/powerpc64/stand/rdboot/cmd.h65
-rw-r--r--sys/arch/powerpc64/stand/rdboot/disk.c208
-rw-r--r--sys/arch/powerpc64/stand/rdboot/disk.h21
-rw-r--r--sys/arch/powerpc64/stand/rdboot/rdboot.c245
-rw-r--r--sys/arch/powerpc64/stand/rdboot/vars.c203
10 files changed, 1354 insertions, 4 deletions
diff --git a/sys/arch/powerpc64/stand/Makefile b/sys/arch/powerpc64/stand/Makefile
index dfe244d4df3..2b496e0cf37 100644
--- a/sys/arch/powerpc64/stand/Makefile
+++ b/sys/arch/powerpc64/stand/Makefile
@@ -1,6 +1,5 @@
-# dummy
-all:
+# $OpenBSD: Makefile,v 1.2 2020/07/16 19:48:58 kettenis Exp $
-clean:
+SUBDIR+= rdboot boot
-includes:
+.include <bsd.subdir.mk>
diff --git a/sys/arch/powerpc64/stand/Makefile.inc b/sys/arch/powerpc64/stand/Makefile.inc
new file mode 100644
index 00000000000..5f00292123a
--- /dev/null
+++ b/sys/arch/powerpc64/stand/Makefile.inc
@@ -0,0 +1,44 @@
+# $OpenBSD: Makefile.inc,v 1.1 2020/07/16 19:48:58 kettenis Exp $
+
+BINDIR= /usr/mdec
+
+STANDALONE?= -D_STANDALONE
+
+.if ${MACHINE} == "powerpc64"
+CPPFLAGS+= ${STANDALONE}
+CPPFLAGS+= -I.
+CFLAGS+= -fno-stack-protector -Wall
+CFLAGS+= -fno-builtin-vprintf -fno-builtin-printf -fno-builtin-putchar
+# Silence warnings
+CFLAGS+= -fno-builtin-snprintf
+CFLAGS+= -fno-builtin-memcpy
+CFLAGS+= -fno-builtin-memcmp
+CFLAGS+= -fno-builtin-memset
+CFLAGS+= -fno-builtin-strncpy
+CFLAGS+= -fno-builtin-strncmp
+CFLAGS+= -fno-builtin-exit
+AS?= as
+LD?= ld
+.endif
+
+### Figure out what to use for libsa
+LIBSADIR?= ${.CURDIR}/../libsa
+
+.if exists(${LIBSADIR}/${__objdir})
+LIBSAOBJDIR= ${LIBSADIR}/${__objdir}
+.else
+LIBSAOBJDIR= ${LIBSADIR}
+.endif
+
+LIBSA= ${LIBSAOBJDIR}/libsa.a
+
+### Figure out what to use for libz
+LIBZDIR?= ${.CURDIR}/../libz
+
+.if exists(${LIBZDIR}/${__objdir})
+LIBZOBJDIR= ${LIBZDIR}/${__objdir}
+.else
+LIBZOBJDIR= ${LIBZDIR}
+.endif
+
+LIBZ= ${LIBZOBJDIR}/libz.a
diff --git a/sys/arch/powerpc64/stand/boot/Makefile b/sys/arch/powerpc64/stand/boot/Makefile
new file mode 100644
index 00000000000..0919efd524f
--- /dev/null
+++ b/sys/arch/powerpc64/stand/boot/Makefile
@@ -0,0 +1,39 @@
+# $OpenBSD: Makefile,v 1.1 2020/07/16 19:48:58 kettenis Exp $
+
+NOMAN=
+#MAN= boot.8
+
+.if ${MACHINE} == "powerpc64"
+all: bsd rdboot
+
+bsd:
+ cd ${.CURDIR}/../../compile/BOOT && \
+ ${MAKE} config && ${MAKE} clean && ${MAKE}
+ cp -p ${.CURDIR}/../../compile/BOOT/obj/bsd bsd
+
+rdboot:
+ cp -p ${.CURDIR}/../rdboot/obj/rdboot rdboot
+ strip rdboot
+
+mr.fs: rdboot
+ rm -rf $@.d
+ install -d -o root -g wheel $@.d/dev
+ install -d -o root -g wheel $@.d/mnt
+ install -d -o root -g wheel $@.d/sbin
+ install -o ${BINOWN} -g ${BINGRP} -m 555 rdboot $@.d/sbin/init
+ cd $@.d/dev && sh ${DESTDIR}/dev/MAKEDEV boot
+ makefs -o disklabel=rdboot,minfree=0,density=1024 $@ $@.d
+
+boot: bsd mr.fs
+ cp bsd boot
+ rdsetroot boot mr.fs
+
+realinstall: boot
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 boot ${DESTDIR}/usr/mdec
+
+clean:
+ rm -f boot bsd mr.fs rdboot
+ rm -rf mr.fs.d
+.endif
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/powerpc64/stand/rdboot/Makefile b/sys/arch/powerpc64/stand/rdboot/Makefile
new file mode 100644
index 00000000000..b99ed3689d6
--- /dev/null
+++ b/sys/arch/powerpc64/stand/rdboot/Makefile
@@ -0,0 +1,19 @@
+# $OpenBSD: Makefile,v 1.1 2020/07/16 19:48:58 kettenis Exp $
+
+NOMAN=
+
+.if ${MACHINE} == "powerpc64"
+PROG= rdboot
+SRCS= cmd.c disk.c rdboot.c vars.c
+LDADD+= -lutil
+LDSTATIC+= -static
+.else
+NOPROG=
+.endif
+
+.PATH: ${S}/lib/libsa
+#SRCS+= hexdump.c strtoll.c
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/powerpc64/stand/rdboot/cmd.c b/sys/arch/powerpc64/stand/rdboot/cmd.c
new file mode 100644
index 00000000000..ed93604aae1
--- /dev/null
+++ b/sys/arch/powerpc64/stand/rdboot/cmd.c
@@ -0,0 +1,507 @@
+/* $OpenBSD: cmd.c,v 1.1 2020/07/16 19:48:58 kettenis Exp $ */
+
+/*
+ * Copyright (c) 1997-1999 Michael Shalayeff
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "cmd.h"
+#include "disk.h"
+
+static int Xboot(void);
+static int Xecho(void);
+static int Xhelp(void);
+static int Xls(void);
+static int Xnop(void);
+static int Xreboot(void);
+#ifdef MACHINE_CMD
+static int Xmachine(void);
+extern const struct cmd_table MACHINE_CMD[];
+#endif
+extern int Xset(void);
+
+#ifdef CHECK_SKIP_CONF
+extern int CHECK_SKIP_CONF(void);
+#endif
+
+extern const struct cmd_table cmd_set[];
+const struct cmd_table cmd_table[] = {
+ {"#", CMDT_CMD, Xnop}, /* XXX must be first */
+ {"boot", CMDT_CMD, Xboot},
+ {"echo", CMDT_CMD, Xecho},
+ {"help", CMDT_CMD, Xhelp},
+ {"ls", CMDT_CMD, Xls},
+#ifdef MACHINE_CMD
+ {"machine",CMDT_MDC, Xmachine},
+#endif
+ {"reboot", CMDT_CMD, Xreboot},
+ {"set", CMDT_SET, Xset},
+ {NULL, 0},
+};
+
+static void ls(const char *, struct stat *);
+static int readline(char *, size_t, int);
+char *nextword(char *);
+static char *whatcmd(const struct cmd_table **ct, char *);
+static char *qualify(char *);
+
+char cmd_buf[CMD_BUFF_SIZE];
+
+int
+getcmd(void)
+{
+ cmd.cmd = NULL;
+
+ if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout))
+ cmd.cmd = cmd_table;
+
+ return docmd();
+}
+
+int
+read_conf(void)
+{
+ struct stat sb;
+ const char *path;
+ int fd, rc = 0;
+
+#ifdef CHECK_SKIP_CONF
+ if (CHECK_SKIP_CONF()) {
+ printf("boot.conf processing skipped at operator request\n");
+ cmd.timeout = 0;
+ return -1; /* Pretend file wasn't found */
+ }
+#endif
+
+ path = disk_open(qualify(cmd.conf));
+ if (path == NULL) {
+ fprintf(stderr, "cannot open device for reading %s: %s\n",
+ cmd.conf, strerror(errno));
+ return -1;
+ }
+ if ((fd = open(path, O_RDONLY)) == -1) {
+ if (errno != ENOENT && errno != ENXIO) {
+ fprintf(stderr, "%s: open(%s): %s\n", __func__,
+ cmd.path, strerror(errno));
+ rc = 0;
+ } else
+ rc = -1;
+ goto out;
+ }
+
+ (void) fstat(fd, &sb);
+ if (sb.st_uid || (sb.st_mode & 2)) {
+ fprintf(stderr, "non-secure %s, will not proceed\n", cmd.path);
+ rc = -1;
+ goto out;
+ }
+
+ do {
+ char *p = cmd_buf;
+
+ cmd.cmd = NULL;
+ do {
+ rc = read(fd, p, 1);
+ } while (rc > 0 && *p++ != '\n' &&
+ (p-cmd_buf) < sizeof(cmd_buf));
+
+ if (rc < 0) { /* Error from read() */
+ fprintf(stderr, "%s: %s\n", cmd.path, strerror(errno));
+ break;
+ }
+
+ if (rc == 0) { /* eof from read() */
+ if (p != cmd_buf) { /* Line w/o trailing \n */
+ *p = '\0';
+ rc = docmd();
+ break;
+ }
+ } else { /* rc > 0, read a char */
+ p--; /* Get back to last character */
+
+ if (*p != '\n') { /* Line was too long */
+ fprintf(stderr, "%s: line too long\n",
+ cmd.path);
+
+ /* Don't want to run the truncated command */
+ rc = -1;
+ }
+ *p = '\0';
+ }
+ } while (rc > 0 && !(rc = docmd()));
+
+out:
+ if (fd != -1)
+ close(fd);
+ disk_close();
+ return rc;
+}
+
+int
+docmd(void)
+{
+ char *p = NULL;
+ const struct cmd_table *ct = cmd_table, *cs;
+
+ cmd.argc = 1;
+ if (cmd.cmd == NULL) {
+
+ /* command */
+ for (p = cmd_buf; *p == ' ' || *p == '\t'; p++)
+ ;
+ if (*p == '#' || *p == '\0') { /* comment or empty string */
+#ifdef DEBUG
+ printf("rem\n");
+#endif
+ return 0;
+ }
+ ct = cmd_table;
+ cs = NULL;
+ cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */
+ p = whatcmd(&ct, p);
+ if (ct == NULL) {
+ cmd.argc++;
+ ct = cmd_table;
+ } else if (ct->cmd_type == CMDT_SET && p != NULL) {
+ cs = cmd_set;
+#ifdef MACHINE_CMD
+ } else if (ct->cmd_type == CMDT_MDC && p != NULL) {
+ cs = MACHINE_CMD;
+#endif
+ }
+
+ if (cs != NULL) {
+ p = whatcmd(&cs, p);
+ if (cs == NULL) {
+ printf("%s: syntax error\n", ct->cmd_name);
+ return 0;
+ }
+ ct = cs;
+ }
+ cmd.cmd = ct;
+ }
+
+ cmd.argv[0] = ct->cmd_name;
+ while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) {
+ cmd.argv[cmd.argc++] = p;
+ p = nextword(p);
+ }
+ cmd.argv[cmd.argc] = NULL;
+
+ return (*cmd.cmd->cmd_exec)();
+}
+
+static char *
+whatcmd(const struct cmd_table **ct, char *p)
+{
+ char *q;
+ int l;
+
+ q = nextword(p);
+
+ for (l = 0; p[l]; l++)
+ ;
+
+ while ((*ct)->cmd_name != NULL && strncmp(p, (*ct)->cmd_name, l))
+ (*ct)++;
+
+ if ((*ct)->cmd_name == NULL)
+ *ct = NULL;
+
+ return q;
+}
+
+static int
+readline(char *buf, size_t n, int to)
+{
+ struct termios saved_tio, tio;
+ struct timeval tv;
+ fd_set fdset;
+ char *p;
+ int timed_out = 0;
+#ifdef DEBUG
+ extern int debug;
+#endif
+
+ /* Only do timeout if greater than 0 */
+ if (to > 0) {
+ /* Switch to non-canonical mode for timeout detection. */
+ tcgetattr(STDIN_FILENO, &saved_tio);
+ tio = saved_tio;
+ tio.c_lflag &= ~(ECHO | ICANON);
+ tcsetattr(STDIN_FILENO, TCSANOW, &tio);
+
+ FD_ZERO(&fdset);
+ FD_SET(STDIN_FILENO, &fdset);
+ tv.tv_sec = to;
+ tv.tv_usec = 0;
+ if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, &tv) == 0)
+ timed_out = 1;
+
+ /* Restore canonical mode. */
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_tio);
+
+ if (timed_out) {
+ strlcpy(buf, "boot", 5);
+ putchar('\n');
+ return strlen(buf);
+ }
+ }
+
+ /* User has typed something. Turn off timeouts. */
+ cmd.timeout = 0;
+
+ if (fgets(buf, n, stdin) == NULL)
+ return 0;
+
+ /* Strip trailing newline. */
+ p = strchr(buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+
+ return strlen(buf);
+}
+
+/*
+ * Search for spaces/tabs after the current word. If found, \0 the
+ * first one. Then pass a pointer to the first character of the
+ * next word, or NULL if there is no next word.
+ */
+char *
+nextword(char *p)
+{
+ /* skip blanks */
+ while (*p && *p != '\t' && *p != ' ')
+ p++;
+ if (*p) {
+ *p++ = '\0';
+ while (*p == '\t' || *p == ' ')
+ p++;
+ }
+ if (*p == '\0')
+ p = NULL;
+ return p;
+}
+
+static void
+print_help(const struct cmd_table *ct)
+{
+ for (; ct->cmd_name != NULL; ct++)
+ printf(" %s", ct->cmd_name);
+ putchar('\n');
+}
+
+static int
+Xhelp(void)
+{
+ printf("commands:");
+ print_help(cmd_table);
+#ifdef MACHINE_CMD
+ return Xmachine();
+#else
+ return 0;
+#endif
+}
+
+#ifdef MACHINE_CMD
+static int
+Xmachine(void)
+{
+ printf("machine:");
+ print_help(MACHINE_CMD);
+ return 0;
+}
+#endif
+
+static int
+Xecho(void)
+{
+ int i;
+
+ for (i = 1; i < cmd.argc; i++)
+ printf("%s ", cmd.argv[i]);
+ putchar('\n');
+ return 0;
+}
+
+static int
+Xls(void)
+{
+ struct stat sb;
+ const char *path;
+ DIR *dir;
+ struct dirent *dent;
+ int dirfd, oldcwd;
+
+ path = disk_open(qualify(cmd.argv[1] ? cmd.argv[1] : "/."));
+ if (path == NULL)
+ return 0;
+
+ if (stat(path, &sb) < 0) {
+ printf("stat(%s): %s\n", cmd.path, strerror(errno));
+ goto out;
+ }
+
+ if ((sb.st_mode & S_IFMT) != S_IFDIR)
+ ls(path, &sb);
+ else {
+ oldcwd = open(".", O_RDONLY);
+
+ dirfd = open(path, O_RDONLY);
+ if (dirfd < 0) {
+ printf("opendir(%s): %s\n", cmd.path, strerror(errno));
+ close(oldcwd);
+ goto out;
+ }
+ if ((dir = fdopendir(dirfd)) < 0) {
+ printf("opendir(%s): %s\n", cmd.path, strerror(errno));
+ close(dirfd);
+ close(oldcwd);
+ goto out;
+ }
+ fchdir(dirfd);
+ while ((dent = readdir(dir)) != NULL) {
+ if (fstatat(dirfd, dent->d_name, &sb,
+ AT_SYMLINK_NOFOLLOW) < 0)
+ printf("stat(%s): %s\n", dent->d_name,
+ strerror(errno));
+ else
+ ls(dent->d_name, &sb);
+ }
+ closedir(dir);
+
+ fchdir(oldcwd);
+ close(oldcwd);
+ }
+
+out:
+ disk_close();
+ return 0;
+}
+
+#define lsrwx(mode,s) \
+ putchar ((mode) & S_IROTH? 'r' : '-'); \
+ putchar ((mode) & S_IWOTH? 'w' : '-'); \
+ putchar ((mode) & S_IXOTH? *(s): (s)[1]);
+
+static void
+ls(const char *name, struct stat *sb)
+{
+ putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]);
+ lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-"));
+ lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-"));
+ lsrwx(sb->st_mode , (sb->st_mode & S_ISTXT? "tT" : "x-"));
+
+ printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid,
+ (u_long)sb->st_size, name);
+}
+#undef lsrwx
+
+int doboot = 1;
+
+static int
+Xnop(void)
+{
+ if (doboot) {
+ doboot = 0;
+ return (Xboot());
+ }
+
+ return 0;
+}
+
+static int
+Xboot(void)
+{
+ if (cmd.argc > 1 && cmd.argv[1][0] != '-') {
+ qualify((cmd.argv[1]? cmd.argv[1]: cmd.image));
+ if (bootparse(2))
+ return 0;
+ } else {
+ if (bootparse(1))
+ return 0;
+ snprintf(cmd.path, sizeof cmd.path, "%s:%s",
+ cmd.bootdev, cmd.image);
+ }
+
+ return 1;
+}
+
+/*
+ * Qualifies the path adding necessary dev
+ */
+
+static char *
+qualify(char *name)
+{
+ char *p;
+
+ for (p = name; *p; p++)
+ if (*p == ':')
+ break;
+ if (*p == ':')
+ strlcpy(cmd.path, name, sizeof(cmd.path));
+ else
+ snprintf(cmd.path, sizeof cmd.path, "%s:%s",
+ cmd.bootdev, name);
+ return cmd.path;
+}
+
+static int
+Xreboot(void)
+{
+ printf("Rebooting...\n");
+ reboot(0);
+ return 0; /* just in case */
+}
+
+int
+upgrade(void)
+{
+ struct stat sb;
+ const char *path;
+ int ret = 0;
+
+ path = disk_open(qualify("/bsd.upgrade"));
+ if (path == NULL)
+ return 0;
+ if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode))
+ ret = 1;
+ disk_close();
+
+ return ret;
+}
diff --git a/sys/arch/powerpc64/stand/rdboot/cmd.h b/sys/arch/powerpc64/stand/rdboot/cmd.h
new file mode 100644
index 00000000000..1bbe0af07c9
--- /dev/null
+++ b/sys/arch/powerpc64/stand/rdboot/cmd.h
@@ -0,0 +1,65 @@
+/* $OpenBSD: cmd.h,v 1.1 2020/07/16 19:48:58 kettenis Exp $ */
+
+/*
+ * Copyright (c) 1997 Michael Shalayeff
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define CMD_BUFF_SIZE 133
+#define BOOTDEVLEN 1024
+
+struct cmd_table {
+ char *cmd_name;
+ char cmd_type;
+#define CMDT_CMD 0
+#define CMDT_VAR 1
+#define CMDT_SET 2
+#define CMDT_MDC 3
+ int (*cmd_exec)(void);
+};
+
+struct cmd_state {
+ char bootdev[BOOTDEVLEN]; /* device */
+ char image[MAXPATHLEN - 16]; /* image */
+ unsigned char bootduid[8]; /* duid of root disk */
+ int boothowto; /* howto */
+ int hasduid;
+ char *conf; /* /etc/boot.conf normally */
+ int timeout;
+
+ char path[MAXPATHLEN]; /* buffer for pathname compose */
+ const struct cmd_table *cmd;
+ int argc;
+ char *argv[8]; /* XXX i hope this is enough */
+};
+extern struct cmd_state cmd;
+
+int getcmd(void);
+int read_conf(void);
+int bootparse(int);
+void boot(dev_t);
+
+int upgrade(void);
+int docmd(void); /* No longer static: needed by regress test */
diff --git a/sys/arch/powerpc64/stand/rdboot/disk.c b/sys/arch/powerpc64/stand/rdboot/disk.c
new file mode 100644
index 00000000000..73298dd165f
--- /dev/null
+++ b/sys/arch/powerpc64/stand/rdboot/disk.c
@@ -0,0 +1,208 @@
+/* $OpenBSD: disk.c,v 1.1 2020/07/16 19:48:58 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2019 Visa Hankala
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "cmd.h"
+
+int disk_proberoot(const char *);
+
+int mounted = 0;
+int rdroot = -1; /* fd that points to the root of the ramdisk */
+
+void
+disk_init(void)
+{
+ char rootdevs[1024];
+ char *devname, *disknames, *ptr;
+ size_t size;
+ int mib[2];
+
+ rdroot = open("/", O_RDONLY);
+ if (rdroot == -1)
+ err(1, "failed to open root directory fd");
+
+ if (strlen(cmd.bootdev) != 0)
+ return;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_DISKNAMES;
+ size = 0;
+ if (sysctl(mib, 2, NULL, &size, NULL, 0) == -1) {
+ fprintf(stderr, "%s: cannot get hw.disknames: %s\n", __func__,
+ strerror(errno));
+ return;
+ }
+ disknames = malloc(size);
+ if (disknames == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __func__);
+ return;
+ }
+ if (sysctl(mib, 2, disknames, &size, NULL, 0) == -1) {
+ fprintf(stderr, "%s: cannot get hw.disknames: %s\n", __func__,
+ strerror(errno));
+ free(disknames);
+ return;
+ }
+
+ printf("probing disks\n");
+ rootdevs[0] = '\0';
+ ptr = disknames;
+ while ((devname = strsep(&ptr, ",")) != NULL) {
+ char *duid;
+
+ duid = strchr(devname, ':');
+ if (duid == NULL)
+ continue;
+ *duid++ = '\0';
+
+ /* Disk without a duid cannot be a root device. */
+ if (strlen(duid) == 0)
+ continue;
+
+ if (disk_proberoot(devname)) {
+ if (strlen(cmd.bootdev) == 0) {
+ snprintf(cmd.bootdev, sizeof(cmd.bootdev),
+ "%sa", devname);
+ }
+ (void)strlcat(rootdevs, " ", sizeof(rootdevs));
+ (void)strlcat(rootdevs, devname, sizeof(rootdevs));
+ }
+ }
+ if (strlen(rootdevs) != 0)
+ printf("available root devices:%s\n", rootdevs);
+ else
+ printf("no root devices found\n");
+}
+
+int
+disk_proberoot(const char *devname)
+{
+ static const char *const names[] = {
+ "bin", "dev", "etc", "home", "mnt", "root", "sbin", "tmp",
+ "usr", "var", NULL
+ };
+ struct ufs_args ffs_args;
+ struct stat st;
+ char path[32];
+ int i, is_root = 1;
+
+ snprintf(path, sizeof(path), "/dev/%sa", devname);
+ memset(&ffs_args, 0, sizeof(ffs_args));
+ ffs_args.fspec = path;
+ if (mount(MOUNT_FFS, "/mnt", MNT_RDONLY, &ffs_args) == -1)
+ return 0;
+ for (i = 0; names[i] != NULL; i++) {
+ snprintf(path, sizeof(path), "/mnt/%s", names[i]);
+ if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
+ is_root = 0;
+ break;
+ }
+ }
+ (void)unmount("/mnt", 0);
+
+ return is_root;
+}
+
+const char *
+disk_open(const char *path)
+{
+ struct ufs_args ffs_args;
+ struct disklabel label;
+ char devname[32];
+ char *devpath;
+ const char *ptr;
+ int fd;
+
+ if (mounted) {
+ fprintf(stderr, "%s: cannot nest\n", __func__);
+ return NULL;
+ }
+
+ ptr = strchr(path, ':');
+ if (ptr != NULL) {
+ snprintf(devname, sizeof(devname), "%.*s",
+ (int)(ptr - path), path);
+ ptr++; /* skip ':' */
+ } else {
+ strlcpy(devname, cmd.bootdev, sizeof(devname));
+ ptr = path;
+ }
+ if (strlen(devname) == 0) {
+ fprintf(stderr, "no device specified\n");
+ return NULL;
+ }
+
+ cmd.hasduid = 0;
+ fd = opendev(devname, O_RDONLY, OPENDEV_BLCK, &devpath);
+ if (fd != -1) {
+ if (ioctl(fd, DIOCGDINFO, &label) != -1) {
+ memcpy(cmd.bootduid, label.d_uid, 8);
+ cmd.hasduid = 1;
+ }
+ close(fd);
+ } else {
+ fprintf(stderr, "failed to open device %s: %s\n", devname,
+ strerror(errno));
+ return NULL;
+ }
+
+ memset(&ffs_args, 0, sizeof(ffs_args));
+ ffs_args.fspec = devpath;
+ if (mount(MOUNT_FFS, "/mnt", MNT_FORCE | MNT_NOATIME,
+ &ffs_args) == -1) {
+ fprintf(stderr, "failed to mount %s: %s\n", devpath,
+ strerror(errno));
+ return NULL;
+ }
+ if (chroot("/mnt") == -1) {
+ fprintf(stderr, "failed to chroot: %s\n", strerror(errno));
+ (void)unmount("/mnt", 0);
+ return NULL;
+ }
+ mounted = 1;
+
+ return ptr;
+}
+
+void
+disk_close(void)
+{
+ if (mounted) {
+ (void)fchdir(rdroot);
+ (void)chroot(".");
+ mounted = 0;
+ (void)unmount("/mnt", 0);
+ }
+}
diff --git a/sys/arch/powerpc64/stand/rdboot/disk.h b/sys/arch/powerpc64/stand/rdboot/disk.h
new file mode 100644
index 00000000000..4c01e33ca82
--- /dev/null
+++ b/sys/arch/powerpc64/stand/rdboot/disk.h
@@ -0,0 +1,21 @@
+/* $OpenBSD: disk.h,v 1.1 2020/07/16 19:48:58 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2019 Visa Hankala
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+void disk_init(void);
+const char *disk_open(const char *);
+void disk_close(void);
diff --git a/sys/arch/powerpc64/stand/rdboot/rdboot.c b/sys/arch/powerpc64/stand/rdboot/rdboot.c
new file mode 100644
index 00000000000..704e8945181
--- /dev/null
+++ b/sys/arch/powerpc64/stand/rdboot/rdboot.c
@@ -0,0 +1,245 @@
+/* $OpenBSD: rdboot.c,v 1.1 2020/07/16 19:48:58 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2019-2020 Visa Hankala
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <util.h>
+
+#include <machine/kexec.h>
+#include <machine/param.h>
+
+#include "cmd.h"
+#include "disk.h"
+
+#define DEVRANDOM "/dev/random"
+#define BOOTRANDOM "/etc/random.seed"
+#define BOOTRANDOM_MAX 256 /* no point being greater than RC4STATE */
+#define KERNEL "/bsd"
+
+int loadrandom(void);
+void kexec(void);
+
+struct cmd_state cmd;
+int kexecfd = -1;
+const char version[] = "0.1";
+
+int
+main(void)
+{
+ char bootduid[8];
+ int fd, hasboot;
+
+ fd = open(_PATH_CONSOLE, O_RDWR);
+ login_tty(fd);
+
+ /* Keep stdout unbuffered to mimic ordinary bootblocks. */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ printf(">> OpenBSD/" MACHINE " BOOT %s\n", version);
+
+ kexecfd = open("/dev/kexec", O_WRONLY);
+ if (kexecfd == -1)
+ err(1, "cannot open boot control device");
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.boothowto = 0;
+ cmd.conf = "/etc/boot.conf";
+ strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
+ cmd.timeout = 5;
+
+#if 0
+ if (ioctl(kexecfd, KIOC_GETBOOTDUID, bootduid) == -1) {
+ if (errno != ENOENT)
+ fprintf(stderr, "cannot get bootduid from kernel: %s\n",
+ strerror(errno));
+ } else {
+ snprintf(cmd.bootdev, sizeof(cmd.bootdev), "%s%sa",
+ rootdev, isduid(rootdev, OPENDEV_PART) ? "." : "");
+ }
+#endif
+
+ disk_init();
+
+ if (upgrade()) {
+ strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
+ printf("upgrade detected: switching to %s\n", cmd.image);
+ }
+
+ hasboot = read_conf();
+
+ for (;;) {
+ if (hasboot <= 0) {
+ do {
+ printf("boot> ");
+ } while (!getcmd());
+ }
+
+ if (loadrandom() == 0)
+ cmd.boothowto |= RB_GOODRANDOM;
+
+ kexec();
+
+ hasboot = 0;
+ strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
+ printf("will try %s\n", cmd.image);
+ }
+
+ return 0;
+}
+
+int
+loadrandom(void)
+{
+ char buf[BOOTRANDOM_MAX];
+ struct stat sb;
+ int fd, ret = 0;
+
+ /* Read the file from the device specified by the kernel path. */
+ if (disk_open(cmd.path) == NULL)
+ return -1;
+ fd = open(BOOTRANDOM, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "%s: cannot open %s: %s", __func__, BOOTRANDOM,
+ strerror(errno));
+ disk_close();
+ return -1;
+ }
+ if (fstat(fd, &sb) == 0) {
+ if (sb.st_mode & S_ISTXT) {
+ printf("NOTE: random seed is being reused.\n");
+ ret = -1;
+ }
+ if (read(fd, buf, sizeof(buf)) != sizeof(buf))
+ ret = -1;
+ fchmod(fd, sb.st_mode | S_ISTXT);
+ } else {
+ ret = -1;
+ }
+ close(fd);
+ disk_close();
+
+ /*
+ * Push the whole buffer to the entropy pool.
+ * The kernel will use the entropy on kexec().
+ * It does not matter if some of the buffer content is uninitialized.
+ */
+ fd = open(DEVRANDOM, O_WRONLY);
+ if (fd == -1) {
+ fprintf(stderr, "%s: cannot open %s: %s", __func__,
+ DEVRANDOM, strerror(errno));
+ return -1;
+ }
+ write(fd, buf, sizeof(buf));
+ close(fd);
+ return ret;
+}
+
+void
+kexec(void)
+{
+ struct kexec_args kargs;
+ struct stat sb;
+ char boothowtostr[32];
+ char rootdev[32];
+ char *kimg = NULL;
+ const char *path;
+ ssize_t n;
+ off_t pos;
+ int argc, fd = -1, ret;
+
+ path = disk_open(cmd.path);
+ if (path == NULL)
+ return;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ goto load_failed;
+ if (fstat(fd, &sb) == -1)
+ goto load_failed;
+ if (!S_ISREG(sb.st_mode) || sb.st_size == 0) {
+ errno = ENOEXEC;
+ goto load_failed;
+ }
+
+ kimg = malloc(sb.st_size);
+ if (kimg == NULL)
+ goto load_failed;
+
+ pos = 0;
+ while (pos < sb.st_size) {
+ n = read(fd, kimg + pos, sb.st_size - pos);
+ if (n == -1)
+ goto load_failed;
+ pos += n;
+ }
+
+ close(fd);
+ disk_close();
+
+ memset(&kargs, 0, sizeof(kargs));
+ kargs.kimg = kimg;
+ kargs.klen = sb.st_size;
+ argc = 0;
+ if (cmd.boothowto != 0) {
+ snprintf(boothowtostr, sizeof(boothowtostr), "boothowto=%d",
+ cmd.boothowto);
+ kargs.argv[argc++] = boothowtostr;
+ }
+ if (cmd.hasduid) {
+ snprintf(rootdev, sizeof(rootdev),
+ "rootdev=%02x%02x%02x%02x%02x%02x%02x%02x",
+ cmd.bootduid[0], cmd.bootduid[1],
+ cmd.bootduid[2], cmd.bootduid[3],
+ cmd.bootduid[4], cmd.bootduid[5],
+ cmd.bootduid[6], cmd.bootduid[7]);
+ kargs.argv[argc++] = rootdev;
+ }
+
+ printf("booting %s\n", cmd.path);
+ ret = ioctl(kexecfd, KIOC_KEXEC, &kargs);
+ if (ret == -1)
+ fprintf(stderr, "failed to execute kernel %s: %s\n",
+ cmd.path, strerror(errno));
+ else
+ fprintf(stderr, "kexec() returned unexpectedly\n");
+ free(kimg);
+ return;
+
+load_failed:
+ fprintf(stderr, "failed to load kernel %s: %s\n",
+ cmd.path, strerror(errno));
+ if (fd != -1)
+ close(fd);
+ disk_close();
+ free(kimg);
+}
diff --git a/sys/arch/powerpc64/stand/rdboot/vars.c b/sys/arch/powerpc64/stand/rdboot/vars.c
new file mode 100644
index 00000000000..a923e35184a
--- /dev/null
+++ b/sys/arch/powerpc64/stand/rdboot/vars.c
@@ -0,0 +1,203 @@
+/* $OpenBSD: vars.c,v 1.1 2020/07/16 19:48:58 kettenis Exp $ */
+
+/*
+ * Copyright (c) 1998-2000 Michael Shalayeff
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "cmd.h"
+
+extern int debug;
+int db_console = -1;
+
+static int Xdevice(void);
+#ifdef DEBUG
+static int Xdebug(void);
+#endif
+static int Xdb_console(void);
+static int Ximage(void);
+static int Xhowto(void);
+static int Xtimeout(void);
+int Xset(void);
+
+const struct cmd_table cmd_set[] = {
+ {"howto", CMDT_VAR, Xhowto},
+#ifdef DEBUG
+ {"debug", CMDT_VAR, Xdebug},
+#endif
+ {"device", CMDT_VAR, Xdevice},
+ {"image", CMDT_VAR, Ximage},
+ {"timeout",CMDT_VAR, Xtimeout},
+ {"db_console", CMDT_VAR, Xdb_console},
+ {NULL,0}
+};
+
+#ifdef DEBUG
+static int
+Xdebug(void)
+{
+ if (cmd.argc != 2)
+ printf( "o%s\n", debug? "n": "ff" );
+ else
+ debug = (cmd.argv[1][0] == '0' ||
+ (cmd.argv[1][0] == 'o' && cmd.argv[1][1] == 'f'))?
+ 0: 1;
+ return 0;
+}
+#endif
+
+int
+Xdb_console(void)
+{
+ if (cmd.argc != 2) {
+ switch (db_console) {
+ case 0:
+ printf("off\n");
+ break;
+ case 1:
+ printf("on\n");
+ break;
+ default:
+ printf("unset\n");
+ break;
+ }
+ } else {
+ if (strcmp(cmd.argv[1], "0") == 0 ||
+ strcmp(cmd.argv[1], "off") == 0)
+ db_console = 0;
+ else if (strcmp(cmd.argv[1], "1") == 0 ||
+ strcmp(cmd.argv[1], "on") == 0)
+ db_console = 1;
+ }
+
+ return (0);
+}
+
+static int
+Xtimeout(void)
+{
+ if (cmd.argc != 2)
+ printf( "%d\n", cmd.timeout );
+ else
+ cmd.timeout = (int)strtol( cmd.argv[1], (char **)NULL, 0 );
+ return 0;
+}
+
+/* called only w/ no arguments */
+int
+Xset(void)
+{
+ const struct cmd_table *ct;
+
+ printf("boot\n");
+ for (ct = cmd_set; ct->cmd_name != NULL; ct++) {
+ printf("%s\t ", ct->cmd_name);
+ (*ct->cmd_exec)();
+ }
+ return 0;
+}
+
+static int
+Xdevice(void)
+{
+ if (cmd.argc != 2)
+ printf("%s\n", cmd.bootdev);
+ else
+ strlcpy(cmd.bootdev, cmd.argv[1], sizeof(cmd.bootdev));
+ return 0;
+}
+
+static int
+Ximage(void)
+{
+ if (cmd.argc != 2)
+ printf("%s\n", cmd.image);
+ else
+ strlcpy(cmd.image, cmd.argv[1], sizeof(cmd.image));
+ return 0;
+}
+
+static int
+Xhowto(void)
+{
+ if (cmd.argc == 1) {
+ if (cmd.boothowto) {
+ putchar('-');
+ if (cmd.boothowto & RB_ASKNAME)
+ putchar('a');
+ if (cmd.boothowto & RB_CONFIG)
+ putchar('c');
+ if (cmd.boothowto & RB_SINGLE)
+ putchar('s');
+ if (cmd.boothowto & RB_KDB)
+ putchar('d');
+ }
+ putchar('\n');
+ } else
+ bootparse(1);
+ return 0;
+}
+
+int
+bootparse(int i)
+{
+ char *cp;
+ int howto = cmd.boothowto;
+
+ for (; i < cmd.argc; i++) {
+ cp = cmd.argv[i];
+ if (*cp == '-') {
+ while (*++cp) {
+ switch (*cp) {
+ case 'a':
+ howto |= RB_ASKNAME;
+ break;
+ case 'c':
+ howto |= RB_CONFIG;
+ break;
+ case 's':
+ howto |= RB_SINGLE;
+ break;
+ case 'd':
+ howto |= RB_KDB;
+ break;
+ default:
+ printf("howto: bad option: %c\n", *cp);
+ return 1;
+ }
+ }
+ }
+ }
+ cmd.boothowto = howto;
+ return 0;
+}