Hi,

booting from an ffs2 filesystem is a puzzle containing many pieces.
For amd64 and i386 mbr booting, the pieces below are needed.

Lifted from an old bitrig tree. 

Note that this is *not* enough to get thing going since boot(8) and
its variants do not support ffs2 yet, but for this diff I'm only
interested in not breaking existing working mbr boot setups.

        -Otto

Index: sys/arch/amd64/stand/biosboot/biosboot.S
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/biosboot/biosboot.S,v
retrieving revision 1.7
diff -u -p -r1.7 biosboot.S
--- sys/arch/amd64/stand/biosboot/biosboot.S    5 Jul 2011 17:38:54 -0000       
1.7
+++ sys/arch/amd64/stand/biosboot/biosboot.S    19 Feb 2020 15:19:55 -0000
@@ -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.
+ * blkskew     uint8t  the skew used to parse di_db[]. this is 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, blkskew
        .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   blkskew, @function
 
 
 /* Clobbers %ax, maybe more */
@@ -460,6 +464,8 @@ load_blocks:
 
        /* Get the next filesystem block number into %eax */
        lodsl                   /* %eax = *(%si++), make sure 0x66 0xad */
+blkskew = .+2
+       addw    $0x90, %si      /* adjust %si if needed (for ffs2) */
 
        pushal                          /* Save all 32-bit registers */
 
Index: sys/arch/i386/stand/biosboot/biosboot.S
===================================================================
RCS file: /cvs/src/sys/arch/i386/stand/biosboot/biosboot.S,v
retrieving revision 1.41
diff -u -p -r1.41 biosboot.S
--- sys/arch/i386/stand/biosboot/biosboot.S     5 Jul 2011 17:38:54 -0000       
1.41
+++ sys/arch/i386/stand/biosboot/biosboot.S     19 Feb 2020 15:19:55 -0000
@@ -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.
+ * blkskew     uint8t  the skew used to parse di_db[]. this is 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, blkskew
        .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   blkskew, @function
 
 
 /* Clobbers %ax, maybe more */
@@ -460,6 +464,8 @@ load_blocks:
 
        /* Get the next filesystem block number into %eax */
        lodsl                   /* %eax = *(%si++), make sure 0x66 0xad */
+blkskew = .+2
+       addw    $0x90, %si      /* adjust %si if needed (for ffs2) */
 
        pushal                          /* Save all 32-bit registers */
 
Index: usr.sbin/installboot/i386_installboot.c
===================================================================
RCS file: /cvs/src/usr.sbin/installboot/i386_installboot.c,v
retrieving revision 1.33
diff -u -p -r1.33 i386_installboot.c
--- usr.sbin/installboot/i386_installboot.c     2 Sep 2019 16:36:12 -0000       
1.33
+++ usr.sbin/installboot/i386_installboot.c     19 Feb 2020 15:19:55 -0000
@@ -2,6 +2,7 @@
 /*     $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
 
 /*
+ * Copyright (c) 2013 Pedro Martelletto
  * Copyright (c) 2011 Joel Sing <js...@openbsd.org>
  * Copyright (c) 2003 Tom Cosgrove <tom.cosgr...@arches-consulting.com>
  * Copyright (c) 1997 Michael Shalayeff
@@ -82,6 +83,7 @@ struct sym_data pbr_symbols[] = {
        {"_inodeblk",   4},
        {"_inodedbl",   4},
        {"_nblocks",    2},
+       {"_blkskew",    1},
        {NULL}
 };
 
@@ -90,6 +92,10 @@ static u_int findopenbsd(int, struct dis
 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,13 @@ getbootparams(char *boot, int devfd, str
        struct fs       *fs;
        char            *sblock, *buf;
        u_int           blk, *ap;
-       struct ufs1_dinode *ip;
+       struct ufs1_dinode      *ip1;
+       struct ufs2_dinode      *ip2;
        int             ndb;
        int             mib[3];
        size_t          size;
        dev_t           dev;
+       int             skew;
 
        /*
         * Open 2nd-level boot program and record enough details about
@@ -723,19 +731,10 @@ getbootparams(char *boot, int devfd, str
        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 +742,26 @@ getbootparams(char *boot, int devfd, str
 
        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) {
+               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;
+               skew = sizeof(u_int32_t);
+       } else {
+               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;
+               skew = 0;
+       }
+
        if (ndb <= 0)
                errx(1, "No blocks to load");
 
@@ -778,10 +788,10 @@ getbootparams(char *boot, int devfd, str
        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, "_blkskew", skew);
 
        if (verbose) {
                fprintf(stderr, "%s is %d blocks x %d bytes\n",
@@ -792,6 +802,8 @@ getbootparams(char *boot, int devfd, str
                    pp->p_offset,
                    ino_to_fsba(fs, fsb.st_ino),
                    (unsigned int)((((char *)ap) - buf) + INODEOFF));
+               fprintf(stderr, "expecting %d-bit fs blocks (skew %d)\n",
+                   skew ? 64 : 32, skew);
        }
 
        free (sblock);
@@ -880,4 +892,73 @@ pbr_set_symbols(char *fname, char *proto
 
                free(nl);
        }
+}
+
+static int
+sbchk(struct fs *fs, daddr_t sbloc)
+{
+       if (verbose)
+               warnx("looking for superblock at %lld", sbloc);
+
+       if (fs->fs_magic != FS_UFS2_MAGIC && fs->fs_magic != FS_UFS1_MAGIC) {
+               if (verbose)
+                       warnx("bad superblock magic 0x%x", 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)
+                       warnx("skipping ffs1 superblock at %lld", sbloc);
+               return (0);
+       }
+
+       if (fs->fs_bsize <= 0 ||
+           fs->fs_bsize < sizeof(struct fs) ||
+           fs->fs_bsize > MAXBSIZE) {
+               if (verbose)
+                       warnx("invalid superblock block size %d",
+                           fs->fs_bsize);
+               return (0);
+       }
+
+       if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE) {
+               if (verbose)
+                       warnx("invalid superblock size %d", fs->fs_sbsize);
+               return (0);
+       }
+
+       if (fs->fs_inopb <= 0) {
+               if (verbose)
+                       warnx("invalid superblock inodes/block %d",
+                           fs->fs_inopb);
+               return (0);
+       }
+
+       if (verbose)
+               warnx("found valid %s superblock",
+                   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");
 }
Index: usr.sbin/installboot/i386_softraid.c
===================================================================
RCS file: /cvs/src/usr.sbin/installboot/i386_softraid.c,v
retrieving revision 1.12
diff -u -p -r1.12 i386_softraid.c
--- usr.sbin/installboot/i386_softraid.c        2 Sep 2019 16:36:12 -0000       
1.12
+++ usr.sbin/installboot/i386_softraid.c        19 Feb 2020 15:19:55 -0000
@@ -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, "_blkskew", 0);
 
        if (verbose)
                fprintf(stderr, "%s is %d blocks x %d bytes\n",


Reply via email to