diff options
author | H. Peter Anvin <hpa@zytor.com> | 2008-09-05 14:49:42 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2008-09-05 14:49:42 -0700 |
commit | 058dd028ac7d8ae217d1b3b00213751d63034195 (patch) | |
tree | 53bd1e95555370d939258873062db00c7d74bf7d /utils | |
parent | 1eb0d6f7cfa7547470580d821ca815e20df4e93e (diff) | |
download | syslinux-058dd028ac7d8ae217d1b3b00213751d63034195.tar.gz |
ISOLINUX: support for hybrid mode (CD-ROM/USB key)
Still a work in progress.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'utils')
-rw-r--r-- | utils/Makefile | 6 | ||||
-rw-r--r-- | utils/isohybrid.in | 165 |
2 files changed, 170 insertions, 1 deletions
diff --git a/utils/Makefile b/utils/Makefile index 64f8236f..de8c9992 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -20,7 +20,7 @@ include $(topdir)/MCONFIG CFLAGS = -W -Wall -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 LDFLAGS = -O2 -s -TARGETS = mkdiskimage gethostip +TARGETS = mkdiskimage isohybrid gethostip ASIS = keytab-lilo lss16toppm md5pass ppmtolss16 sha1pass syslinux2ansi all: $(TARGETS) @@ -32,6 +32,10 @@ mkdiskimage: mkdiskimage.in ../mbr/mbr.bin bin2hex.pl $(PERL) bin2hex.pl < ../mbr/mbr.bin | cat mkdiskimage.in - > $@ chmod a+x $@ +isohybrid: isohybrid.in ../mbr/isohdpfx.bin bin2hex.pl + $(PERL) bin2hex.pl < ../mbr/isohdpfx.bin | cat isohybrid.in - > $@ + chmod a+x $@ + gethostip: gethostip.o $(CC) $(LDFLAGS) -o $@ $^ diff --git a/utils/isohybrid.in b/utils/isohybrid.in new file mode 100644 index 00000000..a0487ca0 --- /dev/null +++ b/utils/isohybrid.in @@ -0,0 +1,165 @@ +#!/usr/bin/perl +## ----------------------------------------------------------------------- +## +## Copyright 2002-2008 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +# +# Post-process an ISO 9660 image generated with mkisofs/genisoimage +# to allow "hybrid booting" as a CD-ROM or as a hard disk. +# + +use bytes; +use integer; +use Fcntl; +use Errno; +use Cwd; +use IO::Handle; # For flush() + +# Use this fake geometry (zipdrive-style...) +$h = 64; $s = 32; + +sub get_random() { + # Get a 32-bit random number + my $rfd, $rnd; + my $rid; + + if (sysopen($rfd, '/dev/urandom', O_RDONLY) && + sysread($rfd, $rnd, 4) == 4) { + $rid = unpack("V", $rnd); + } + + close($rfd) if (defined($rfd)); + return $rid if (defined($rid)); + + # This sucks but is better than nothing... + return ($$+time()) & 0xffffffff; +} + + +($file) = @ARGV; +open(FILE, "+< $file\0") or die "$0: cannot open $file: $!\n"; +binmode FILE; + +# +# First, actually figure out where mkisofs hid isolinux.bin +# +seek(FILE, 17*2048, SEEK_SET) or die "$0: $file: $!\n"; +read(FILE, $boot_record, 2048) == 2048 or die "$0: $file: read error\n"; +($br_sign, $br_cat_offset) = unpack("a71V", $boot_record); +if ($br_sign ne ("\0CD001\1EL TORITO SPECIFICATION" . ("\0" x 41))) { + die "$0: $file: no boot record found\n"; +} +seek(FILE, $br_cat_offset*2048, SEEK_SET) or die "$0: $file: $!\n"; +read(FILE, $boot_cat, 2048) == 2048 or die "$0: $file: read error\n"; + +# We must have a Validation Entry followed by a Default Entry... +# no fanciness allowed for the Hybrid mode [XXX: might relax this later] +@ve = unpack("v16", $boot_cat); +$cs = 0; +for ($i = 0; $i < 16; $i++) { + $cs += $ve[$i]; +} +if ($ve[0] != 0x0001 || $ve[15] != 0xaa55 || $cs & 0xffff) { + die "$0: $file: invalid boot catalog\n"; +} +($de_boot, $de_media, $de_seg, $de_sys, $de_mbz1, $de_count, + $de_lba, $de_mbz2) = unpack("CCvCCvVv", substr($boot_cat, 32, 32)); +if ($de_boot != 0x88 || $de_media != 0 || + ($de_segment != 0 && $de_segment != 0x7c0) || $de_count != 4) { + die "$0: $file: unexpected boot catalog parameters\n"; +} + +# Get the total size of the image +(@imgstat = stat(FILE)) or die "$0: $file: $!\n"; +$imgsize = $imgstat[7]; +if (!$imgsize) { + die "$0: $file: cannot determine length of file\n"; +} +# Target image size: round up to a multiple of $h*$s*512 +$cylsize = $h*$s*512; +$frac = $imgsize % $cylsize; +$padding = ($frac > 0) ? $cylsize - $frac : 0; +$imgsize += $padding; +$c = $imgsize/$cylsize; +if ($c > 1024) { + print STDERR "Warning: more than 1024 cylinders ($c).\n"; + print STDERR "Not all BIOSes will be able to boot this device.\n"; + $cc = 1024; +} else { + $cc = $c; +} + +# Now $de_lba should contain the CD sector number for isolinux.bin +seek(FILE, 0, SEEK_SET) or die "$0: $file: $!\n"; + +# Print the MBR and partition table +$mbr = ''; +while ( $line = <DATA> ) { + chomp $line; + foreach $byte ( split(/\s+/, $line) ) { + $mbr .= chr(hex($byte)); + } +} +if ( length($mbr) > 432 ) { + die "$0: Bad MBR code\n"; +} + +$mbr .= "\0" x (432 - length($mbr)); + +$mbr .= pack("VV", $de_lba*4, 0); # Offset 432: LBA of isolinux.bin +if (defined($id)) { + $id = to_int($id); +} else { + $id = get_random(); +} +$mbr .= pack("V", $id); # Offset 440: MBR ID +$mbr .= "\0\0"; # Offset 446: actual partition table + +# Print partition table +$psize = $c*$h*$s-$s; +$bhead = 0; +$bsect = 1; +$bcyl = 0; +$ehead = $h-1; +$esect = $s + ((($cc-1) & 0x300) >> 2); +$ecyl = ($cc-1) & 0xff; +$fstype = 0x83; # Linux (any better ideas?) +$pentry = 1; +if ( $c > 1024 ) { + $fstype = 0x0e; +} elsif ( $psize > 65536 ) { + $fstype = 0x06; +} else { + $fstype = 0x04; +} +for ( $i = 1 ; $i <= 4 ; $i++ ) { + if ( $i == $pentry ) { + $mbr .= pack("CCCCCCCCVV", 0x80, $bhead, $bsect, $bcyl, $fstype, + $ehead, $esect, $ecyl, $s, $psize); + } else { + $mbr .= "\0" x 16; + } +} +$mbr .= "\x55\xaa"; + +print FILE $mbr; + +# Pad the image to a fake cylinder boundary +seek(FILE, $imgstat[7], SEEK_SET) or die "$0: $file: $!\n"; +if ($padding) { + print FILE "\0" x $padding; +} + +# Done... +close(FILE); + +exit 0; +__END__ |