On Tue, Oct 04, 2016 at 08:08:32PM +0000, Miod Vallat wrote:
> The sgi boot blocks use the PROM (ARCBios or ARCS) for its I/O routines.
> When using a disk-based path, these routines are using the partition
> table found in the ``volume header''.
> 
> In order to be able to use 16 partitions per disk, the OpenBSD port only
> claims one volume header partition, #0, as the OpenBSD area, and puts
> its own label in there.
> 
> Unfortunately, this means that `sd0a', the OpenBSD partition on which
> the kernel is found, may not actually start at the same location as the
> volume header partition #0, even though this is the case in most setups.
> 
> When reinstalling an O2 some time ago, I did not pay attention to this
> during install:
> 
>   Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a] c
>   [...]
>   Label editor (enter '?' for help at any prompt)
>   > p
>   OpenBSD area: 0-17773524; size: 17773524; free: 0
>   #                size           offset  fstype [fsize bsize   cpg]
>     a:         17770389             3135  4.2BSD   1024  8192    16
>     c:         17773524                0  unused
>     p:             3135                0 unknown
>   > d a
>   > a
>   partition: [a]
>   offset: [3135]
>   size: [17770389] 400M
>   Rounding size to cylinder (3360 sectors): 816705
>   FS type: [4.2BSD]
>   mount point: [none] /
>   Rounding offset to bsize (32 sectors): 3136
>   Rounding size to bsize (32 sectors): 816704
> 
> And `sd0a' ended up starting one sector after the beginning of the
> volume header partition #0.
> 
> Of course, rebooting afterwards did not work as expected:
> 
>   OpenBSD/sgi-IP32 ARCBios boot version 1.7
>   arg 0: pci(0)scsi(0)disk(1)rdisk(0)partition(8)/boot
>   arg 1: OSLoadOptions=auto
>   arg 2: ConsoleIn=serial(0)
>   arg 3: ConsoleOut=serial(0)
>   arg 4: SystemPartition=pci(0)scsi(0)disk(1)rdisk(0)partition(8)
>   arg 5: OSLoader=boot
>   arg 6: OSLoadPartition=pci(0)scsi(0)disk(1)rdisk(0)partition(0)
>   arg 7: OSLoadFilename=bsd
>   Boot: pci(0)scsi(0)disk(1)rdisk(0)partition(0)bsd
>   cannot open pci(0)scsi(0)disk(1)rdisk(0)partition(0)/etc/random.seed: 
> Invalid argument
>   open pci(0)scsi(0)disk(1)rdisk(0)partition(0)bsd: Invalid argument
>   Boot FAILED!
> 
> The proper way to fix this is to make the boot blocks read the real
> OpenBSD label instead of assuming sd0a spans volume header partition #0
> in all cases.
> 
> This is achieved by the diff below, which will attempt to use the raw
> disk device (volume header partition #10, equivalent to sd0c) for disk
> accesses and will read both the volume header (to know where the OpenBSD
> disklabel lies) and then the OpenBSD label (to know where sd0a really
> is).
> 
> Of course, this has to cope with the two valid disk syntaxes (true
> ARCBios used on older sgi systems, and ARCS dksc() syntax used on Origin
> and later systems).
> 
> This diff has been tested on O2 (IP32) and Origin 350 (IP27). It is
> written in a conservative way, in order to revert to the existing
> behaviour if anything fails (invalid volume header, no OpenBSD label
> yet...) and should not cause any regression.
> 
> Note that network boots are not affected by these changes.

I tested this also on Octane (IP30), and it works fine. The diff is now
committed. Thanks!

> Index: Makefile32.inc
> ===================================================================
> RCS file: /OpenBSD/src/sys/arch/sgi/stand/Makefile32.inc,v
> retrieving revision 1.5
> diff -u -p -r1.5 Makefile32.inc
> --- Makefile32.inc    19 Oct 2012 13:51:59 -0000      1.5
> +++ Makefile32.inc    30 Sep 2016 09:19:15 -0000
> @@ -18,6 +18,7 @@ AS+=                -32
>  LD?=         ld
>  LD+=         -m elf32btsmip
>  LIBSA_CPPFLAGS=
> +CFLAGS+=     -DLIBSA_LONGLONG_PRINTF
>  .endif
>  
>  ### Figure out what to use for libsa and libz
> Index: boot/Makefile
> ===================================================================
> RCS file: /OpenBSD/src/sys/arch/sgi/stand/boot/Makefile,v
> retrieving revision 1.16
> diff -u -p -r1.16 Makefile
> --- boot/Makefile     30 Jul 2016 03:25:49 -0000      1.16
> +++ boot/Makefile     30 Sep 2016 09:19:15 -0000
> @@ -13,14 +13,14 @@ AFLAGS+=  ${SAABI}
>  
>  S=           ${.CURDIR}/../../../..
>  SRCS=                start.S arcbios.c boot.c conf.c diskio.c filesystem.c \
> -             netfs.c netio.c strchr.c strstr.c
> +             netfs.c netio.c strstr.c
>  
>  .PATH:               ${S}/lib/libsa
>  SRCS+=               loadfile.c
>  
>  .PATH:               ${S}/lib/libkern/arch/mips64 ${S}/lib/libkern
> -SRCS+=               strlcpy.c memcpy.c strlen.c strrchr.c strlcat.c 
> strncmp.c \
> -             strcmp.S
> +SRCS+=               memcpy.c strchr.c strcmp.S strlcat.c strlcpy.c strlen.c 
> \
> +             strncmp.c strrchr.c
>  
>  CLEANFILES+= machine mips64
>  
> Index: boot/diskio.c
> ===================================================================
> RCS file: /OpenBSD/src/sys/arch/sgi/stand/boot/diskio.c,v
> retrieving revision 1.10
> diff -u -p -r1.10 diskio.c
> --- boot/diskio.c     30 Sep 2015 22:45:57 -0000      1.10
> +++ boot/diskio.c     30 Sep 2016 09:19:15 -0000
> @@ -1,6 +1,21 @@
>  /*   $OpenBSD: diskio.c,v 1.10 2015/09/30 22:45:57 krw Exp $ */
>  
>  /*
> + * Copyright (c) 2016 Miodrag Vallat.
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +/*
>   * Copyright (c) 2000 Opsycon AB  (www.opsycon.se)
>   * Copyright (c) 2000 Rtmx, Inc   (www.rtmx.com)
>   * 
> @@ -33,11 +48,15 @@
>   *
>   */
>  
> -#include <stand.h>
>  #include <sys/param.h>
> +#include <lib/libkern/libkern.h>
> +#include <stand.h>
> +
>  #include <sys/disklabel.h>
>  #include <mips64/arcbios.h>
>  
> +char *strstr(char *, const char *);  /* strstr.c */
> +
>  struct       dio_softc {
>       int     sc_fd;                  /* PROM file ID */
>       int     sc_part;                /* Disk partition number. */
> @@ -50,18 +69,20 @@ diostrategy(void *devdata, int rw, daddr
>  {
>       struct dio_softc *sc = (struct dio_softc *)devdata;
>       struct partition *pp = &sc->sc_label.d_partitions[sc->sc_part];
> +     uint64_t blkoffset;
>       arc_quad_t offset;
>       long result;
>  
> -     offset.hi = 0;
> -     offset.lo = (pp->p_offset + bn) * DEV_BSIZE;
> -
> -     if ((Bios_Seek(sc->sc_fd, &offset, 0) < 0) ||
> -         (Bios_Read(sc->sc_fd, addr, reqcnt, &result) < 0))
> -             return (EIO);
> +     blkoffset = (DL_GETPOFFSET(pp) + bn) * DEV_BSIZE;
> +     offset.hi = blkoffset >> 32;
> +     offset.lo = blkoffset;
> +
> +     if (Bios_Seek(sc->sc_fd, &offset, 0) < 0 ||
> +         Bios_Read(sc->sc_fd, addr, reqcnt, &result) < 0)
> +             return EIO;
>  
>       *cnt = result;
> -     return (0);
> +     return 0;
>  }
>  
>  int
> @@ -69,11 +90,18 @@ dioopen(struct open_file *f, ...)
>  {
>       char *ctlr;
>       int partition;
> -
>       struct dio_softc *sc;
>       struct disklabel *lp;
> +     struct sgilabel *sl;
>       long fd;
> +     /* XXX getdisklabel() assumes DEV_BSIZE bytes available */
> +     char buf[DEV_BSIZE + LABELOFFSET];
> +     arc_quad_t offset;
> +     daddr_t native_offset;
> +     long result;
>       va_list ap;
> +     char rawctlr[1 + MAXPATHLEN];
> +     char *partptr;
>  
>       va_start(ap, f);
>       ctlr = va_arg(ap, char *);
> @@ -81,26 +109,130 @@ dioopen(struct open_file *f, ...)
>       va_end(ap);
>  
>       if (partition >= MAXPARTITIONS)
> -             return (ENXIO);
> +             return ENXIO;
>  
> -     if (Bios_Open(ctlr, 0, &fd) < 0)
> -             return (ENXIO);
> +     /*
> +      * If booting from disk, `ctlr` is something like
> +      *   whatever()partition(0)
> +      * or
> +      *   dksc(whatever,0)
> +      * where 0 is the volume header #0 partition, which is the
> +      * OpenBSD area, where the OpenBSD disklabel can be found.
> +      *
> +      * However, the OpenBSD `a' partition, where the kernel is to be
> +      * found, may not start at the same offset.
> +      *
> +      * In order to be able to correctly load any file from the OpenBSD
> +      * partitions, we need to access the volume header partition table
> +      * and the OpenBSD label.
> +      *
> +      * Therefore, make sure we replace `partition(*)' with `partition(10)'
> +      * before reaching ARCBios, in order to access the raw disk.
> +      *
> +      * We could use partition #8 and use the value of SystemPartition in
> +      * the environment to avoid doing this, but this would prevent us
> +      * from being able to boot from a different disk than the one
> +      * pointed to by SystemPartition.
> +      */
> +     
> +     strlcpy(rawctlr, ctlr, sizeof rawctlr);
> +     partptr = strstr(rawctlr, "partition(");
> +     if (partptr != NULL) {
> +             strlcpy(partptr, "partition(10)",
> +                 sizeof rawctlr - (partptr - rawctlr));
> +     } else {
> +             if ((partptr = strstr(rawctlr, "dksc(")) != NULL) {
> +                     partptr = strstr(partptr, ",0)");
> +                     if (partptr != NULL && partptr[3] == '\0')
> +                             strlcpy(partptr, ",10)",
> +                                 sizeof rawctlr - (partptr - rawctlr));
> +             }
> +     }
> +
> +     sl = NULL;      /* no volume header found yet */
> +     if (partptr != NULL) {
> +             if (Bios_Open(rawctlr, 0, &fd) < 0)
> +                     return ENXIO;
> +
> +             /*
> +              * Read the volume header.
> +              */
> +             offset.hi = offset.lo = 0;
> +             if (Bios_Seek(fd, &offset, 0) < 0 ||
> +                 Bios_Read(fd, buf, DEV_BSIZE, &result) < 0 ||
> +                 result != DEV_BSIZE)
> +                     return EIO;
> +
> +             sl = (struct sgilabel *)buf;
> +             if (sl->magic != SGILABEL_MAGIC) {
> +#ifdef DEBUG
> +                     printf("Invalid volume header magic %x\n", sl->magic);
> +#endif
> +                     Bios_Close(fd);
> +                     sl = NULL;
> +             }
> +     }
> +
> +     if (sl == NULL) {
> +             if (Bios_Open(ctlr, 0, &fd) < 0)
> +                     return ENXIO;
> +     }
>  
>       sc = alloc(sizeof(struct dio_softc));
>       bzero(sc, sizeof(struct dio_softc));
>       f->f_devdata = (void *)sc;
> +     lp = &sc->sc_label;
>  
>       sc->sc_fd = fd;
>       sc->sc_part = partition;
>  
> -     lp = &sc->sc_label;
> -     lp->d_secsize = DEV_BSIZE;
> -     lp->d_secpercyl = 1;
> -     lp->d_npartitions = MAXPARTITIONS;
> -     lp->d_partitions[partition].p_offset = 0;
> -     lp->d_partitions[0].p_size = 0x7fff0000;
> +     if (sl != NULL) {
> +             native_offset = sl->partitions[0].first;
> +     } else {
> +             /*
> +              * We could not read the volume header, or there isn't any.
> +              * Stick to the device we were given, and assume the
> +              * OpenBSD disklabel can be found at the beginning.
> +              */
> +             native_offset = 0;
> +     }
> +
> +     /*
> +      * Read the native OpenBSD label.
> +      */
> +#ifdef DEBUG
> +     printf("OpenBSD label @%lld\n", native_offset + LABELSECTOR);
> +#endif
> +     offset.hi = ((native_offset + LABELSECTOR) * DEV_BSIZE) >> 32;
> +     offset.lo = (native_offset + LABELSECTOR) * DEV_BSIZE;
> +
> +     if (Bios_Seek(fd, &offset, 0) < 0 ||
> +         Bios_Read(fd, buf, DEV_BSIZE, &result) < 0 ||
> +         result != DEV_BSIZE)
> +             return EIO;
> +     
> +     if (getdisklabel(buf + LABELOFFSET, lp) == NULL) {
> +#ifdef DEBUG
> +             printf("Found native disklabel, "
> +                 "partition %c starts at %lld\n",
> +                 'a' + partition,
> +                 DL_GETPOFFSET(&lp->d_partitions[partition]));
> +#endif
> +     } else {
> +             /*
> +              * Assume the OpenBSD partition spans the whole device.
> +              */
> +#ifdef DEBUG
> +             printf("No native disklabel found\n");
> +#endif
> +             lp->d_secsize = DEV_BSIZE;
> +             lp->d_secpercyl = 1;
> +             lp->d_npartitions = MAXPARTITIONS;
> +             DL_SETPOFFSET(&lp->d_partitions[partition], native_offset);
> +             DL_SETPSIZE(&lp->d_partitions[partition], -1ULL);
> +     }
>  
> -     return (0);
> +     return 0;
>  }
>  
>  int
> Index: boot/version
> ===================================================================
> RCS file: /OpenBSD/src/sys/arch/sgi/stand/boot/version,v
> retrieving revision 1.8
> diff -u -p -r1.8 version
> --- boot/version      13 Sep 2016 18:27:49 -0000      1.8
> +++ boot/version      30 Sep 2016 09:19:15 -0000
> @@ -34,6 +34,10 @@ No version strings up to 2012
>  1.7
>       Loadfile support for .SUNW_ctf section
>  
> +1.8
> +     Use the OpenBSD disklabel instead of assuming OpenBSD partition `a`
> +     starts at the beginning of the volume header partition #0.
> +
>  #endif
>  
> -static const char version[] = "1.7";
> +static const char version[] = "1.8";
> 

Reply via email to