isohybrid: support booting from partition; fix CBIOS booting
authorH. Peter Anvin <hpa@zytor.com>
Thu, 21 May 2009 22:36:50 +0000 (15:36 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 21 May 2009 22:36:50 +0000 (15:36 -0700)
Fix CBIOS in isohybrid mode.  Also allow an isohybrid image to be
booted from a partition.  Unfortunately this breaks compatibility
between differing versions of isohybrid and isolinux.bin.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
core/isolinux.asm
mbr/Makefile
mbr/checksize.pl
mbr/isohdpfx.S
utils/Makefile
utils/isohybrid.in

index cc97f47..b85ecd3 100644 (file)
@@ -112,6 +112,8 @@ DiskError   resb 1                  ; Error code for disk I/O
 DriveNumber    resb 1                  ; CD-ROM BIOS drive number
 ISOFlags       resb 1                  ; Flags for ISO directory search
 RetryCount      resb 1                 ; Used for disk access retries
+               alignb 8
+bsHidden       resq 1                  ; Used in hybrid mode
 bsSecPerTrack  resw 1                  ; Used in hybrid mode
 bsHeads                resw 1                  ; Used in hybrid mode
 
@@ -222,26 +224,31 @@ bi_end:
                ; Custom entry point for the hybrid-mode disk.
                ; The following values will have been pushed onto the
                ; entry stack:
-               ;       - CBIOS Heads
-               ;       - CBIOS Sectors
-               ;       - EBIOS flag
-               ;       - DX (including drive number)
-               ;       - DI
                ;       - ES
+               ;       - DI
+               ;       - DX (including drive number)
+               ;       - partition offset (qword)
+               ;       - EBIOS flag
+               ;       - CBIOS Sectors
+               ;       - CBIOS Heads
                ;       (top of stack)
+               ;
 %ifndef DEBUG_MESSAGES
 _hybrid_signature:
-               dd 0x7078c0fb                   ; An arbitrary number...
-
+               dd 0x0defe3f7
 _start_hybrid:
+               pop word [cs:bsHeads]
+               pop word [cs:bsSecPerTrack]
+
                pop ax
                mov si,bios_cbios
                and ax,ax
                jz .cbios
                mov si,bios_ebios
 .cbios:
-               pop word [cs:bsSecPerTrack]
-               pop word [cs:bsHeads]
+
+               pop dword [cs:bsHidden]
+               pop dword [cs:bsHidden+4]
 
                pop dx
                pop di
@@ -745,6 +752,8 @@ getlinsec_ebios:
                xor edx,edx
                shld edx,eax,2
                shl eax,2                       ; Convert to HDD sectors
+               add eax,[bsHidden]
+               adc edx,[bsHidden+4]
                shl bp,2
 
 .loop:
@@ -814,7 +823,9 @@ getlinsec_ebios:
 ; getlinsec implementation for legacy CBIOS
 ;
 getlinsec_cbios:
+               xor edx,edx
                shl eax,2                       ; Convert to HDD sectors
+               add eax,[bsHidden]
                shl bp,2
 
 .loop:
index 3140132..c3eb97a 100644 (file)
 topdir = ..
 include $(topdir)/MCONFIG.embedded
 
-all:   mbr.bin   altmbr.bin   gptmbr.bin   isohdpfx.bin   \
-       mbr_c.bin altmbr_c.bin gptmbr_c.bin isohdpfx_c.bin \
-       mbr_f.bin altmbr_f.bin gptmbr_f.bin isohdpfx_f.bin
+all:   mbr.bin   altmbr.bin   gptmbr.bin   isohdpfx.bin   isohdppx.bin \
+       mbr_c.bin altmbr_c.bin gptmbr_c.bin isohdpfx_c.bin isohdppx_c.bin \
+       mbr_f.bin altmbr_f.bin gptmbr_f.bin isohdpfx_f.bin isohdppx_f.bin
 
-.PRECIOUS: %.o
 %.o: %.S
        $(CC) $(MAKEDEPS) $(SFLAGS) -Wa,-a=$*.lst -c -o $@ $<
 
@@ -50,3 +49,5 @@ clean: tidy
 
 spotless: clean
        rm -f *.bin
+
+-include .*.d
index 4648c95..7d61bdf 100755 (executable)
@@ -27,7 +27,7 @@ if (!defined($maxsize)) {
        $maxsize = $padsize = 440;
     } elsif ($file =~ /^gptmbr[^0-9a-z]/) {
        $maxsize = $padsize = 424;
-    } elsif ($file =~ /^isohdpfx[^0-9a-z]/) {
+    } elsif ($file =~ /^isohdp[fp]x[^0-9a-z]/) {
        $maxsize = $padsize = 432;
     } elsif ($file =~ /^altmbr[^0-9a-z]/) {
        $maxsize = 439; $padsize = 440;
index f42b4b5..53e1ed6 100644 (file)
@@ -39,7 +39,7 @@
        .code16
        .text
 
-HYBRID_MAGIC                   = 0x7078c0fb
+HYBRID_MAGIC                   = 0x0defe3f7
 isolinux_hybrid_signature      = 0x7c00+64
 isolinux_start_hybrid          = 0x7c00+64+4
 
@@ -47,10 +47,11 @@ isolinux_start_hybrid               = 0x7c00+64+4
 /* Important: the top 6 words on the stack are passed to isolinux.bin */
 stack          = 0x7c00
 driveno                = (stack-6)
-ebios_flag     = (stack-8)
-sectors                = (stack-10)
-heads          = (stack-12)
-secpercyl      = (stack-16)
+partoffset     = (stack-14)
+ebios_flag     = (stack-16)
+sectors                = (stack-18)
+heads          = (stack-20)
+secpercyl      = (stack-24)
 
 BIOS_kbdflags  = 0x417
 BIOS_page      = 0x462
@@ -66,18 +67,47 @@ bootsec:
 _start:
 
        cli
-       xorw    %ax, %ax
-       movw    %ax, %ds
-       movw    %ax, %ss
+       xorw    %bx, %bx
+       movw    %bx, %ds
+       movw    %bx, %ss
        movw    $stack, %sp
-       movw    %sp, %si
-       pushw   %es             /* es:di -> $PnP header */
+       pushw   %es                     /* -4: es:di -> $PnP header */
        pushw   %di
-       movw    %ax, %es
+       movw    %bx, %es
        sti
        cld
 
+       ADJUST_DRIVE
+       pushw   %dx                     /* -6: dl -> drive number */
+
+       /* Check to see if we have a partition table entry */
+#ifdef PARTITION_SUPPORT
+       andw    %si, %si                /* %si == 0 -> no partition data */
+       jz      1f
+       testb   $0x7f, (%si)            /* Invalid active flag field? */
+       jnz     1f
+       cmpl    $0x58504721, %eax       /* !GPT signature in EAX? */
+       jne     2f
+       cmpb    $0xee, 4(%si)           /* EFI partition type? */
+       jne     2f
+       /* We have GPT partition information */
+       pushl   (36+16)(%si)            /* -10: partoffset_hi */
+       pushl   (32+16)(%si)            /* -14: partoffset_lo */
+       jmp     3f
+2:
+       /* We have non-GPT partition information */
+       pushl   $0                      /* -10: partoffset_hi */
+       pushl   8(%si)                  /* -14: partoffset_lo */
+       jmp     3f
+#endif
+1:
+       /* We have no partition information */
+       pushl   $0                      /* -10: partoffset_hi */
+       pushl   $0                      /* -14: partoffset_lo */
+3:
+       
        /* Copy down to 0:0x600 */
+       movw    $0x7c00, %si
        movw    $_start, %di
        movw    $(512/2), %cx
        rep; movsw
@@ -85,9 +115,6 @@ _start:
        ljmpw   $0, $next
 next:
 
-       ADJUST_DRIVE
-       pushw   %dx             /* dl -> drive number */
-
        /* Check to see if we have EBIOS */
        pushw   %dx             /* drive number */
        movb    $0x41, %ah      /* %al == 0 already */
@@ -106,24 +133,24 @@ next:
           read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
        movl    $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
                (read_sector_cbios)
-
+       jmp     1f
 1:
        popw    %dx
-       pushw   %cx             /* Save EBIOS flag */
+       pushw   %cx             /* -16: Save EBIOS flag */
 
        /* Get (C)HS geometry */
        movb    $0x08, %ah
        int     $0x13
        andw    $0x3f, %cx      /* Sector count */
-       pushw   %cx             /* Save sectors on the stack */
+       pushw   %cx             /* -18: Save sectors on the stack */
        movzbw  %dh, %ax        /* dh = max head */
        incw    %ax             /* From 0-based max to count */
-       pushw   %ax             /* Save heads on the stack */
+       pushw   %ax             /* -20: Save heads on the stack */
        mulw    %cx             /* Heads*sectors -> sectors per cylinder */
 
        /* Save sectors/cylinder on the stack */
-       pushw   %dx             /* High word */
-       pushw   %ax             /* Low word */
+       pushw   %dx             /* -22: High word */
+       pushw   %ax             /* -24: Low word */
 
        /*
         * Load sectors.  We do this one at a time mostly to avoid
@@ -169,6 +196,8 @@ bad_signature:
 read_sector:
        pushal
        xorl    %edx, %edx
+       addl    (partoffset), %eax
+       adcl    (partoffset+4), %edx
        pushl   %edx    /* MSW of LBA */
        pushl   %eax    /* LSW of LBA */
        pushw   %es     /* Buffer segment */
index 7670bef..9df9595 100644 (file)
@@ -23,7 +23,8 @@ LDFLAGS  = -O2 -s
 TARGETS         = mkdiskimage isohybrid gethostip
 ASIS     = keytab-lilo lss16toppm md5pass ppmtolss16 sha1pass syslinux2ansi
 
-ISOHDPFX = ../mbr/isohdpfx.bin ../mbr/isohdpfx_f.bin ../mbr/isohdpfx_c.bin
+ISOHDPFX = ../mbr/isohdpfx.bin ../mbr/isohdpfx_f.bin ../mbr/isohdpfx_c.bin \
+          ../mbr/isohdppx.bin ../mbr/isohdppx_f.bin ../mbr/isohdppx_c.bin
 
 all: $(TARGETS)
 
index 2bbaada..b3a502b 100644 (file)
@@ -43,6 +43,7 @@ use Fcntl;
     'type'   => [0, 255],
     'id'     => [0, 0xffffffff],
     'hd0'    => [0, 2],
+    'partok' => [0, 1],
 );
 
 # Boolean options just set other options
@@ -50,6 +51,8 @@ use Fcntl;
     'nohd0'    => ['hd0', 0],
     'forcehd0' => ['hd0', 1],
     'ctrlhd0'  => ['hd0', 2],
+    'nopartok' => ['partok', 0],
+    'partok'   => ['partok', 1],
 );
 
 sub usage() {
@@ -63,6 +66,7 @@ sub usage() {
     "  -id         Specify MBR ID (default random)\n",
     "  -forcehd0   Always assume we are loaded as disk ID 0\n",
     "  -ctrlhd0    Assume disk ID 0 if the Ctrl key is pressed\n",
+    "  -partok     Allow booting from within a partition\n";
     exit 1;
 }
 
@@ -161,9 +165,10 @@ if ($de_boot != 0x88 || $de_media != 0 ||
 # Now $de_lba should contain the CD sector number for isolinux.bin
 seek(FILE, $de_lba*2048+0x40, SEEK_SET) or die "$0: $file: $!\n";
 read(FILE, $ibsig, 4);
-if ($ibsig ne "\xfb\xc0\x78\x70") {
-    die "$0: $file: bootloader is missing isolinux.bin hybrid signature\n".
-       "Note: isolinux-debug.bin does not support hybrid booting\n";
+if ($ibsig ne "\xf7\xe3\xef\x0d") {
+    die "$0: $file: bootloader is missing current (3.81+) isolinux.bin\n".
+       "        hybrid signature; Note that isolinux-debug.bin does not\n".
+       "        support hybrid booting.\n";
 }
 
 # Get the total size of the image
@@ -202,7 +207,7 @@ if (defined($opt{'id'})) {
 # Print the MBR and partition table
 seek(FILE, 0, SEEK_SET) or die "$0: $file: $!\n";
 
-for ($i = 0; $i <= $opt{'hd0'}; $i++) {
+for ($i = 0; $i <= $opt{'hd0'}+3*$opt{'partok'}; $i++) {
     $mbr = get_hex_data();
 }
 if ( length($mbr) > 432 ) {