diff options
-rw-r--r-- | distrib/octeon/boot/Makefile | 65 | ||||
-rw-r--r-- | distrib/octeon/boot/list | 9 | ||||
-rw-r--r-- | etc/etc.octeon/MAKEDEV.md | 6 | ||||
-rw-r--r-- | sys/arch/octeon/compile/BOOT/Makefile | 1 | ||||
-rw-r--r-- | sys/arch/octeon/conf/BOOT | 70 | ||||
-rw-r--r-- | sys/arch/octeon/conf/files.octeon | 5 | ||||
-rw-r--r-- | sys/arch/octeon/dev/octboot.c | 387 | ||||
-rw-r--r-- | sys/arch/octeon/include/conf.h | 10 | ||||
-rw-r--r-- | sys/arch/octeon/include/octboot.h | 35 | ||||
-rw-r--r-- | sys/arch/octeon/include/octeonvar.h | 9 | ||||
-rw-r--r-- | sys/arch/octeon/octeon/conf.c | 5 | ||||
-rw-r--r-- | sys/arch/octeon/octeon/locore.S | 14 | ||||
-rw-r--r-- | sys/arch/octeon/octeon/machdep.c | 243 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/Makefile | 16 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/cmd.c | 503 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/cmd.h | 65 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/disk.c | 207 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/disk.h | 21 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/rdboot.c | 192 | ||||
-rw-r--r-- | sys/arch/octeon/stand/rdboot/vars.c | 203 |
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; +} |