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 <[email protected]>
> > > >
> > > > In comparison to MI boot which only cares about /bsd.upgrade's x bit,
> > > > powerpc64 rdboot just wants a regular file.
> > > >
> > > > Require and strip u+x before execution to prevent sysupgrade(8) loop.
> > > > I'm new to powerpc64 and can't think of a reason to be different.
> > > >
> > > > Feedback? Objection? OK?
> > >
> > > So there is a problem with this approach. Calling chmod() will mean
> > > the bootloader will change the filesystem. What happens if you're
> > > booting with a root filesystem that was not cleanly unmounted?
> > > Modifying a forcibly mounted filesystem may not be without risk.
> >
> > Isn't that already the case with chmo() /etc/random.seed?
> >
> > Can you explain how that is not a problem in other non-kernel boot loaders
> > using libsa's ufs2_open() instead of mount(2)?
>
> chmod() through libsa's filesystem code modifies only the inode.
> Doing a mount-chmod-unmount cycle using the kernel triggers multiple
> writes to the filesystem.
>
> In the past, I have pondered if octeon (and powerpc64) bootcode should
> use libsa instead of replicating the MI boot code. I did not use libsa
> initially because the libsa and libc APIs differ, and I did not want
> to use custom system call stubs. The original octboot/kexec interface
> was not suitable for libsa use, either.
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);
>