summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--distrib/octeon/boot/Makefile65
-rw-r--r--distrib/octeon/boot/list9
-rw-r--r--etc/etc.octeon/MAKEDEV.md6
-rw-r--r--sys/arch/octeon/compile/BOOT/Makefile1
-rw-r--r--sys/arch/octeon/conf/BOOT70
-rw-r--r--sys/arch/octeon/conf/files.octeon5
-rw-r--r--sys/arch/octeon/dev/octboot.c387
-rw-r--r--sys/arch/octeon/include/conf.h10
-rw-r--r--sys/arch/octeon/include/octboot.h35
-rw-r--r--sys/arch/octeon/include/octeonvar.h9
-rw-r--r--sys/arch/octeon/octeon/conf.c5
-rw-r--r--sys/arch/octeon/octeon/locore.S14
-rw-r--r--sys/arch/octeon/octeon/machdep.c243
-rw-r--r--sys/arch/octeon/stand/rdboot/Makefile16
-rw-r--r--sys/arch/octeon/stand/rdboot/cmd.c503
-rw-r--r--sys/arch/octeon/stand/rdboot/cmd.h65
-rw-r--r--sys/arch/octeon/stand/rdboot/disk.c207
-rw-r--r--sys/arch/octeon/stand/rdboot/disk.h21
-rw-r--r--sys/arch/octeon/stand/rdboot/rdboot.c192
-rw-r--r--sys/arch/octeon/stand/rdboot/vars.c203
20 files changed, 2056 insertions, 10 deletions
diff --git a/distrib/octeon/boot/Makefile b/distrib/octeon/boot/Makefile
new file mode 100644
index 00000000000..9d9e619bb65
--- /dev/null
+++ b/distrib/octeon/boot/Makefile
@@ -0,0 +1,65 @@
+# $OpenBSD: Makefile,v 1.1 2019/07/17 14:36:32 visa Exp $
+
+FS= miniroot${OSrev}.fs
+FSSIZE= 24576
+FSDISKTYPE= miniroot
+MOUNT_POINT= /mnt
+MTREE= ${UTILS}/mtree.conf
+RAMDISK= BOOT
+
+LISTS= ${.CURDIR}/list
+UTILS= ${.CURDIR}/../../miniroot
+
+MRDISKTYPE= rdroot
+MRMAKEFSARGS= -o disklabel=${MRDISKTYPE},minfree=0,density=4096
+
+all: bsd.rd
+
+bsd.rd: mr.fs bsd
+ cp bsd bsd.rd
+ rdsetroot bsd.rd mr.fs
+
+bsd:
+ cd ${.CURDIR}/../../../sys/arch/${MACHINE}/compile/${RAMDISK} && \
+ su ${BUILDUSER} -c '${MAKE} config && ${MAKE} clean && exec ${MAKE}'
+ cp -p ${.CURDIR}/../../../sys/arch/${MACHINE}/compile/${RAMDISK}/obj/bsd bsd
+
+mr.fs: rdboot
+ rm -rf $@.d
+ install -d -o root -g wheel $@.d
+ mtree -def ${MTREE} -p $@.d -u
+ CURDIR=${.CURDIR} OBJDIR=${.OBJDIR} OSrev=${OSrev} \
+ TARGDIR=$@.d UTILS=${UTILS} RELEASEDIR=${RELEASEDIR} \
+ sh ${UTILS}/runlist.sh ${LISTS}
+ makefs ${MRMAKEFSARGS} $@ $@.d
+
+instbin.mk instbin.cache instbin.c: instbin.conf
+ crunchgen -E -M -D ${.CURDIR}/../../.. -L ${DESTDIR}/usr/lib \
+ -c instbin.c -e instbin -m instbin.mk instbin.conf
+
+instbin: instbin.mk instbin.cache instbin.c
+ ${MAKE} -f instbin.mk SRCLIBDIR=${.CURDIR}/../../../lib all
+
+instbin.conf: ${LISTS}
+ awk -f ${UTILS}/makeconf.awk ${LISTS} > instbin.conf
+
+rdboot:
+ cp -p ${.CURDIR}/../../../sys/arch/${MACHINE}/stand/rdboot/obj/rdboot rdboot
+ strip rdboot
+
+unconfig:
+ -umount -f ${MOUNT_POINT}
+ -[ -f vnd ] && vnconfig -u `cat vnd` && rm -f vnd
+
+.ifdef RELEASEDIR
+install:
+ cp bsd.rd ${RELEASEDIR}/boot
+ chmod a+r ${RELEASEDIR}/boot
+.endif
+
+clean cleandir:
+ rm -f *.core mr.fs instbin instbin.mk instbin.cache \
+ lib*.a lib*.olist instbin.map *.o *.lo *.c bsd bsd.rd rdboot
+ rm -rf cd-dir mr.fs.d
+
+.include <bsd.obj.mk>
diff --git a/distrib/octeon/boot/list b/distrib/octeon/boot/list
new file mode 100644
index 00000000000..8bc8325c46e
--- /dev/null
+++ b/distrib/octeon/boot/list
@@ -0,0 +1,9 @@
+# $OpenBSD: list,v 1.1 2019/07/17 14:36:32 visa Exp $
+
+SRCDIRS distrib/special
+
+COPY ${OBJDIR}/rdboot sbin/init
+
+# copy the MAKEDEV script and make some devices
+SCRIPT ${DESTDIR}/dev/MAKEDEV dev/MAKEDEV
+SPECIAL cd dev; sh MAKEDEV boot
diff --git a/etc/etc.octeon/MAKEDEV.md b/etc/etc.octeon/MAKEDEV.md
index d5f61418c60..173fb01913d 100644
--- a/etc/etc.octeon/MAKEDEV.md
+++ b/etc/etc.octeon/MAKEDEV.md
@@ -1,6 +1,6 @@
define(MACHINE,octeon)dnl
vers(__file__,
- {-$OpenBSD: MAKEDEV.md,v 1.13 2016/09/04 15:38:59 naddy Exp $-},
+ {-$OpenBSD: MAKEDEV.md,v 1.14 2019/07/17 14:36:31 visa Exp $-},
etc.MACHINE)dnl
dnl
dnl Copyright (c) 2001-2006 Todd T. Fries <todd@OpenBSD.org>
@@ -86,6 +86,10 @@ _DEV(switch, 75)
dnl
divert(__mddivert)dnl
dnl
+boot)
+ _recurse ramdisk random
+ M octboot c 21 0 600
+ ;;
_std(2, 3, 35, 6)
M openprom c 20 0 600
;;
diff --git a/sys/arch/octeon/compile/BOOT/Makefile b/sys/arch/octeon/compile/BOOT/Makefile
new file mode 100644
index 00000000000..01b5f23410c
--- /dev/null
+++ b/sys/arch/octeon/compile/BOOT/Makefile
@@ -0,0 +1 @@
+.include "../Makefile.inc"
diff --git a/sys/arch/octeon/conf/BOOT b/sys/arch/octeon/conf/BOOT
new file mode 100644
index 00000000000..fc1516290e6
--- /dev/null
+++ b/sys/arch/octeon/conf/BOOT
@@ -0,0 +1,70 @@
+# $OpenBSD: BOOT,v 1.1 2019/07/17 14:36:32 visa Exp $
+
+machine octeon mips64
+maxusers 4
+
+option TIMEZONE=0
+option DST=0
+option SMALL_KERNEL
+option NO_PROPOLICE
+
+option RAMDISK_HOOKS
+option MINIROOTSIZE=10240
+
+option PCIVERBOSE
+option USBVERBOSE
+
+option FFS
+option FFS2
+
+option CPU_MIPS64R2
+option CPU_OCTEON
+option FPUEMUL
+makeoption LINK_ADDRESS="0xffffffff82000000"
+
+config bsd root on rd0a swap on rd0b
+
+mainbus0 at root
+cpu0 at mainbus0
+clock0 at mainbus0
+iobus0 at mainbus0
+octcf0 at iobus0
+amdcf0 at iobus0
+
+simplebus* at fdt?
+simplebus* at iobus?
+
+com* at fdt_octeon?
+octcib* at fdt? # Interrupt controller
+octcit* at fdt? # Interrupt controller v3
+octciu* at fdt? # Interrupt controller v1
+octmmc* at fdt? # MMC host controller
+sdmmc* at octmmc? # SD/MMC bus
+
+# AHCI controllers
+octsctl* at fdt?
+ahci* at octsctl?
+
+dwctwo0 at iobus0 irq 56
+octuctl* at fdt?
+octxctl* at fdt?
+ehci0 at octuctl?
+ohci0 at octuctl?
+xhci* at octxctl?
+
+usb* at dwctwo?
+usb* at ehci?
+usb* at ohci?
+usb* at xhci?
+
+uhub* at usb?
+uhub* at uhub?
+umass* at uhub?
+
+scsibus* at scsi?
+sd* at scsibus?
+
+pseudo-device etherip # pulls ether in kernel
+pseudo-device octboot 1
+pseudo-device rd 1
+pseudo-device wsmux 2
diff --git a/sys/arch/octeon/conf/files.octeon b/sys/arch/octeon/conf/files.octeon
index 90cf58cedb3..36a195257d7 100644
--- a/sys/arch/octeon/conf/files.octeon
+++ b/sys/arch/octeon/conf/files.octeon
@@ -1,4 +1,4 @@
-# $OpenBSD: files.octeon,v 1.50 2019/04/23 13:53:46 visa Exp $
+# $OpenBSD: files.octeon,v 1.51 2019/07/17 14:36:32 visa Exp $
# Standard stanzas config(8) can't run without
maxpartitions 16
@@ -165,5 +165,8 @@ device octxctl: fdt
attach octxctl at fdt
file arch/octeon/dev/octxctl.c octxctl
+pseudo-device octboot
+file arch/octeon/dev/octboot.c octboot needs-flag
+
pseudo-device openprom
file arch/octeon/octeon/openprom.c openprom needs-flag
diff --git a/sys/arch/octeon/dev/octboot.c b/sys/arch/octeon/dev/octboot.c
new file mode 100644
index 00000000000..659b165e632
--- /dev/null
+++ b/sys/arch/octeon/dev/octboot.c
@@ -0,0 +1,387 @@
+/* $OpenBSD: octboot.c,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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec_elf.h>
+#include <sys/malloc.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <mips64/memconf.h>
+
+#include <machine/autoconf.h>
+#include <machine/octboot.h>
+#include <machine/octeonvar.h>
+
+typedef void (*kentry)(register_t, register_t, register_t, register_t);
+#define PRIMARY 1
+
+int octboot_kexec(struct octboot_kexec_args *, struct proc *);
+int octboot_read(struct proc *, struct vnode *, void *, size_t, off_t);
+
+uint64_t octeon_boot_entry;
+uint32_t octeon_boot_ready;
+
+void
+octbootattach(int num)
+{
+}
+
+int
+octbootopen(dev_t dev, int flags, int mode, struct proc *p)
+{
+ return (0);
+}
+
+int
+octbootclose(dev_t dev, int flags, int mode, struct proc *p)
+{
+ return (0);
+}
+
+int
+octbootioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ int error = 0;
+
+ switch (cmd) {
+ case OBIOC_GETROOTDEV:
+ if (strlen(uboot_rootdev) == 0) {
+ error = ENOENT;
+ break;
+ }
+ strlcpy((char *)data, uboot_rootdev, PATH_MAX);
+ break;
+
+ case OBIOC_KEXEC:
+ error = suser(p);
+ if (error != 0)
+ break;
+ error = octboot_kexec((struct octboot_kexec_args *)data, p);
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ return error;
+}
+
+int
+octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p)
+{
+ extern char start[], end[];
+ Elf_Ehdr eh;
+ Elf_Phdr *ph = NULL;
+ Elf_Shdr *sh = NULL;
+ struct nameidata nid;
+ struct vattr va;
+ paddr_t ekern = 0, elfp, maxp = 0, off, pa, shp;
+ size_t len, phsize, shsize, shstrsize, size;
+ char *argbuf = NULL, *argptr;
+ char *shstr = NULL;
+ int argc = 0, error, havesyms = 0, i, nalloc = 0;
+
+ NDINIT(&nid, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, kargs->path, p);
+ error = namei(&nid);
+ if (error != 0)
+ return error;
+ error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p);
+ if (error != 0)
+ goto fail;
+ if (nid.ni_vp->v_type != VREG || va.va_size == 0) {
+ error = EINVAL;
+ goto fail;
+ }
+ error = VOP_ACCESS(nid.ni_vp, VREAD, p->p_ucred, p);
+ if (error != 0)
+ goto fail;
+
+ /*
+ * Load kernel arguments into a temporary buffer.
+ * This also translates the userspace argv pointers to kernel pointers.
+ */
+ argbuf = malloc(PAGE_SIZE, M_TEMP, M_NOWAIT);
+ if (argbuf == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+ argptr = argbuf;
+ for (i = 0; i < OCTBOOT_MAX_ARGS && kargs->argv[i] != NULL; i++) {
+ len = argbuf + PAGE_SIZE - argptr;
+ error = copyinstr(kargs->argv[i], argptr, len, &len);
+ if (error != 0)
+ goto fail;
+ kargs->argv[i] = argptr;
+ argptr += len;
+ argc++;
+ }
+
+ /*
+ * Read the headers and validate them.
+ */
+ error = octboot_read(p, nid.ni_vp, &eh, sizeof(eh), 0);
+ if (error != 0)
+ goto fail;
+
+ /* Load program headers. */
+ ph = mallocarray(eh.e_phnum, sizeof(Elf_Phdr), M_TEMP, M_NOWAIT);
+ if (ph == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+ phsize = eh.e_phnum * sizeof(Elf_Phdr);
+ error = octboot_read(p, nid.ni_vp, ph, phsize, eh.e_phoff);
+ if (error != 0)
+ goto fail;
+
+ /* Load section headers. */
+ sh = mallocarray(eh.e_shnum, sizeof(Elf_Shdr), M_TEMP, M_NOWAIT);
+ if (sh == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+ shsize = eh.e_shnum * sizeof(Elf_Shdr);
+ error = octboot_read(p, nid.ni_vp, sh, shsize, eh.e_shoff);
+ if (error != 0)
+ goto fail;
+
+ /* Sanity-check addresses. */
+ for (i = 0; i < eh.e_phnum; i++) {
+ if (ph[i].p_type != PT_LOAD &&
+ ph[i].p_type != PT_OPENBSD_RANDOMIZE)
+ continue;
+ if (ph[i].p_paddr < CKSEG0_BASE ||
+ ph[i].p_paddr + ph[i].p_memsz >= CKSEG0_BASE + CKSEG_SIZE) {
+ error = ENOEXEC;
+ goto fail;
+ }
+ }
+
+ /*
+ * Allocate physical memory and load the segments.
+ */
+
+ for (i = 0; i < eh.e_phnum; i++) {
+ if (ph[i].p_type != PT_LOAD)
+ continue;
+ pa = CKSEG0_TO_PHYS(ph[i].p_paddr);
+ size = roundup(ph[i].p_memsz, BOOTMEM_BLOCK_ALIGN);
+ if (bootmem_alloc_region(pa, size) != 0) {
+ printf("kexec: failed to allocate segment "
+ "0x%lx @ 0x%lx\n", size, pa);
+ error = ENOMEM;
+ goto fail;
+ }
+ if (maxp < pa + size)
+ maxp = pa + size;
+ nalloc++;
+ }
+
+ for (i = 0; i < eh.e_phnum; i++) {
+ if (ph[i].p_type == PT_OPENBSD_RANDOMIZE) {
+ /* Assume that the segment is inside a LOAD segment. */
+ arc4random_buf((caddr_t)ph[i].p_paddr, ph[i].p_filesz);
+ continue;
+ }
+
+ if (ph[i].p_type != PT_LOAD)
+ continue;
+
+ error = octboot_read(p, nid.ni_vp, (caddr_t)ph[i].p_paddr,
+ ph[i].p_filesz, ph[i].p_offset);
+ if (error != 0)
+ goto fail;
+
+ /* Clear any BSS. */
+ if (ph[i].p_memsz > ph[i].p_filesz) {
+ memset((caddr_t)ph[i].p_paddr + ph[i].p_filesz,
+ 0, ph[i].p_memsz - ph[i].p_filesz);
+ }
+ }
+ ekern = maxp;
+
+ for (i = 0; i < eh.e_shnum; i++) {
+ if (sh[i].sh_type == SHT_SYMTAB) {
+ havesyms = 1;
+ break;
+ }
+ }
+
+ if (havesyms) {
+ /* Reserve space for ssym and esym pointers. */
+ maxp += sizeof(int32_t) * 2;
+
+ elfp = roundup(maxp, sizeof(Elf_Addr));
+ maxp = elfp + sizeof(Elf_Ehdr);
+ shp = maxp;
+ maxp = shp + roundup(shsize, sizeof(Elf_Addr));
+ maxp = roundup(maxp, BOOTMEM_BLOCK_ALIGN);
+ if (bootmem_alloc_region(ekern, maxp - ekern) != 0) {
+ printf("kexec: failed to allocate %zu bytes for ELF "
+ "and section headers\n", maxp - ekern);
+ error = ENOMEM;
+ goto fail;
+ }
+
+ shstrsize = sh[eh.e_shstrndx].sh_size;
+ shstr = malloc(shstrsize, M_TEMP, M_NOWAIT);
+ if (shstr == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+ error = octboot_read(p, nid.ni_vp, shstr, shstrsize,
+ sh[eh.e_shstrndx].sh_offset);
+ if (error != 0)
+ goto fail;
+
+ off = roundup(sizeof(Elf_Ehdr) + shsize, sizeof(Elf_Addr));
+ off = maxp - elfp;
+ for (i = 0; i < eh.e_shnum; i++) {
+ if (sh[i].sh_type == SHT_STRTAB ||
+ sh[i].sh_type == SHT_SYMTAB ||
+ strcmp(shstr + sh[i].sh_name, ELF_CTF) == 0 ||
+ strcmp(shstr + sh[i].sh_name, ".debug_line") == 0) {
+ size_t bsize = roundup(sh[i].sh_size,
+ BOOTMEM_BLOCK_ALIGN);
+
+ if (bootmem_alloc_region(maxp, bsize) != 0) {
+ error = ENOMEM;
+ goto fail;
+ }
+ error = octboot_read(p, nid.ni_vp,
+ (caddr_t)PHYS_TO_CKSEG0(maxp),
+ sh[i].sh_size, sh[i].sh_offset);
+ maxp += bsize;
+ if (error != 0)
+ goto fail;
+ sh[i].sh_offset = off;
+ sh[i].sh_flags |= SHF_ALLOC;
+ off += bsize;
+ }
+ }
+
+ eh.e_phoff = 0;
+ eh.e_shoff = sizeof(eh);
+ eh.e_phentsize = 0;
+ eh.e_phnum = 0;
+ memcpy((caddr_t)PHYS_TO_CKSEG0(elfp), &eh, sizeof(eh));
+ memcpy((caddr_t)PHYS_TO_CKSEG0(shp), sh, shsize);
+
+ *(int32_t *)PHYS_TO_CKSEG0(ekern) = PHYS_TO_CKSEG0(elfp);
+ *((int32_t *)PHYS_TO_CKSEG0(ekern) + 1) = PHYS_TO_CKSEG0(maxp);
+ }
+
+ /*
+ * Put kernel arguments in place.
+ */
+ octeon_boot_desc->argc = 0;
+ for (i = 0; i < OCTEON_ARGV_MAX; i++)
+ octeon_boot_desc->argv[i] = 0;
+ if (argptr > argbuf) {
+ size = roundup(argptr - argbuf, BOOTMEM_BLOCK_ALIGN);
+ if (bootmem_alloc_region(maxp, size) != 0) {
+ error = ENOMEM;
+ goto fail;
+ }
+ memcpy((caddr_t)PHYS_TO_CKSEG0(maxp), argbuf, argptr - argbuf);
+ for (i = 0; i < argc; i++) {
+ KASSERT(kargs->argv[i] >= argbuf);
+ KASSERT(kargs->argv[i] < argbuf + PAGE_SIZE);
+ octeon_boot_desc->argv[i] = kargs->argv[i] - argbuf +
+ maxp;
+ }
+ octeon_boot_desc->argc = argc;
+ maxp += size;
+ }
+
+ printf("launching kernel\n");
+
+ config_suspend_all(DVACT_POWERDOWN);
+
+ intr_disable();
+
+ /* Put UVM memory back to the free list. */
+ for (i = 0; mem_layout[i].mem_last_page != 0; i++) {
+ uint64_t fp = mem_layout[i].mem_first_page;
+ uint64_t lp = mem_layout[i].mem_last_page;
+
+ bootmem_free(ptoa(fp), ptoa(lp) - ptoa(fp));
+ }
+
+ /*
+ * Release the memory of the bootloader kernel.
+ * This may overwrite a tiny region at the start of the running image.
+ */
+ bootmem_free(CKSEG0_TO_PHYS((vaddr_t)start), end - start);
+
+ /* Let secondary cores proceed to the new kernel. */
+ octeon_boot_entry = eh.e_entry;
+ octeon_syncw(); /* Order writes. */
+ octeon_boot_ready = 1; /* Open the gate. */
+ octeon_syncw(); /* Flush writes. */
+ delay(1000); /* Give secondary cores a lead. */
+
+ __asm__ volatile (
+ " cache 1, 0($0)\n" /* Flush and invalidate dcache. */
+ " cache 0, 0($0)\n" /* Invalidate icache. */
+ ::: "memory");
+
+ (*(kentry)eh.e_entry)(0, 0, PRIMARY, (register_t)octeon_boot_desc);
+
+ for (;;)
+ continue;
+
+fail:
+ if (ekern != 0)
+ bootmem_free(ekern, maxp - ekern);
+ for (i = 0; i < eh.e_phnum && nalloc > 0; i++) {
+ if (ph[i].p_type == PT_LOAD) {
+ pa = CKSEG0_TO_PHYS(ph[i].p_paddr);
+ bootmem_free(pa, ph[i].p_memsz);
+ nalloc--;
+ }
+ }
+ free(shstr, M_TEMP, shstrsize);
+ free(sh, M_TEMP, shsize);
+ free(ph, M_TEMP, phsize);
+ free(argbuf, M_TEMP, PAGE_SIZE);
+ vput(nid.ni_vp);
+ return error;
+}
+
+int
+octboot_read(struct proc *p, struct vnode *vp, void *buf, size_t size,
+ off_t off)
+{
+ size_t resid;
+ int error;
+
+ error = vn_rdwr(UIO_READ, vp, buf, size, off, UIO_SYSSPACE, 0,
+ p->p_ucred, &resid, p);
+ if (error != 0)
+ return error;
+ if (resid != 0)
+ return ENOEXEC;
+ return 0;
+}
diff --git a/sys/arch/octeon/include/conf.h b/sys/arch/octeon/include/conf.h
index e84bc9ea15a..a954a3fa714 100644
--- a/sys/arch/octeon/include/conf.h
+++ b/sys/arch/octeon/include/conf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.h,v 1.2 2016/07/05 12:53:40 visa Exp $ */
+/* $OpenBSD: conf.h,v 1.3 2019/07/17 14:36:32 visa Exp $ */
/* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */
/*
@@ -36,12 +36,20 @@
#include <sys/conf.h>
/* open, close, ioctl */
+#define cdev_octboot_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) nullop, 0, selfalse, \
+ (dev_type_mmap((*))) enodev }
+
+/* open, close, ioctl */
#define cdev_openprom_init(c,n) { \
dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
(dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
(dev_type_stop((*))) nullop, 0, selfalse, \
(dev_type_mmap((*))) enodev }
+cdev_decl(octboot);
cdev_decl(openprom);
#endif /* _OCTEON_CONF_H_ */
diff --git a/sys/arch/octeon/include/octboot.h b/sys/arch/octeon/include/octboot.h
new file mode 100644
index 00000000000..60c9f300169
--- /dev/null
+++ b/sys/arch/octeon/include/octboot.h
@@ -0,0 +1,35 @@
+/* $OpenBSD: octboot.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.
+ */
+
+#ifndef _OCTEON_OCTBOOT_H_
+#define _OCTEON_OCTBOOT_H_
+
+#include <sys/ioccom.h>
+
+#define OCTBOOT_MAX_ARGS 8 /* maximum number of boot arguments */
+
+struct octboot_kexec_args {
+ const char *path; /* kernel path */
+ char *argv[OCTBOOT_MAX_ARGS];
+ /* kernel boot arguments */
+};
+
+#define OBIOC_KEXEC _IOW('O', 1, struct octboot_kexec_args)
+#define OBIOC_GETROOTDEV _IOR('O', 2, char[PATH_MAX])
+
+#endif /* !_OCTEON_OCTBOOT_H_ */
diff --git a/sys/arch/octeon/include/octeonvar.h b/sys/arch/octeon/include/octeonvar.h
index 6e645788059..1e2c221dd02 100644
--- a/sys/arch/octeon/include/octeonvar.h
+++ b/sys/arch/octeon/include/octeonvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: octeonvar.h,v 1.45 2018/04/09 13:46:15 visa Exp $ */
+/* $OpenBSD: octeonvar.h,v 1.46 2019/07/17 14:36:32 visa Exp $ */
/* $NetBSD: maltavar.h,v 1.3 2002/03/18 10:10:16 simonb Exp $ */
/*-
@@ -272,6 +272,13 @@ extern struct boot_info *octeon_boot_info;
#define BOOTINFO_CFG_FLAG_DEBUG (1ull << 2)
#define BOOTINFO_CFG_FLAG_NO_MAGIC (1ull << 3)
+#define BOOTMEM_BLOCK_ALIGN 16
+#define BOOTMEM_BLOCK_MASK (BOOTMEM_BLOCK_ALIGN - 1)
+#define BOOTMEM_BLOCK_MIN_SIZE 16
+
+int bootmem_alloc_region(paddr_t, size_t);
+void bootmem_free(paddr_t, size_t);
+
int octeon_ioclock_speed(void);
#endif /* _KERNEL */
diff --git a/sys/arch/octeon/octeon/conf.c b/sys/arch/octeon/octeon/conf.c
index bdf9353e534..6b96db3daab 100644
--- a/sys/arch/octeon/octeon/conf.c
+++ b/sys/arch/octeon/octeon/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.20 2016/09/04 10:51:24 naddy Exp $ */
+/* $OpenBSD: conf.c,v 1.21 2019/07/17 14:36:32 visa Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -140,6 +140,7 @@ cdev_decl(pci);
#include "vscsi.h"
#include "pppx.h"
#include "fuse.h"
+#include "octboot.h"
#include "openprom.h"
#include "switch.h"
@@ -170,7 +171,7 @@ struct cdevsw cdevsw[] =
cdev_disk_init(NWD,wd), /* 18: ST506/ESDI/IDE disk */
cdev_disk_init(NAMDCF,amdcf), /* 19: CF disk */
cdev_openprom_init(NOPENPROM,openprom), /* 20: /dev/openprom */
- cdev_notdef(), /* 21: */
+ cdev_octboot_init(NOCTBOOT,octboot), /* 21: /dev/octboot */
cdev_disk_init(NRD,rd), /* 22: ramdisk device */
cdev_notdef(), /* 23: was: concatenated disk driver */
cdev_notdef(), /* 24: */
diff --git a/sys/arch/octeon/octeon/locore.S b/sys/arch/octeon/octeon/locore.S
index 32667171a6b..96e6b7534bf 100644
--- a/sys/arch/octeon/octeon/locore.S
+++ b/sys/arch/octeon/octeon/locore.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.S,v 1.19 2019/05/06 17:13:22 visa Exp $ */
+/* $OpenBSD: locore.S,v 1.20 2019/07/17 14:36:32 visa Exp $ */
/*
* Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -37,6 +37,7 @@
#include <octeon/dev/cn30xxcorereg.h>
#include "assym.h"
+#include "octboot.h"
#define RNG_CONTROL_ADDR 0x9001180040000000
#define RNG_CONTROL_ENABLE 0x3
@@ -88,6 +89,17 @@ locore_start:
nop
j hw_cpu_spinup_trampoline
nop
+#elif NOCTBOOT > 0
+ LA t0, octeon_boot_ready
+1: lw t1, (t0)
+ beq t1, zero, 1b
+ nop
+
+ LA t0, octeon_boot_entry
+ ld t0, (t0) # get entry point
+ cache 1, 0(zero) # flush and invalidate dcache
+ jr t0
+ cache 0, 0(zero) # invalidate icache
#else
/* Halt extra cores on single-processor kernel. */
1: wait
diff --git a/sys/arch/octeon/octeon/machdep.c b/sys/arch/octeon/octeon/machdep.c
index 2adb012c0c5..ef27fb00932 100644
--- a/sys/arch/octeon/octeon/machdep.c
+++ b/sys/arch/octeon/octeon/machdep.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: machdep.c,v 1.114 2019/07/12 03:09:23 visa Exp $ */
+/* $OpenBSD: machdep.c,v 1.115 2019/07/17 14:36:32 visa Exp $ */
/*
* Copyright (c) 2009, 2010 Miodrag Vallat.
+ * Copyright (c) 2019 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
@@ -86,6 +87,8 @@
#include <machine/octeonvar.h>
#include <machine/octeon_model.h>
+#include "octboot.h"
+
/* The following is used externally (sysctl_hw) */
char machine[] = MACHINE; /* Machine "architecture" */
char cpu_model[64];
@@ -152,6 +155,12 @@ struct timecounter ioclock_timecounter = {
* determined at runtime */
};
+static struct octeon_bootmem_block *
+pa_to_block(paddr_t addr)
+{
+ return (struct octeon_bootmem_block *)PHYS_TO_XKPHYS(addr, CCA_CACHED);
+}
+
void
octeon_memory_init(struct boot_info *boot_info)
{
@@ -178,11 +187,23 @@ octeon_memory_init(struct boot_info *boot_info)
if (blockaddr == 0)
panic("bootmem list is empty");
for (i = 0; i < MAXMEMSEGS && blockaddr != 0; blockaddr = block->next) {
- block = (struct octeon_bootmem_block *)PHYS_TO_XKPHYS(
- blockaddr, CCA_CACHED);
+ block = pa_to_block(blockaddr);
printf("avail phys mem 0x%016lx - 0x%016lx\n", blockaddr,
(paddr_t)(blockaddr + block->size));
+#if NOCTBOOT > 0
+ /*
+ * Reserve the physical memory below the boot kernel
+ * for loading the actual kernel.
+ */
+ extern char start[];
+ if (blockaddr < CKSEG_SIZE &&
+ PHYS_TO_CKSEG0(blockaddr) < (vaddr_t)start) {
+ printf("skipped\n");
+ continue;
+ }
+#endif
+
fp = atop(round_page(blockaddr));
lp = atop(trunc_page(blockaddr + block->size));
@@ -209,6 +230,13 @@ octeon_memory_init(struct boot_info *boot_info)
for (i = 0; mem_layout[i].mem_last_page; i++) {
printf("mem_layout[%d] page 0x%016llX -> 0x%016llX\n", i,
mem_layout[i].mem_first_page, mem_layout[i].mem_last_page);
+
+#if NOCTBOOT > 0
+ fp = mem_layout[i].mem_first_page;
+ lp = mem_layout[i].mem_last_page;
+ if (bootmem_alloc_region(ptoa(fp), ptoa(lp) - ptoa(fp)) != 0)
+ panic("%s: bootmem allocation failed", __func__);
+#endif
}
}
@@ -898,6 +926,215 @@ ioclock_get_timecount(struct timecounter *tc)
return octeon_xkphys_read_8(reg);
}
+#if NOCTBOOT > 0
+static uint64_t
+size_trunc(uint64_t size)
+{
+ return (size & ~BOOTMEM_BLOCK_MASK);
+}
+
+void
+bootmem_dump(void)
+{
+ struct octeon_bootmem_desc *memdesc = (struct octeon_bootmem_desc *)
+ PHYS_TO_XKPHYS(octeon_boot_info->phys_mem_desc_addr, CCA_CACHED);
+ struct octeon_bootmem_block *block;
+ paddr_t pa;
+
+ pa = memdesc->head_addr;
+ while (pa != 0) {
+ block = pa_to_block(pa);
+ printf("free 0x%lx - 0x%lx\n", pa, pa + (size_t)block->size);
+ pa = block->next;
+ }
+}
+
+/*
+ * Allocate the given region from the free memory list.
+ */
+int
+bootmem_alloc_region(paddr_t pa, size_t size)
+{
+ struct octeon_bootmem_desc *memdesc = (struct octeon_bootmem_desc *)
+ PHYS_TO_XKPHYS(octeon_boot_info->phys_mem_desc_addr, CCA_CACHED);
+ struct octeon_bootmem_block *block, *next, nblock;
+ paddr_t bpa;
+
+ if (pa == 0 || size < BOOTMEM_BLOCK_MIN_SIZE ||
+ (pa & BOOTMEM_BLOCK_MASK) != 0 ||
+ (size & BOOTMEM_BLOCK_MASK) != 0)
+ return EINVAL;
+
+ if (memdesc->head_addr == 0 || pa < memdesc->head_addr)
+ return ENOMEM;
+
+ /* Check if the region is at the head of the free list. */
+ if (pa == memdesc->head_addr) {
+ block = pa_to_block(memdesc->head_addr);
+ if (block->size < size)
+ return ENOMEM;
+ if (size_trunc(block->size) == size) {
+ memdesc->head_addr = block->next;
+ } else {
+ KASSERT(block->size > size);
+ nblock.next = block->next;
+ nblock.size = block->size - size;
+ KASSERT(nblock.size >= BOOTMEM_BLOCK_MIN_SIZE);
+ memdesc->head_addr += size;
+ *pa_to_block(memdesc->head_addr) = nblock;
+ }
+ return 0;
+ }
+
+ /* Find the block that immediately precedes or is at `pa'. */
+ bpa = memdesc->head_addr;
+ block = pa_to_block(bpa);
+ while (block->next != 0 && block->next < pa) {
+ bpa = block->next;
+ block = pa_to_block(bpa);
+ }
+
+ /* Refuse to play if the block is not properly aligned. */
+ if ((bpa & BOOTMEM_BLOCK_MASK) != 0)
+ return ENOMEM;
+
+ if (block->next == pa) {
+ next = pa_to_block(block->next);
+ if (next->size < size)
+ return ENOMEM;
+ if (size_trunc(next->size) == size) {
+ block->next = next->next;
+ } else {
+ KASSERT(next->size > size);
+ nblock.next = next->next;
+ nblock.size = next->size - size;
+ KASSERT(nblock.size >= BOOTMEM_BLOCK_MIN_SIZE);
+ block->next += size;
+ *pa_to_block(block->next) = nblock;
+ }
+ } else {
+ KASSERT(bpa < pa);
+ KASSERT(block->next == 0 || block->next > pa);
+
+ if (bpa + block->size < pa + size)
+ return ENOMEM;
+ if (bpa + size_trunc(block->size) == pa + size) {
+ block->size = pa - bpa;
+ } else {
+ KASSERT(bpa + block->size > pa + size);
+ nblock.next = block->next;
+ nblock.size = block->size - (pa - bpa) - size;
+ KASSERT(nblock.size >= BOOTMEM_BLOCK_MIN_SIZE);
+ block->next = pa + size;
+ block->size = pa - bpa;
+ *pa_to_block(block->next) = nblock;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Release the given region to the free memory list.
+ */
+void
+bootmem_free(paddr_t pa, size_t size)
+{
+ struct octeon_bootmem_desc *memdesc = (struct octeon_bootmem_desc *)
+ PHYS_TO_XKPHYS(octeon_boot_info->phys_mem_desc_addr, CCA_CACHED);
+ struct octeon_bootmem_block *block, *next, *prev;
+ paddr_t prevpa;
+
+ if (pa == 0 || size < BOOTMEM_BLOCK_MIN_SIZE ||
+ (pa & BOOTMEM_BLOCK_MASK) != 0 ||
+ (size & BOOTMEM_BLOCK_MASK) != 0)
+ panic("%s: invalid block 0x%lx @ 0x%lx", __func__, size, pa);
+
+ /* If the list is empty, insert at the head. */
+ if (memdesc->head_addr == 0) {
+ block = pa_to_block(pa);
+ block->next = 0;
+ block->size = size;
+ memdesc->head_addr = pa;
+ return;
+ }
+
+ /* If the block precedes the current head, insert before, or merge. */
+ if (pa <= memdesc->head_addr) {
+ block = pa_to_block(pa);
+ if (pa + size < memdesc->head_addr) {
+ block->next = memdesc->head_addr;
+ block->size = size;
+ memdesc->head_addr = pa;
+ } else if (pa + size == memdesc->head_addr) {
+ next = pa_to_block(memdesc->head_addr);
+ block->next = next->next;
+ block->size = next->size + size;
+ memdesc->head_addr = pa;
+ } else {
+ panic("%s: overlap 1: 0x%lx @ 0x%lx / 0x%llx @ 0x%llx",
+ __func__, size, pa,
+ pa_to_block(memdesc->head_addr)->size,
+ memdesc->head_addr);
+ }
+ return;
+ }
+
+ /* Find the immediate predecessor. */
+ prevpa = memdesc->head_addr;
+ prev = pa_to_block(prevpa);
+ while (prev->next != 0 && prev->next < pa) {
+ prevpa = prev->next;
+ prev = pa_to_block(prevpa);
+ }
+ if (prevpa + prev->size > pa) {
+ panic("%s: overlap 2: 0x%llx @ 0x%lx / 0x%lx @ 0x%lx",
+ __func__, prev->size, prevpa, size, pa);
+ }
+
+ /* Merge with or insert after the predecessor. */
+ if (prevpa + prev->size == pa) {
+ if (prev->next == 0) {
+ prev->size += size;
+ return;
+ }
+ next = pa_to_block(prev->next);
+ if (prevpa + prev->size + size < prev->next) {
+ prev->size += size;
+ } else if (prevpa + prev->size + size == prev->next) {
+ prev->next = next->next;
+ prev->size += size + next->size;
+ } else {
+ panic("%s: overlap 3: 0x%llx @ 0x%lx / 0x%lx @ 0x%lx / "
+ "0x%llx @ 0x%llx", __func__,
+ prev->size, prevpa, size, pa,
+ next->size, prev->next);
+ }
+ } else {
+ /* The block is disjoint with prev. */
+ KASSERT(prevpa + prev->size < pa);
+
+ block = pa_to_block(pa);
+ if (pa + size < prev->next || prev->next == 0) {
+ block->next = prev->next;
+ block->size = size;
+ prev->next = pa;
+ } else if (pa + size == prev->next) {
+ next = pa_to_block(prev->next);
+ block->next = next->next;
+ block->size = next->size + size;
+ prev->next = pa;
+ } else {
+ next = pa_to_block(prev->next);
+ panic("%s: overlap 4: 0x%llx @ 0x%lx / "
+ "0x%lx @ 0x%lx / 0x%llx @ 0x%llx",
+ __func__, prev->size, prevpa, size, pa,
+ next->size, prev->next);
+ }
+ }
+}
+#endif /* NOCTBOOT > 0 */
+
#ifdef MULTIPROCESSOR
uint32_t cpu_spinup_mask = 0;
uint64_t cpu_spinup_a0, cpu_spinup_sp;
diff --git a/sys/arch/octeon/stand/rdboot/Makefile b/sys/arch/octeon/stand/rdboot/Makefile
new file mode 100644
index 00000000000..38f01e78ef6
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/Makefile
@@ -0,0 +1,16 @@
+# $OpenBSD: Makefile,v 1.1 2019/07/17 14:36:32 visa Exp $
+
+NOMAN=
+
+.if ${MACHINE} == "octeon"
+PROG= rdboot
+SRCS= cmd.c disk.c rdboot.c vars.c
+LDADD+= -lutil
+LDSTATIC+= -static
+.else
+NOPROG=
+.endif
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/octeon/stand/rdboot/cmd.c b/sys/arch/octeon/stand/rdboot/cmd.c
new file mode 100644
index 00000000000..85c8a28e238
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/cmd.c
@@ -0,0 +1,503 @@
+/* $OpenBSD: cmd.c,v 1.1 2019/07/17 14:36:32 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;
+ 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. */
+ strtok(buf, "\n");
+
+ 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);
+ }
+
+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
new file mode 100644
index 00000000000..1ffafde59ef
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/cmd.h
@@ -0,0 +1,65 @@
+/* $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
new file mode 100644
index 00000000000..cc943444c73
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/disk.c
@@ -0,0 +1,207 @@
+/* $OpenBSD: disk.c,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.
+ */
+
+#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_RDONLY, &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
new file mode 100644
index 00000000000..ac0d1879bb0
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/disk.h
@@ -0,0 +1,21 @@
+/* $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
new file mode 100644
index 00000000000..0b66162142e
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/rdboot.c
@@ -0,0 +1,192 @@
+/* $OpenBSD: rdboot.c,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.
+ */
+
+#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 <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <util.h>
+
+#include <machine/octboot.h>
+#include <machine/param.h>
+
+#include "cmd.h"
+#include "disk.h"
+
+#define DEVRANDOM "/dev/random"
+#define BOOTRANDOM "/etc/random.seed"
+#define BOOTRANDOM_MAX 512
+#define KERNEL "/bsd"
+
+void loadrandom(void);
+void kexec(void);
+
+struct cmd_state cmd;
+int octbootfd = -1;
+const char version[] = "1.0";
+
+int
+main(void)
+{
+ char rootdev[PATH_MAX];
+ int fd, hasboot;
+
+ fd = open(_PATH_CONSOLE, O_RDWR);
+ login_tty(fd);
+
+ /* Keep stdout unbuffered to mimic ordinary bootblocks. */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ printf(">> OpenBSD/" MACHINE " BOOT %s\n", version);
+
+ 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;
+
+ if (ioctl(octbootfd, OBIOC_GETROOTDEV, rootdev) == -1) {
+ if (errno != ENOENT)
+ fprintf(stderr, "cannot get rootdev from kernel: %s\n",
+ strerror(errno));
+ } else {
+ snprintf(cmd.bootdev, sizeof(cmd.bootdev), "%s%sa",
+ rootdev, isduid(rootdev, OPENDEV_PART) ? "." : "");
+ }
+
+ disk_init();
+
+ if (upgrade()) {
+ strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
+ printf("upgrade detected: switching to %s\n", cmd.image);
+ }
+
+ hasboot = read_conf();
+
+ for (;;) {
+ if (hasboot <= 0) {
+ do {
+ printf("boot> ");
+ } while (!getcmd());
+ }
+
+ loadrandom();
+ kexec();
+
+ hasboot = 0;
+ strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
+ printf("will try %s\n", cmd.image);
+ }
+
+ return 0;
+}
+
+void
+loadrandom(void)
+{
+ char buf[BOOTRANDOM_MAX];
+ int fd;
+
+ /* Read the file from the device specified by the kernel path. */
+ if (disk_open(cmd.path) == NULL)
+ return;
+ fd = open(BOOTRANDOM, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "%s: cannot open %s: %s", __func__, BOOTRANDOM,
+ strerror(errno));
+ disk_close();
+ return;
+ }
+ read(fd, buf, sizeof(buf));
+ 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;
+ }
+ write(fd, buf, sizeof(buf));
+ close(fd);
+}
+
+void
+kexec(void)
+{
+ struct octboot_kexec_args kargs;
+ char kernelflags[8];
+ char rootdev[32];
+ const char *path;
+ int argc, ret;
+
+ path = disk_open(cmd.path);
+ if (path == NULL)
+ return;
+
+ memset(&kargs, 0, sizeof(kargs));
+ kargs.path = path;
+ argc = 0;
+ if (cmd.boothowto != 0) {
+ snprintf(kernelflags, sizeof(kernelflags), "-%s%s%s%s",
+ (cmd.boothowto & RB_ASKNAME) ? "a" : "",
+ (cmd.boothowto & RB_CONFIG) ? "c" : "",
+ (cmd.boothowto & RB_KDB) ? "d" : "",
+ (cmd.boothowto & RB_SINGLE) ? "s" : "");
+ kargs.argv[argc++] = kernelflags;
+ }
+ if (cmd.hasduid) {
+ snprintf(rootdev, sizeof(rootdev),
+ "rootdev=%02x%02x%02x%02x%02x%02x%02x%02x",
+ cmd.bootduid[0], cmd.bootduid[1],
+ cmd.bootduid[2], cmd.bootduid[3],
+ cmd.bootduid[4], cmd.bootduid[5],
+ cmd.bootduid[6], cmd.bootduid[7]);
+ kargs.argv[argc++] = rootdev;
+ }
+
+ printf("booting %s\n", cmd.path);
+ ret = ioctl(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");
+
+ disk_close();
+}
diff --git a/sys/arch/octeon/stand/rdboot/vars.c b/sys/arch/octeon/stand/rdboot/vars.c
new file mode 100644
index 00000000000..926c8a6cb16
--- /dev/null
+++ b/sys/arch/octeon/stand/rdboot/vars.c
@@ -0,0 +1,203 @@
+/* $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;
+}