Despite the touted support, OpenBSD wouldn't be able to boot off an
extended partition, unless it's the very first or second one.

The kernel was fixed (after a fashion) some time ago, but boot(8) and
installboot(8) still live under the mistaken idea that extended partitions
are defined recursively, with each of them acting like a full MBR again
and again, each with 4 smaller partitions inside it, and the offset of
each subsequent extended partition should be calculated wrt. the offset
of the bigger one containing it.

That doesn't work that way and never worked that way: There is one big
extended partition defined in the MBR, and then inside it there is a
linked list of 'logical' partitions, each of them with a fake MBR
defining a data sub-partition (whose offset is from the start of this
logical partition), and possibly a link to the next logical partition
(whose offset is from the start of the main extended partition).

diff -rup osys/arch/i386/stand/installboot/installboot.c 
sys/arch/i386/stand/installboot/installboot.c
--- osys/arch/i386/stand/installboot/installboot.c      2011-01-26 
01:56:16.000000000 +0200
+++ sys/arch/i386/stand/installboot/installboot.c       2011-02-07 
19:33:08.000000000 +0200
@@ -103,7 +103,7 @@ static void devread(int, void *, daddr_t
 static void    sym_set_value(struct sym_data *, char *, u_int32_t);
 static void    pbr_set_symbols(char *, char *, struct sym_data *);
 static void    usage(void);
-static long    findopenbsd(int, struct disklabel *, off_t, int *);
+static long    findopenbsd(int, struct disklabel *);
 static void    write_bootblocks(int devfd, struct disklabel *);
 
 static int     sr_volume(int, int *, int *);
@@ -213,7 +213,6 @@ write_bootblocks(int devfd, struct diskl
        struct  stat sb;
        off_t   startoff = 0;
        long    start = 0;
-       int     n = 8;
 
        /* Write patched proto bootblock(s) into the superblock. */
        if (fstat(devfd, &sb) < 0)
@@ -233,7 +232,7 @@ write_bootblocks(int devfd, struct diskl
        if (dl->d_type != 0 && dl->d_type != DTYPE_FLOPPY &&
            dl->d_type != DTYPE_VND) {
                /* Find OpenBSD partition. */
-               start = findopenbsd(devfd, dl, (off_t)DOSBBSECTOR, &n);
+               start = findopenbsd(devfd, dl);
                if (start == -1)
                        errx(1, "no OpenBSD partition");
                startoff = (off_t)start * dl->d_secsize;
@@ -247,35 +246,30 @@ write_bootblocks(int devfd, struct diskl
 }
 
 long
-findopenbsd(int devfd, struct disklabel *dl, off_t mbroff, int *n)
+findopenbsd(int devfd, struct disklabel *dl)
 {
        struct          dos_mbr mbr;
        struct          dos_partition *dp;
-       off_t           startoff;
-       long            start;
+       off_t           off, eoff, noff;
 
-       /* Limit the number of recursions */
-       if (!(*n)--)
-               return (-1);
-
-       if (lseek(devfd, mbroff * dl->d_secsize, SEEK_SET) < 0 ||
+       off = eoff = 0;
+redo:
+       if (lseek(devfd, off * dl->d_secsize, SEEK_SET) < 0 ||
            read(devfd, &mbr, sizeof(mbr)) != sizeof(mbr))
                err(4, "can't read master boot record");
 
        if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
                errx(1, "broken MBR");
 
-       for (dp = mbr.dmbr_parts; dp < &mbr.dmbr_parts[NDOSPART];
+       for (noff = 0, dp = mbr.dmbr_parts; dp < &mbr.dmbr_parts[NDOSPART];
            dp++) {
-               if (!dp->dp_size)
-                       continue;
                if (dp->dp_typ == DOSPTYP_OPENBSD) {
                        if (verbose)
                                fprintf(stderr,
                                    "using MBR partition %ld: type 0x%02X 
offset %d\n",
                                    (long)(dp - mbr.dmbr_parts),
                                    dp->dp_typ, dp->dp_start);
-                       return (dp->dp_start + mbroff);
+                       return (dp->dp_start + off);
                } else if (dp->dp_typ == DOSPTYP_EXTEND ||
                    dp->dp_typ == DOSPTYP_EXTENDL) {
                        if (verbose)
@@ -283,12 +277,14 @@ findopenbsd(int devfd, struct disklabel 
                                    "extended partition %ld: type 0x%02X offset 
%d\n",
                                    (long)(dp - mbr.dmbr_parts),
                                    dp->dp_typ, dp->dp_start);
-                       startoff = (off_t)dp->dp_start + mbroff;
-                       start = findopenbsd(devfd, dl, startoff, n);
-                       if (start != -1)
-                               return (start);
+                       noff = dp->dp_start + eoff;
                }
        }
+       if(noff){
+               if(!eoff) eoff = noff;
+               off = noff;
+               goto redo;
+       }
 
        return (-1);
 }
diff -rup osys/arch/i386/stand/libsa/biosdev.c 
sys/arch/i386/stand/libsa/biosdev.c
--- osys/arch/i386/stand/libsa/biosdev.c        2011-01-09 01:15:25.000000000 
+0200
+++ sys/arch/i386/stand/libsa/biosdev.c 2011-02-07 19:18:04.000000000 +0200
@@ -46,7 +46,7 @@ static int biosdisk_errno(u_int);
 int CHS_rw (int, int, int, int, int, int, void *);
 static int EDD_rw (int, int, u_int64_t, u_int32_t, void *);
 
-static daddr_t findopenbsd(bios_diskinfo_t *, daddr_t, const char **, int *);
+static daddr_t findopenbsd(bios_diskinfo_t *, const char **);
 
 extern int debug;
 int bios_bootdev;
@@ -345,21 +345,17 @@ biosd_io(int rw, bios_diskinfo_t *bd, da
  * Try to read the bsd label on the given BIOS device
  */
 static daddr_t
-findopenbsd(bios_diskinfo_t *bd, daddr_t mbroff, const char **err, int *n)
+findopenbsd(bios_diskinfo_t *bd, const char **err)
 {
        int error, i;
        struct dos_mbr mbr;
        struct dos_partition *dp;
-       daddr_t off;
-
-       /* Limit the number of recursions */
-       if (!(*n)--) {
-               *err = "too many extended partitions";
-               return (-1);
-       }
+       daddr_t off, eoff, noff;
 
+       off = eoff = 0;
+redo:
        /* Read MBR */
-       error = biosd_io(F_READ, bd, mbroff, 1, &mbr);
+       error = biosd_io(F_READ, bd, off, 1, &mbr);
        if (error) {
                *err = biosdisk_err(error);
                return (-1);
@@ -372,10 +368,8 @@ findopenbsd(bios_diskinfo_t *bd, daddr_t
        }
 
        /* Search for OpenBSD partition */
-       for (i = 0; i < NDOSPART; i++) {
+       for (i = 0, noff = 0; i < NDOSPART; i++) {
                dp = &mbr.dmbr_parts[i];
-               if (!dp->dp_size)
-                       continue;
 #ifdef BIOS_DEBUG
                if (debug)
                        printf("found partition %u: "
@@ -385,14 +379,17 @@ findopenbsd(bios_diskinfo_t *bd, daddr_t
                            dp->dp_start, dp->dp_start);
 #endif
                if (dp->dp_typ == DOSPTYP_OPENBSD) {
-                       return (dp->dp_start + mbroff);
+                       return (dp->dp_start + off);
                } else if (dp->dp_typ == DOSPTYP_EXTEND ||
                    dp->dp_typ == DOSPTYP_EXTENDL) {
-                       off = findopenbsd(bd, dp->dp_start + mbroff, err, n);
-                       if (off != -1)
-                               return (off);
+                       noff = dp->dp_start + eoff;
                }
        }
+       if(noff){
+               if(!eoff) eoff = noff;
+               off = noff;
+               goto redo;
+       }
 
        return (-1);
 }
@@ -404,7 +401,6 @@ bios_getdisklabel(bios_diskinfo_t *bd, s
        char *buf;
        const char *err = NULL;
        int error;
-       int n = 8;
 
        /* Sanity check */
        if (bd->bios_edd == -1 &&
@@ -413,7 +409,7 @@ bios_getdisklabel(bios_diskinfo_t *bd, s
 
        /* MBR is a harddisk thing */
        if (bd->bios_number & 0x80) {
-               off = findopenbsd(bd, DOSBBSECTOR, &err, &n);
+               off = findopenbsd(bd, &err);
                if (off == -1) {
                        if (err != NULL)
                                return (err);
62ccd6efa3a20d4a2684fc7e41566b11de0dfe955e899ce6d1f984ba9f3d9bb1

Reply via email to