summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2020-03-09 06:16:57 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2020-03-09 06:16:57 +0000
commit6f8b3d77296cd33aad00b67fa827f37f41187e26 (patch)
tree241edac4f307c17c5ae5a810a61e7583ad5e3344
parent17bc656393fede29483e1d66cb5856dc100132e7 (diff)
Recommit, now that we found out how to fix the BIOS related issues: go
back to a 4 byte add instruction. We do not know *why* though, so if somebody likes a challenge... Lots of help from semarie@ who has a few systems showing the issue. ok deraadt@
-rw-r--r--sys/arch/amd64/stand/biosboot/biosboot.S17
-rw-r--r--sys/arch/i386/stand/biosboot/biosboot.S17
-rw-r--r--usr.sbin/installboot/i386_installboot.c117
-rw-r--r--usr.sbin/installboot/i386_softraid.c3
4 files changed, 131 insertions, 23 deletions
diff --git a/sys/arch/amd64/stand/biosboot/biosboot.S b/sys/arch/amd64/stand/biosboot/biosboot.S
index 9c787cf1192..294388aaa77 100644
--- a/sys/arch/amd64/stand/biosboot/biosboot.S
+++ b/sys/arch/amd64/stand/biosboot/biosboot.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: biosboot.S,v 1.9 2020/03/07 15:11:50 otto Exp $ */
+/* $OpenBSD: biosboot.S,v 1.10 2020/03/09 06:16:56 otto Exp $ */
/*
* Copyright (c) 2003 Tobias Weingartner
@@ -108,6 +108,9 @@
* While this can be calculated as
* howmany(di_size, fs_bsize) it takes us too
* many code bytes to do it.
+ * blkincr uint8 the increment used to parse di_db[]. set to four by
+ * installboot for ffs2 (due to 64-bit blocks) and should
+ * be zero for ffs1.
*
* All of these are patched directly into the code where they are used
* (once only, each), to save space.
@@ -121,7 +124,7 @@
*/
.globl inodeblk, inodedbl, fs_bsize_p, fsbtodb, p_offset, nblocks
- .globl fs_bsize_s, force_chs
+ .globl fs_bsize_s, force_chs, blkincr
.type inodeblk, @function
.type inodedbl, @function
.type fs_bsize_p, @function
@@ -130,6 +133,7 @@
.type p_offset, @function
.type nblocks, @function
.type force_chs, @function
+ .type blkincr, @function
/* Clobbers %ax, maybe more */
@@ -461,6 +465,15 @@ load_blocks:
/* Get the next filesystem block number into %eax */
lodsl /* %eax = *(%si++), make sure 0x66 0xad */
+ /*
+ * The addw could be a 3 byte instruction, but stick to a 4 byte
+ * one since the former inroduces mysterious hangs on *some*
+ * BIOS implementations, possibly alignment related.
+ * Grand prize for somebody finding the root cause!
+ */
+blkincr = .+2
+ addw $0x90, %si /* adjust %si if needed (for ffs2) */
+
pushal /* Save all 32-bit registers */
/*
diff --git a/sys/arch/i386/stand/biosboot/biosboot.S b/sys/arch/i386/stand/biosboot/biosboot.S
index d58b4326946..790e80a104c 100644
--- a/sys/arch/i386/stand/biosboot/biosboot.S
+++ b/sys/arch/i386/stand/biosboot/biosboot.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: biosboot.S,v 1.43 2020/03/07 15:11:50 otto Exp $ */
+/* $OpenBSD: biosboot.S,v 1.44 2020/03/09 06:16:56 otto Exp $ */
/*
* Copyright (c) 2003 Tobias Weingartner
@@ -108,6 +108,9 @@
* While this can be calculated as
* howmany(di_size, fs_bsize) it takes us too
* many code bytes to do it.
+ * blkincr uint8 the increment used to parse di_db[]. set to four by
+ * installboot for ffs2 (due to 64-bit blocks) and should
+ * be zero for ffs1.
*
* All of these are patched directly into the code where they are used
* (once only, each), to save space.
@@ -121,7 +124,7 @@
*/
.globl inodeblk, inodedbl, fs_bsize_p, fsbtodb, p_offset, nblocks
- .globl fs_bsize_s, force_chs
+ .globl fs_bsize_s, force_chs, blkincr
.type inodeblk, @function
.type inodedbl, @function
.type fs_bsize_p, @function
@@ -130,6 +133,7 @@
.type p_offset, @function
.type nblocks, @function
.type force_chs, @function
+ .type blkincr, @function
/* Clobbers %ax, maybe more */
@@ -461,6 +465,15 @@ load_blocks:
/* Get the next filesystem block number into %eax */
lodsl /* %eax = *(%si++), make sure 0x66 0xad */
+ /*
+ * The addw could be a 3 byte instruction, but stick to a 4 byte
+ * one since the former inroduces mysterious hangs on *some*
+ * BIOS implementations, possibly alignment related.
+ * Grand prize for somebody finding the root cause!
+ */
+blkincr = .+2
+ addw $0x90, %si /* adjust %si if needed (for ffs2) */
+
pushal /* Save all 32-bit registers */
/*
diff --git a/usr.sbin/installboot/i386_installboot.c b/usr.sbin/installboot/i386_installboot.c
index c84e9f131e3..a904ed981c1 100644
--- a/usr.sbin/installboot/i386_installboot.c
+++ b/usr.sbin/installboot/i386_installboot.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: i386_installboot.c,v 1.35 2020/03/07 15:11:50 otto Exp $ */
+/* $OpenBSD: i386_installboot.c,v 1.36 2020/03/09 06:16:56 otto Exp $ */
/* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
/*
+ * Copyright (c) 2013 Pedro Martelletto
* Copyright (c) 2011 Joel Sing <jsing@openbsd.org>
* Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
* Copyright (c) 1997 Michael Shalayeff
@@ -82,6 +83,7 @@ struct sym_data pbr_symbols[] = {
{"_inodeblk", 4},
{"_inodedbl", 4},
{"_nblocks", 2},
+ {"_blkincr", 1},
{NULL}
};
@@ -90,6 +92,10 @@ static u_int findopenbsd(int, struct disklabel *);
static int getbootparams(char *, int, struct disklabel *);
static char *loadproto(char *, long *);
static int gpt_chk_mbr(struct dos_partition *, u_int64_t);
+static int sbchk(struct fs *, daddr_t);
+static void sbread(int, daddr_t, struct fs **, char *);
+
+static const daddr_t sbtry[] = SBLOCKSEARCH;
/*
* Read information about /boot's inode and filesystem parameters, then
@@ -662,11 +668,11 @@ getbootparams(char *boot, int devfd, struct disklabel *dl)
struct fs *fs;
char *sblock, *buf;
u_int blk, *ap;
- struct ufs1_dinode *ip;
int ndb;
int mib[3];
size_t size;
dev_t dev;
+ int incr;
/*
* Open 2nd-level boot program and record enough details about
@@ -723,19 +729,10 @@ getbootparams(char *boot, int devfd, struct disklabel *dl)
pp = &dl->d_partitions[DISKPART(fsb.st_dev)];
close(fd);
- /* Read superblock. */
if ((sblock = malloc(SBSIZE)) == NULL)
err(1, NULL);
- devread(devfd, sblock, DL_SECTOBLK(dl, pp->p_offset) + SBLOCK,
- SBSIZE, "superblock");
- fs = (struct fs *)sblock;
-
- /* Sanity-check super-block. */
- if (fs->fs_magic != FS_MAGIC)
- errx(1, "Bad magic number in superblock");
- if (fs->fs_inopb <= 0)
- err(1, "Bad inopb=%d in superblock", fs->fs_inopb);
+ sbread(devfd, DL_SECTOBLK(dl, pp->p_offset), &fs, sblock);
/* Read inode. */
if ((buf = malloc(fs->fs_bsize)) == NULL)
@@ -743,15 +740,26 @@ getbootparams(char *boot, int devfd, struct disklabel *dl)
blk = fsbtodb(fs, ino_to_fsba(fs, fsb.st_ino));
- devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk,
- fs->fs_bsize, "inode");
- ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, fsb.st_ino);
-
/*
* Have the inode. Figure out how many filesystem blocks (not disk
* sectors) there are for biosboot to load.
*/
- ndb = howmany(ip->di_size, fs->fs_bsize);
+ devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk,
+ fs->fs_bsize, "inode");
+ if (fs->fs_magic == FS_UFS2_MAGIC) {
+ struct ufs2_dinode *ip2 = (struct ufs2_dinode *)(buf) +
+ ino_to_fsbo(fs, fsb.st_ino);
+ ndb = howmany(ip2->di_size, fs->fs_bsize);
+ ap = (u_int *)ip2->di_db;
+ incr = sizeof(u_int32_t);
+ } else {
+ struct ufs1_dinode *ip1 = (struct ufs1_dinode *)(buf) +
+ ino_to_fsbo(fs, fsb.st_ino);
+ ndb = howmany(ip1->di_size, fs->fs_bsize);
+ ap = (u_int *)ip1->di_db;
+ incr = 0;
+ }
+
if (ndb <= 0)
errx(1, "No blocks to load");
@@ -778,10 +786,10 @@ getbootparams(char *boot, int devfd, struct disklabel *dl)
sym_set_value(pbr_symbols, "_p_offset", pp->p_offset);
sym_set_value(pbr_symbols, "_inodeblk",
ino_to_fsba(fs, fsb.st_ino));
- ap = ip->di_db;
sym_set_value(pbr_symbols, "_inodedbl",
((((char *)ap) - buf) + INODEOFF));
sym_set_value(pbr_symbols, "_nblocks", ndb);
+ sym_set_value(pbr_symbols, "_blkincr", incr);
if (verbose) {
fprintf(stderr, "%s is %d blocks x %d bytes\n",
@@ -792,6 +800,8 @@ getbootparams(char *boot, int devfd, struct disklabel *dl)
pp->p_offset,
ino_to_fsba(fs, fsb.st_ino),
(unsigned int)((((char *)ap) - buf) + INODEOFF));
+ fprintf(stderr, "expecting %d-bit fs blocks (incr %d)\n",
+ incr ? 64 : 32, incr);
}
free (sblock);
@@ -881,3 +891,74 @@ pbr_set_symbols(char *fname, char *proto, struct sym_data *sym_list)
free(nl);
}
}
+
+static int
+sbchk(struct fs *fs, daddr_t sbloc)
+{
+ if (verbose)
+ fprintf(stderr, "looking for superblock at %lld\n", sbloc);
+
+ if (fs->fs_magic != FS_UFS2_MAGIC && fs->fs_magic != FS_UFS1_MAGIC) {
+ if (verbose)
+ fprintf(stderr, "bad superblock magic 0x%x\n",
+ fs->fs_magic);
+ return (0);
+ }
+
+ /*
+ * Looking for an FFS1 file system at SBLOCK_UFS2 will find the
+ * wrong superblock for file systems with 64k block size.
+ */
+ if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2) {
+ if (verbose)
+ fprintf(stderr, "skipping ffs1 superblock at %lld\n",
+ sbloc);
+ return (0);
+ }
+
+ if (fs->fs_bsize <= 0 || fs->fs_bsize < sizeof(struct fs) ||
+ fs->fs_bsize > MAXBSIZE) {
+ if (verbose)
+ fprintf(stderr, "invalid superblock block size %d\n",
+ fs->fs_bsize);
+ return (0);
+ }
+
+ if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE) {
+ if (verbose)
+ fprintf(stderr, "invalid superblock size %d\n",
+ fs->fs_sbsize);
+ return (0);
+ }
+
+ if (fs->fs_inopb <= 0) {
+ if (verbose)
+ fprintf(stderr, "invalid superblock inodes/block %d\n",
+ fs->fs_inopb);
+ return (0);
+ }
+
+ if (verbose)
+ fprintf(stderr, "found valid %s superblock\n",
+ fs->fs_magic == FS_UFS2_MAGIC ? "ffs2" : "ffs1");
+
+ return (1);
+}
+
+static void
+sbread(int fd, daddr_t poffset, struct fs **fs, char *sblock)
+{
+ int i;
+ daddr_t sboff;
+
+ for (i = 0; sbtry[i] != -1; i++) {
+ sboff = sbtry[i] / DEV_BSIZE;
+ devread(fd, sblock, poffset + sboff, SBSIZE, "superblock");
+ *fs = (struct fs *)sblock;
+ if (sbchk(*fs, sbtry[i]))
+ break;
+ }
+
+ if (sbtry[i] == -1)
+ errx(1, "couldn't find ffs superblock");
+}
diff --git a/usr.sbin/installboot/i386_softraid.c b/usr.sbin/installboot/i386_softraid.c
index e9aaf23dd30..5c4de777772 100644
--- a/usr.sbin/installboot/i386_softraid.c
+++ b/usr.sbin/installboot/i386_softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i386_softraid.c,v 1.14 2020/03/07 15:11:50 otto Exp $ */
+/* $OpenBSD: i386_softraid.c,v 1.15 2020/03/09 06:16:56 otto Exp $ */
/*
* Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
* Copyright (c) 2010 Otto Moerbeek <otto@drijf.net>
@@ -190,6 +190,7 @@ sr_install_bootldr(int devfd, char *dev)
sym_set_value(pbr_symbols, "_inodeblk", inodeblk);
sym_set_value(pbr_symbols, "_inodedbl", inodedbl);
sym_set_value(pbr_symbols, "_nblocks", nblocks);
+ sym_set_value(pbr_symbols, "_blkincr", 0);
if (verbose)
fprintf(stderr, "%s is %d blocks x %d bytes\n",