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 <k...@openbsd.org>
> > > 
> > > 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);

Reply via email to