On Sat, Sep 23, 2023 at 02:26:18PM +0000, Klemens Nanni wrote:
> On Sat, Sep 23, 2023 at 01:11:32PM +0200, Mark Kettenis wrote:
> > > Date: Thu, 21 Sep 2023 22:30:01 +0000
> > > From: Klemens Nanni <[email protected]>
> > >
> > > In comparison to MI boot which only cares about /bsd.upgrade's x bit,
> > > powerpc64 rdboot just wants a regular file.
> > >
> > > Require and strip u+x before execution to prevent sysupgrade(8) loop.
> > > I'm new to powerpc64 and can't think of a reason to be different.
> > >
> > > Feedback? Objection? OK?
> >
> > So there is a problem with this approach. Calling chmod() will mean
> > the bootloader will change the filesystem. What happens if you're
> > booting with a root filesystem that was not cleanly unmounted?
> > Modifying a forcibly mounted filesystem may not be without risk.
>
> Isn't that already the case with chmo() /etc/random.seed?
>
> Can you explain how that is not a problem in other non-kernel boot loaders
> using libsa's ufs2_open() instead of mount(2)?
chmod() through libsa's filesystem code modifies only the inode.
Doing a mount-chmod-unmount cycle using the kernel triggers multiple
writes to the filesystem.
In the past, I have pondered if octeon (and powerpc64) bootcode should
use libsa instead of replicating the MI boot code. I did not use libsa
initially because the libsa and libc APIs differ, and I did not want
to use custom system call stubs. The original octboot/kexec interface
was not suitable for libsa use, either.
However, the libsa and libc worlds can be reconciled with a trick.
The libsa code is first compiled in standalone mode into a relinkable
object ("saboot"). This object is then tweaked to avoid name conflicts
with libc. Finally, the object is linked with glue code and libc into
a proper rdboot executable that the kernel can run.
Some have seen this before.
diff --git a/sys/arch/octeon/stand/Makefile b/sys/arch/octeon/stand/Makefile
index 498bd2809c6..4a86a8bef6b 100644
--- a/sys/arch/octeon/stand/Makefile
+++ b/sys/arch/octeon/stand/Makefile
@@ -1,5 +1,5 @@
# $OpenBSD: Makefile,v 1.4 2019/08/04 08:53:14 visa Exp $
-SUBDIR+= rdboot boot
+SUBDIR+= saboot rdboot boot
.include <bsd.subdir.mk>
diff --git a/sys/arch/octeon/stand/Makefile.inc
b/sys/arch/octeon/stand/Makefile.inc
deleted file mode 100644
index 18d8470f888..00000000000
--- a/sys/arch/octeon/stand/Makefile.inc
+++ /dev/null
@@ -1,45 +0,0 @@
-# $OpenBSD: Makefile.inc,v 1.1 2013/06/05 01:02:29 jasper Exp $
-
-BINDIR= /usr/mdec
-
-STANDALONE?= -D_STANDALONE
-
-.if ${MACHINE} == "octeon"
-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
-SAABI= -mips3 -mno-abicalls -G 0 -fno-pic -fno-common
-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/octeon/stand/libsa/Makefile
b/sys/arch/octeon/stand/libsa/Makefile
deleted file mode 100644
index 3b2961f25c0..00000000000
--- a/sys/arch/octeon/stand/libsa/Makefile
+++ /dev/null
@@ -1,51 +0,0 @@
-# $OpenBSD: Makefile,v 1.8 2019/10/29 02:55:52 deraadt Exp $
-
-.include "${.CURDIR}/../Makefile.inc"
-
-LIB= sa
-
-.PATH: ${.CURDIR}/../../../../lib/libsa
-
-CLEANFILES += machine mips64
-
-CFLAGS+= ${CEXTRAFLAGS} ${SAABI} -nostdinc -mno-abicalls -D_NO_ABICALLS \
- -fno-pie \
- -I${.CURDIR} -I${.CURDIR}/../include -I${.CURDIR}/../.. \
- -I${.CURDIR}/../../.. -I${.CURDIR}/../../../.. \
- -I${.CURDIR}/../../../../lib/libsa \
- -I${.OBJDIR}
-
-# stand routines
-SRCS= alloc.c cons.c ctime.c exit.c getchar.c getfile.c getln.c globals.c \
- memcmp.c memcpy.c memmove.c memset.c printf.c putchar.c \
- snprintf.c strchr.c strcmp.c strerror.c strncmp.c strncpy.c strtol.c
-
-# io routines
-SRCS+= close.c closeall.c dev.c disklabel.c dkcksum.c fstat.c ioctl.c \
- lseek.c open.c read.c readdir.c stat.c write.c
-
-#SRCS+= cread.c
-#CPPFLAGS+= -D__INTERNAL_LIBSA_CREAD
-
-# boot filesystems
-SRCS+= ufs.c cd9660.c
-
-CFLAGS+=-DNO_NET
-
-SRCS+= loadfile.c arc4.c
-
-${OBJS}: ${.CURDIR}/../Makefile.inc
-
-NOPROFILE=
-NOPIC=
-
-.if !make(clean) && !make(cleandir) && !make(includes) && !make(obj)
-.BEGIN:
- @([ -h machine ] || ln -s ${.CURDIR}/../../include machine)
- @([ -h mips64 ] || ln -s ${.CURDIR}/../../../mips64/include mips64)
-CLEANFILES+= machine mips64
-.endif
-
-install:
-
-.include <bsd.lib.mk>
diff --git a/sys/arch/octeon/stand/rdboot/Makefile
b/sys/arch/octeon/stand/rdboot/Makefile
index 841c363ed60..5833076c30b 100644
--- a/sys/arch/octeon/stand/rdboot/Makefile
+++ b/sys/arch/octeon/stand/rdboot/Makefile
@@ -4,16 +4,32 @@ NOMAN=
.if ${MACHINE} == "octeon"
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
+S= ${.CURDIR}/../../../..
+BOOTDIR= ${S}/arch/octeon/stand/rdboot
+
+CFLAGS+= -Wall
+CFLAGS+= -I${.CURDIR}/../saboot
+
+.PATH: ${BOOTDIR}
+SRCS= rdboot.c unixcall.c
install:
+.if !make(clean) && !make(cleandir) && !make(includes) && !make(obj)
+.BEGIN:
+ @([ -h machine ] || ln -s ${.CURDIR}/../../include machine)
+ @([ -h mips64 ] || ln -s ${.CURDIR}/../../../mips64/include mips64)
+CLEANFILES+= machine mips64
+.endif
+
+SABOOT= ${.CURDIR}/../saboot/obj/saboot.elf
+
+${PROG}: ${OBJS} ${SABOOT}
+ ${CC} -static -o $@ ${SABOOT} ${OBJS} -lutil
+
+.else
+NOPROG=
+.endif
+
.include <bsd.prog.mk>
diff --git a/sys/arch/octeon/stand/rdboot/cmd.c
b/sys/arch/octeon/stand/rdboot/cmd.c
deleted file mode 100644
index c9790bb8920..00000000000
--- a/sys/arch/octeon/stand/rdboot/cmd.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/* $OpenBSD: cmd.c,v 1.3 2019/08/01 04:52:56 visa 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/octeon/stand/rdboot/cmd.h
b/sys/arch/octeon/stand/rdboot/cmd.h
deleted file mode 100644
index 1ffafde59ef..00000000000
--- a/sys/arch/octeon/stand/rdboot/cmd.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* $OpenBSD: cmd.h,v 1.1 2019/07/17 14:36:32 visa 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/octeon/stand/rdboot/disk.c
b/sys/arch/octeon/stand/rdboot/disk.c
deleted file mode 100644
index eda089bc34f..00000000000
--- a/sys/arch/octeon/stand/rdboot/disk.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* $OpenBSD: disk.c,v 1.2 2020/05/26 13:30:47 visa 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/octeon/stand/rdboot/disk.h
b/sys/arch/octeon/stand/rdboot/disk.h
deleted file mode 100644
index ac0d1879bb0..00000000000
--- a/sys/arch/octeon/stand/rdboot/disk.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* $OpenBSD: disk.h,v 1.1 2019/07/17 14:36:32 visa 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/octeon/stand/rdboot/rdboot.c
b/sys/arch/octeon/stand/rdboot/rdboot.c
index 850279c42a4..136d2c89003 100644
--- a/sys/arch/octeon/stand/rdboot/rdboot.c
+++ b/sys/arch/octeon/stand/rdboot/rdboot.c
@@ -1,9 +1,9 @@
/* $OpenBSD: rdboot.c,v 1.8 2020/12/09 18:10:19 krw Exp $ */
/*
- * Copyright (c) 2019-2020 Visa Hankala
+ * Copyright (c) 2019-2022 Visa Hankala
*
- * Permission to use, copy, modify, and/or distribute this software for any
+ * Permission to use, copy, modify, and 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.
*
@@ -19,10 +19,8 @@
#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 <sys/sysctl.h>
#include <err.h>
#include <errno.h>
@@ -36,28 +34,25 @@
#include <util.h>
#include <machine/octboot.h>
-#include <machine/param.h>
-#include "cmd.h"
-#include "disk.h"
+#define BOOTDEVLEN 1024
-#define DEVRANDOM "/dev/random"
-#define BOOTRANDOM "/etc/random.seed"
-#define BOOTRANDOM_MAX 256 /* no point being greater than RC4STATE */
-#define KERNEL "/bsd"
+void findroot(char *, size_t);
-int loadrandom(void);
-void kexec(void);
+void saboot_boot(int);
+void saboot_cninit(void);
+int saboot_proberoot(const char *);
-struct cmd_state cmd;
+char rootdev[32];
int octbootfd = -1;
-const char version[] = "1.3";
+
+extern unsigned char bootduid[];
+extern int bootduidvalid;
int
main(void)
{
- char rootdev[PATH_MAX];
- int fd, hasboot;
+ int fd;
fd = open(_PATH_CONSOLE, O_RDWR);
login_tty(fd);
@@ -65,179 +60,140 @@ main(void)
/* Keep stdout unbuffered to mimic ordinary bootblocks. */
setvbuf(stdout, NULL, _IONBF, 0);
- printf(">> OpenBSD/" MACHINE " BOOT %s\n", version);
-
octbootfd = open("/dev/octboot", O_WRONLY);
if (octbootfd == -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;
+ saboot_cninit();
+ saboot_boot(0);
+ reboot(RB_AUTOBOOT | RB_TIMEBAD);
+
+ return 0;
+}
+
+void
+machdep(void)
+{
if (ioctl(octbootfd, OBIOC_GETROOTDEV, rootdev) == -1) {
- if (errno != ENOENT)
+ if (errno != ENOENT) {
fprintf(stderr, "cannot get rootdev from kernel: %s\n",
strerror(errno));
+ }
+ findroot(rootdev, sizeof(rootdev));
} else {
- snprintf(cmd.bootdev, sizeof(cmd.bootdev), "%s%sa",
- rootdev, isduid(rootdev, OPENDEV_PART) ? "." : "");
+ if (isduid(rootdev, OPENDEV_PART))
+ (void)strlcat(rootdev, ".", sizeof(rootdev));
+ (void)strlcat(rootdev, "a", sizeof(rootdev));
}
+}
- disk_init();
-
- if (upgrade()) {
- strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
- printf("upgrade detected: switching to %s\n", cmd.image);
+void
+findroot(char *rootdev, size_t rootdevlen)
+{
+ char rootdevs[1024];
+ char devname[32];
+ char *diskname, *disknames, *ptr;
+ size_t size;
+ int mib[2];
+
+ 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;
}
- hasboot = read_conf();
-
- for (;;) {
- if (hasboot <= 0) {
- do {
- printf("boot> ");
- } while (!getcmd());
+ printf("probing disks\n");
+ rootdevs[0] = '\0';
+ ptr = disknames;
+ while ((diskname = strsep(&ptr, ",")) != NULL) {
+ char *duid;
+
+ duid = strchr(diskname, ':');
+ if (duid == NULL)
+ continue;
+ *duid++ = '\0';
+
+ /* Disk without a duid cannot contain a root device. */
+ if (strlen(duid) == 0)
+ continue;
+
+ snprintf(devname, sizeof(devname), "%sa", diskname);
+ if (saboot_proberoot(devname)) {
+ if (strlen(rootdev) == 0)
+ (void)strlcpy(rootdev, devname, rootdevlen);
+ (void)strlcat(rootdevs, " ", sizeof(rootdevs));
+ (void)strlcat(rootdevs, devname, sizeof(rootdevs));
}
-
- if (loadrandom() == 0)
- cmd.boothowto |= RB_GOODRANDOM;
-
- kexec();
-
- hasboot = 0;
- strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
- printf("will try %s\n", cmd.image);
+ }
+ if (strlen(rootdevs) != 0) {
+ printf("available root devices:%s\n", rootdevs);
+ } else {
+ printf("no root devices found\n");
+ (void)strlcpy(rootdev, "sd0a", sizeof(rootdev));
}
- return 0;
+ free(disknames);
}
-int
-loadrandom(void)
+void
+devboot(dev_t dev, char *bootdev)
{
- 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;
+ strlcpy(bootdev, rootdev, BOOTDEVLEN);
}
void
-kexec(void)
+_rtt(void)
+{
+ reboot(RB_AUTOBOOT | RB_TIMEBAD);
+}
+
+void
+hexdump(const void *addr, size_t size)
+{
+ /* Not worth it. There are better ways to study the system. */
+ printf("not implemented\n");
+}
+
+int
+ukexec(void *kimg, size_t klen, int howto)
{
struct octboot_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();
+ int argc = 0;
memset(&kargs, 0, sizeof(kargs));
kargs.kimg = kimg;
- kargs.klen = sb.st_size;
- argc = 0;
- if (cmd.boothowto != 0) {
+ kargs.klen = klen;
+ if (howto != 0) {
snprintf(boothowtostr, sizeof(boothowtostr), "boothowto=%d",
- cmd.boothowto);
+ howto);
kargs.argv[argc++] = boothowtostr;
}
- if (cmd.hasduid) {
+ if (bootduidvalid) {
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]);
+ bootduid[0], bootduid[1],
+ bootduid[2], bootduid[3],
+ bootduid[4], bootduid[5],
+ bootduid[6], bootduid[7]);
kargs.argv[argc++] = rootdev;
}
- printf("booting %s\n", cmd.path);
- ret = ioctl(octbootfd, OBIOC_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);
+ return ioctl(octbootfd, OBIOC_KEXEC, &kargs);
}
diff --git a/sys/arch/octeon/stand/rdboot/unixcall.c
b/sys/arch/octeon/stand/rdboot/unixcall.c
new file mode 100644
index 00000000000..b4aa25c4cea
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/unixcall.c
@@ -0,0 +1,153 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and 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/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "unixcall.h"
+
+unsigned char bootduid[8];
+int bootduidvalid;
+
+time_t
+getsecs(void)
+{
+ return time(NULL);
+}
+
+void
+ucninit(void)
+{
+ struct termios tio;
+
+ tcgetattr(STDIN_FILENO, &tio);
+ cfmakeraw(&tio);
+ tio.c_iflag = ICRNL|IXANY;
+ tio.c_oflag = OPOST|ONLCR;
+ tio.c_cflag = CREAD|CS8|HUPCL;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ tcsetattr(STDIN_FILENO, TCSANOW, &tio);
+}
+
+int
+ucngetc(int dopoll)
+{
+ struct pollfd pfd[1];
+ int ret;
+ char b;
+
+ pfd[0].fd = STDIN_FILENO;
+ pfd[0].events = POLLIN;
+
+ for (;;) {
+ ret = poll(pfd, 1, dopoll ? 0 : -1);
+ if (dopoll)
+ return ret > 0;
+ if (ret > 0) {
+ if (read(STDIN_FILENO, &b, 1) < 1)
+ return -1;
+ return b;
+ }
+ }
+}
+
+void
+ucnputc(int c)
+{
+ char b = c;
+
+ write(STDOUT_FILENO, &b, 1);
+}
+
+int
+udiskopen(const char *devname, int *pfd)
+{
+ struct disklabel label;
+
+ if (*devname == '\0' || *devname == '/')
+ return ENODEV;
+ *pfd = opendev(devname, O_RDWR, 0, NULL);
+ if (*pfd == -1)
+ return errno;
+
+ memset(bootduid, 0, sizeof(bootduid));
+ bootduidvalid = 0;
+ if (ioctl(*pfd, DIOCGDINFO, &label) != -1) {
+ memcpy(bootduid, label.d_uid, sizeof(bootduid));
+ bootduidvalid = 1;
+ }
+
+ return 0;
+}
+
+void
+udiskclose(int fd)
+{
+ close(fd);
+}
+
+int
+udiskread(int fd, void *buf, size_t nbytes, off_t offset, size_t *rbytes)
+{
+ ssize_t n;
+
+ n = pread(fd, buf, nbytes, offset);
+ if (n < 0)
+ return errno;
+ if (rbytes != NULL)
+ *rbytes = n;
+ return 0;
+}
+
+int
+udiskwrite(int fd, const void *buf, size_t nbytes, off_t offset, size_t
*wbytes)
+{
+ ssize_t n;
+
+ n = pwrite(fd, buf, nbytes, offset);
+ if (n < 0)
+ return errno;
+ if (wbytes != NULL)
+ *wbytes = n;
+ return 0;
+}
+
+void *
+umalloc(size_t size)
+{
+ return malloc(size);
+}
+
+void
+ufree(void *ptr)
+{
+ free(ptr);
+}
diff --git a/sys/arch/octeon/stand/rdboot/vars.c
b/sys/arch/octeon/stand/rdboot/vars.c
deleted file mode 100644
index 926c8a6cb16..00000000000
--- a/sys/arch/octeon/stand/rdboot/vars.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/* $OpenBSD: vars.c,v 1.1 2019/07/17 14:36:32 visa 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;
-}
diff --git a/sys/arch/octeon/stand/saboot/Makefile
b/sys/arch/octeon/stand/saboot/Makefile
new file mode 100644
index 00000000000..73a328c8027
--- /dev/null
+++ b/sys/arch/octeon/stand/saboot/Makefile
@@ -0,0 +1,64 @@
+# $OpenBSD$
+
+NOMAN=
+
+.if ${MACHINE} == "octeon"
+PROG= saboot.elf
+
+NM?= nm
+OBJCOPY?= objcopy
+
+S= ${.CURDIR}/../../../..
+
+CFLAGS+= -Wall -ffreestanding -D_STANDALONE -nostdinc -fno-builtin
+CFLAGS+= -I${.CURDIR}
+CFLAGS+= -I${.OBJDIR}
+CFLAGS+= -I${S}
+CFLAGS+= -I${S}/lib/libsa
+
+LDFLAGS= -nostdlib
+
+SRCS= conf.c devopen.c loadfile.c saboot.c
+
+.PATH: ${S}/stand/boot
+SRCS+= boot.c cmd.c vars.c
+
+.PATH: ${S}/lib/libsa
+SRCS+= cons.c ctime.c exit.c getchar.c getfile.c getln.c globals.c \
+ memcmp.c memcpy.c memmove.c memset.c printf.c putchar.c \
+ snprintf.c strchr.c strcmp.c strerror.c strlen.c strncmp.c \
+ strncpy.c strtol.c strtoll.c
+SRCS+= close.c closeall.c dev.c disklabel.c dkcksum.c \
+ fchmod.c fstat.c ioctl.c lseek.c open.c read.c readdir.c \
+ stat.c write.c
+SRCS+= arc4.c
+SRCS+= ufs.c ufs2.c
+
+REMAP_OBJ= ${PROG}.tmp
+CLEANFILES+= ${REMAP_OBJ}
+
+REMAP_LIST= ${PROG}.map
+CLEANFILES+= ${REMAP_LIST}
+
+# Build a relocatable object.
+# Add a prefix to the names of defined symbols so as to avoid name collisions
+# when linking with libc in the next step.
+${PROG}: ${OBJS}
+ ${CC} ${LDFLAGS} -r -o ${REMAP_OBJ} ${OBJS}
+ ${NM} -g ${REMAP_OBJ} | awk '$$1 != "U" && $$2 != "F" {printf("%s
saboot_%s\n", $$3, $$3)}' > ${REMAP_LIST}
+ ${OBJCOPY} --redefine-syms=${REMAP_LIST} ${REMAP_OBJ} ${PROG}
+
+install:
+
+.if !make(clean) && !make(cleandir) && !make(includes) && !make(obj)
+.BEGIN:
+ @([ -h machine ] || ln -s ${.CURDIR}/../../include machine)
+ @([ -h mips64 ] || ln -s ${.CURDIR}/../../../mips64/include mips64)
+CLEANFILES+= machine mips64
+.endif
+
+.else
+NOPROG=
+.endif
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/octeon/stand/saboot/conf.c
b/sys/arch/octeon/stand/saboot/conf.c
new file mode 100644
index 00000000000..a4e21f775ad
--- /dev/null
+++ b/sys/arch/octeon/stand/saboot/conf.c
@@ -0,0 +1,41 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and 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/param.h>
+#include <dev/cons.h>
+
+#include "libsa.h"
+#include <lib/libsa/ufs.h>
+#include <lib/libsa/ufs2.h>
+
+const char version[] = "2.0";
+
+struct fs_ops file_system[] = {
+ /* ufs filesystem */
+ { ufs_open, ufs_close, ufs_read, ufs_write,
+ ufs_seek, ufs_stat, ufs_readdir, ufs_fchmod },
+ { ufs2_open, ufs2_close, ufs2_read, ufs2_write,
+ ufs2_seek, ufs2_stat, ufs2_readdir, ufs2_fchmod },
+};
+int nfsys = nitems(file_system);
+
+struct consdev constab[] = {
+ { unix_cnprobe, unix_cninit, unix_cngetc, unix_cnputc },
+ { NULL }
+};
+struct consdev *cn_tab = constab;
diff --git a/sys/arch/octeon/stand/saboot/devopen.c
b/sys/arch/octeon/stand/saboot/devopen.c
new file mode 100644
index 00000000000..ce378fe335c
--- /dev/null
+++ b/sys/arch/octeon/stand/saboot/devopen.c
@@ -0,0 +1,89 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and 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/param.h>
+
+#include "libsa.h"
+#include "unixcall.h"
+
+int diskstrategy(void *, int, daddr_t, size_t, void *, size_t *);
+int diskclose(struct open_file *);
+
+static struct devsw disk = {
+ .dv_name = "disk",
+ .dv_strategy = diskstrategy,
+ .dv_close = diskclose,
+};
+
+int
+diskstrategy(void *devdata, int rw, daddr_t bn, size_t reqcnt,
+ void *buf, size_t *cnt)
+{
+ off_t offs;
+ int error, fd;
+
+ fd = (int)(intptr_t)devdata;
+ offs = bn * DEV_BSIZE;
+ switch (rw) {
+ case F_READ:
+ error = udiskread(fd, buf, reqcnt, offs, cnt);
+ break;
+ case F_WRITE:
+ error = udiskwrite(fd, buf, reqcnt, offs, cnt);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+int
+diskclose(struct open_file *f)
+{
+ int fd = (int)(intptr_t)f->f_devdata;
+
+ udiskclose(fd);
+ return 0;
+}
+
+#define MAXDEVNAME 24
+
+int
+devopen(struct open_file *f, const char *fname, char **file)
+{
+ char devname[MAXDEVNAME];
+ const char *ptr;
+ int error, fd;
+
+ ptr = strchr(fname, ':');
+ if (ptr == NULL)
+ return ENODEV;
+ if (ptr - fname >= sizeof(devname))
+ return EINVAL;
+ memcpy(devname, fname, ptr - fname);
+ devname[ptr - fname] = '\0';
+
+ error = udiskopen(devname, &fd);
+ if (error != 0)
+ return error;
+ *file = (char *)(ptr + 1);
+ f->f_dev = &disk;
+ f->f_devdata = (void *)(intptr_t)fd;
+ return 0;
+}
diff --git a/sys/arch/octeon/stand/saboot/libsa.h
b/sys/arch/octeon/stand/saboot/libsa.h
new file mode 100644
index 00000000000..40fd48cb79e
--- /dev/null
+++ b/sys/arch/octeon/stand/saboot/libsa.h
@@ -0,0 +1,30 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and 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 <lib/libsa/stand.h>
+
+#define DEFAULT_KERNEL_ADDRESS 0
+
+void devboot(dev_t, char *);
+void machdep(void);
+void run_loadfile(uint64_t *, int);
+
+void unix_cnprobe(struct consdev *);
+void unix_cninit(struct consdev *);
+int unix_cngetc(dev_t);
+void unix_cnputc(dev_t, int);
diff --git a/sys/arch/octeon/stand/saboot/loadfile.c
b/sys/arch/octeon/stand/saboot/loadfile.c
new file mode 100644
index 00000000000..1d03e5330e4
--- /dev/null
+++ b/sys/arch/octeon/stand/saboot/loadfile.c
@@ -0,0 +1,115 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and 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/param.h>
+#include <sys/exec_elf.h>
+
+#include <lib/libsa/stand.h>
+
+#include "unixcall.h"
+
+static void *kernbuf;
+static size_t kernsize;
+
+int
+loadfile(const char *fname, uint64_t *marks, int flags)
+{
+ struct stat sb;
+ char *buf = NULL;
+ size_t pos, size = 0;
+ ssize_t nread;
+ int fd;
+
+ free(kernbuf, kernsize);
+ kernbuf = NULL;
+ kernsize = 0;
+
+ fd = open(fname, O_RDONLY);
+ if (fd < 0) {
+ printf("cannot open %s: %s\n", fname, strerror(errno));
+ return -1;
+ }
+ if (fstat(fd, &sb) < 0) {
+ printf("fstat(): %s\n", strerror(errno));
+ goto fail;
+ }
+ size = sb.st_size;
+ if (size < sizeof(Elf_Ehdr)) {
+ printf("not ELF file\n");
+ goto fail;
+ }
+
+ buf = alloc(size);
+ if (buf == NULL) {
+ printf("cannot allocate %zu bytes: %s\n", size,
+ strerror(errno));
+ goto fail;
+ }
+
+ pos = 0;
+ while (pos < size) {
+ nread = read(fd, buf + pos, size - pos);
+ if (nread < 0) {
+ printf("read(): %s\n", fname, strerror(errno));
+ goto fail;
+ }
+ if (nread == 0) {
+ printf("short read\n");
+ goto fail;
+ }
+ pos += nread;
+ }
+
+ /*
+ * Screen non-ELF files.
+ * More proper validation is done at kexec time.
+ */
+ if (buf[0] != ELFMAG0 || buf[1] != ELFMAG1 ||
+ buf[2] != ELFMAG2 || buf[3] != ELFMAG3) {
+ printf("not ELF file\n");
+ goto fail;
+ }
+
+ printf("loading done\n");
+
+ kernbuf = buf;
+ kernsize = size;
+ return fd;
+fail:
+ free(buf, size);
+ close(fd);
+ return -1;
+}
+
+void
+run_loadfile(uint64_t *marks, int howto)
+{
+ if (kernbuf == NULL) {
+ printf("no kernel loaded\n");
+ return;
+ }
+
+ if (ukexec(kernbuf, kernsize, howto) == -1)
+ printf("kexec(): %s\n", strerror(errno));
+ else
+ printf("kexec() returned unexpectedly\n");
+
+ free(kernbuf, kernsize);
+ kernbuf = NULL;
+ kernsize = 0;
+}
diff --git a/sys/arch/octeon/stand/saboot/saboot.c
b/sys/arch/octeon/stand/saboot/saboot.c
new file mode 100644
index 00000000000..5da6e8a9146
--- /dev/null
+++ b/sys/arch/octeon/stand/saboot/saboot.c
@@ -0,0 +1,101 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and 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/param.h>
+#include <dev/cons.h>
+
+#include "libsa.h"
+#include "unixcall.h"
+
+int
+cnspeed(dev_t dev, int sp)
+{
+ return 115200;
+}
+
+char *
+ttyname(int fd)
+{
+ return "com0";
+}
+
+dev_t
+ttydev(char *name)
+{
+ if (strcmp(name, "com0") != 0)
+ return NODEV;
+ return makedev(0, 0);
+}
+
+void
+unix_cnprobe(struct consdev *cn)
+{
+ cn->cn_pri = CN_HIGHPRI;
+}
+
+void
+unix_cninit(struct consdev *cn)
+{
+ ucninit();
+}
+
+int
+unix_cngetc(dev_t dev)
+{
+ int dopoll = ((dev & 0x80) != 0);
+
+ return ucngetc(dopoll);
+}
+
+void
+unix_cnputc(dev_t dev, int c)
+{
+ ucnputc(c);
+}
+
+void *
+alloc(unsigned int size)
+{
+ return umalloc(size);
+}
+
+void
+free(void *ptr, unsigned int size)
+{
+ ufree(ptr);
+}
+
+int
+proberoot(const char *devname)
+{
+ static const char *const names[] = {
+ "bin", "dev", "etc", "home", "mnt", "root", "sbin", "tmp",
+ "usr", "var", NULL
+ };
+ struct stat st;
+ char path[32];
+ int i;
+
+ for (i = 0; names[i] != NULL; i++) {
+ snprintf(path, sizeof(path), "%s:%s", devname, names[i]);
+ if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode))
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/sys/arch/octeon/stand/saboot/unixcall.h
b/sys/arch/octeon/stand/saboot/unixcall.h
new file mode 100644
index 00000000000..83ba14d2430
--- /dev/null
+++ b/sys/arch/octeon/stand/saboot/unixcall.h
@@ -0,0 +1,31 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2022 Visa Hankala
+ *
+ * Permission to use, copy, modify, and 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 ucninit(void);
+int ucngetc(int);
+void ucnputc(int);
+
+int udiskopen(const char *, int *);
+void udiskclose(int);
+int udiskread(int, void *, size_t, off_t, size_t *);
+int udiskwrite(int, const void *, size_t, off_t, size_t *);
+
+void ufree(void *);
+void *umalloc(size_t);
+
+int ukexec(void *, size_t, int);