On Mon, Sep 25, 2023 at 05:35:40AM +0000, Visa Hankala wrote:
> 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.

Are there more reasons or benefits to this approach than a) less intrusive
chmod() and b) more shared, overall less code?

I obviously don't see the full picture (yet).

> 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