diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2016-10-05 11:55:46 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2016-10-05 11:55:46 +0000 |
commit | a5ceb9a2d94c5b29af31cafdc7a0dbda7ad4f47f (patch) | |
tree | b8099f9b32afb70e5bf6224770340dffcf2ac283 /sys/arch/sgi/stand | |
parent | 7c15ec6997944fc7b8b6c3564e8ff037f19fc486 (diff) |
Make the sgi boot blocks read the real OpenBSD disklabel instead of
assuming that the 'a' partition starts at the same location as the
volume header partition #0.
Diff from Miod Vallat
Diffstat (limited to 'sys/arch/sgi/stand')
-rw-r--r-- | sys/arch/sgi/stand/Makefile32.inc | 3 | ||||
-rw-r--r-- | sys/arch/sgi/stand/boot/Makefile | 8 | ||||
-rw-r--r-- | sys/arch/sgi/stand/boot/diskio.c | 174 | ||||
-rw-r--r-- | sys/arch/sgi/stand/boot/version | 8 |
4 files changed, 165 insertions, 28 deletions
diff --git a/sys/arch/sgi/stand/Makefile32.inc b/sys/arch/sgi/stand/Makefile32.inc index 1ab3306ff10..4b5e1977735 100644 --- a/sys/arch/sgi/stand/Makefile32.inc +++ b/sys/arch/sgi/stand/Makefile32.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile32.inc,v 1.5 2012/10/19 13:51:59 miod Exp $ +# $OpenBSD: Makefile32.inc,v 1.6 2016/10/05 11:55:45 visa Exp $ .ifndef __INCLUDED_STAND_MAKEFILE32_INC __INCLUDED_STAND_MAKEFILE32_INC= @@ -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 diff --git a/sys/arch/sgi/stand/boot/Makefile b/sys/arch/sgi/stand/boot/Makefile index f307404393f..a0f6fc970da 100644 --- a/sys/arch/sgi/stand/boot/Makefile +++ b/sys/arch/sgi/stand/boot/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.16 2016/07/30 03:25:49 guenther Exp $ +# $OpenBSD: Makefile,v 1.17 2016/10/05 11:55:45 visa Exp $ NOMAN= noman @@ -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 diff --git a/sys/arch/sgi/stand/boot/diskio.c b/sys/arch/sgi/stand/boot/diskio.c index c21690bd4a1..e145ac0417e 100644 --- a/sys/arch/sgi/stand/boot/diskio.c +++ b/sys/arch/sgi/stand/boot/diskio.c @@ -1,6 +1,21 @@ -/* $OpenBSD: diskio.c,v 1.10 2015/09/30 22:45:57 krw Exp $ */ +/* $OpenBSD: diskio.c,v 1.11 2016/10/05 11:55:45 visa 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, daddr32_t bn, size_t reqcnt, void *addr, { 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; + 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); + 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); - - if (Bios_Open(ctlr, 0, &fd) < 0) - return (ENXIO); + 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; - - return (0); + 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; } int diff --git a/sys/arch/sgi/stand/boot/version b/sys/arch/sgi/stand/boot/version index bd3ec87a6ad..9fbbb89627d 100644 --- a/sys/arch/sgi/stand/boot/version +++ b/sys/arch/sgi/stand/boot/version @@ -1,4 +1,4 @@ -/* $OpenBSD: version,v 1.8 2016/09/13 18:27:49 jasper Exp $ */ +/* $OpenBSD: version,v 1.9 2016/10/05 11:55:45 visa Exp $ */ /* Public domain. Come on, this can hardly be considered as code. */ #if 0 @@ -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"; |