aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-09-05 14:49:42 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-09-05 14:49:42 -0700
commit058dd028ac7d8ae217d1b3b00213751d63034195 (patch)
tree53bd1e95555370d939258873062db00c7d74bf7d /utils
parent1eb0d6f7cfa7547470580d821ca815e20df4e93e (diff)
downloadsyslinux-058dd028ac7d8ae217d1b3b00213751d63034195.tar.gz
syslinux-058dd028ac7d8ae217d1b3b00213751d63034195.tar.xz
syslinux-058dd028ac7d8ae217d1b3b00213751d63034195.zip
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/Makefile6
-rw-r--r--utils/isohybrid.in165
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__