diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2020-03-09 06:16:57 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2020-03-09 06:16:57 +0000 |
commit | 6f8b3d77296cd33aad00b67fa827f37f41187e26 (patch) | |
tree | 241edac4f307c17c5ae5a810a61e7583ad5e3344 | |
parent | 17bc656393fede29483e1d66cb5856dc100132e7 (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.S | 17 | ||||
-rw-r--r-- | sys/arch/i386/stand/biosboot/biosboot.S | 17 | ||||
-rw-r--r-- | usr.sbin/installboot/i386_installboot.c | 117 | ||||
-rw-r--r-- | usr.sbin/installboot/i386_softraid.c | 3 |
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", |