• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/perl
2## -----------------------------------------------------------------------
3##
4##   Copyright 2002-2008 H. Peter Anvin - All Rights Reserved
5##   Copyright 2009 Intel Corporation; author: H. Peter Anvin
6##
7##   This program is free software; you can redistribute it and/or modify
8##   it under the terms of the GNU General Public License as published by
9##   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
10##   Boston MA 02111-1307, USA; either version 2 of the License, or
11##   (at your option) any later version; incorporated herein by reference.
12##
13## -----------------------------------------------------------------------
14
15#
16# Post-process an ISO 9660 image generated with mkisofs/genisoimage
17# to allow "hybrid booting" as a CD-ROM or as a hard disk.
18#
19
20use bytes;
21use Fcntl;
22
23# User-specifyable options
24%opt = (
25    # Fake geometry (zipdrive-style...)
26    'h'      => 64,
27    's'      => 32,
28    # Partition number
29    'entry'  => 1,
30    # Partition offset
31    'offset' => 0,
32    # Partition type
33    'type'   => 0x17,		# "Windows hidden IFS"
34    # MBR ID
35    'id'     => undef,
36);
37
38%valid_range = (
39    'h'      => [1, 256],
40    's'      => [1, 63],
41    'entry'  => [1, 4],
42    'offset' => [0, 64],
43    'type'   => [0, 255],
44    'id'     => [0, 0xffffffff],
45    'hd0'    => [0, 2],
46    'partok' => [0, 1],
47);
48
49# Boolean options just set other options
50%bool_opt = (
51    'nohd0'    => ['hd0', 0],
52    'forcehd0' => ['hd0', 1],
53    'ctrlhd0'  => ['hd0', 2],
54    'nopartok' => ['partok', 0],
55    'partok'   => ['partok', 1],
56);
57
58sub usage() {
59    print STDERR "Usage: $0 [options] filename.iso\n",
60    "Options:\n",
61    "  -h          Number of default geometry heads\n",
62    "  -s          Number of default geometry sectors\n",
63    "  -entry      Specify partition entry number (1-4)\n",
64    "  -offset     Specify partition offset (default 0)\n",
65    "  -type       Specify partition type (default 0x17)\n",
66    "  -id         Specify MBR ID (default random)\n",
67    "  -forcehd0   Always assume we are loaded as disk ID 0\n",
68    "  -ctrlhd0    Assume disk ID 0 if the Ctrl key is pressed\n",
69    "  -partok     Allow booting from within a partition\n";
70    exit 1;
71}
72
73# Parse a C-style integer (decimal/octal/hex)
74sub doh($) {
75    my($n) = @_;
76    return ($n =~ /^0/) ? oct $n : $n+0;
77}
78
79sub get_random() {
80    # Get a 32-bit random number
81    my $rfd, $rnd;
82    my $rid;
83
84    if (open($rfd, "< /dev/urandom\0") && read($rfd, $rnd, 4) == 4) {
85	$rid = unpack("V", $rnd);
86    }
87
88    close($rfd) if (defined($rfd));
89    return $rid if (defined($rid));
90
91    # This sucks but is better than nothing...
92    return ($$+time()) & 0xffffffff;
93}
94
95sub get_hex_data() {
96    my $mbr = '';
97    my $line, $byte;
98    while ( $line = <DATA> ) {
99	chomp $line;
100	last if ($line eq '*');
101	foreach $byte ( split(/\s+/, $line) ) {
102	    $mbr .= chr(hex($byte));
103	}
104    }
105    return $mbr;
106}
107
108while ($ARGV[0] =~ /^\-(.*)$/) {
109    $o = $1;
110    shift @ARGV;
111    if (defined($bool_opt{$o})) {
112	($o, $v) = @{$bool_opt{$o}};
113	$opt{$o} = $v;
114    } elsif (exists($opt{$o})) {
115	$opt{$o} = doh(shift @ARGV);
116	if (defined($valid_range{$o})) {
117	    ($l, $h) = @{$valid_range{$o}};
118	    if ($opt{$o} < $l || $opt{$o} > $h) {
119		die "$0: valid values for the -$o parameter are $l to $h\n";
120	    }
121	}
122    } else {
123	usage();
124    }
125}
126
127($file) = @ARGV;
128
129if (!defined($file)) {
130    usage();
131}
132
133open(FILE, "+< $file\0") or die "$0: cannot open $file: $!\n";
134binmode FILE;
135
136#
137# First, actually figure out where mkisofs hid isolinux.bin
138#
139seek(FILE, 17*2048, SEEK_SET) or die "$0: $file: $!\n";
140read(FILE, $boot_record, 2048) == 2048 or die "$0: $file: read error\n";
141($br_sign, $br_cat_offset) = unpack("a71V", $boot_record);
142if ($br_sign ne ("\0CD001\1EL TORITO SPECIFICATION" . ("\0" x 41))) {
143    die "$0: $file: no boot record found\n";
144}
145seek(FILE, $br_cat_offset*2048, SEEK_SET) or die "$0: $file: $!\n";
146read(FILE, $boot_cat, 2048) == 2048 or die "$0: $file: read error\n";
147
148# We must have a Validation Entry followed by a Default Entry...
149# no fanciness allowed for the Hybrid mode [XXX: might relax this later]
150@ve = unpack("v16", $boot_cat);
151$cs = 0;
152for ($i = 0; $i < 16; $i++) {
153    $cs += $ve[$i];
154}
155if ($ve[0] != 0x0001 || $ve[15] != 0xaa55 || $cs & 0xffff) {
156    die "$0: $file: invalid boot catalog\n";
157}
158($de_boot, $de_media, $de_seg, $de_sys, $de_mbz1, $de_count,
159 $de_lba, $de_mbz2) = unpack("CCvCCvVv", substr($boot_cat, 32, 32));
160if ($de_boot != 0x88 || $de_media != 0 ||
161    ($de_segment != 0 && $de_segment != 0x7c0) || $de_count != 4) {
162    die "$0: $file: unexpected boot catalog parameters\n";
163}
164
165# Now $de_lba should contain the CD sector number for isolinux.bin
166seek(FILE, $de_lba*2048+0x40, SEEK_SET) or die "$0: $file: $!\n";
167read(FILE, $ibsig, 4);
168if ($ibsig ne "\xfb\xc0\x78\x70") {
169    die "$0: $file: bootloader does not have a isolinux.bin hybrid signature.".
170        "Note that isolinux-debug.bin does not support hybrid booting.\n";
171}
172
173# Get the total size of the image
174(@imgstat = stat(FILE)) or die "$0: $file: $!\n";
175$imgsize = $imgstat[7];
176if (!$imgsize) {
177    die "$0: $file: cannot determine length of file\n";
178}
179# Target image size: round up to a multiple of $h*$s*512
180$h = $opt{'h'};
181$s = $opt{'s'};
182$cylsize = $h*$s*512;
183$frac = $imgsize % $cylsize;
184$padding = ($frac > 0) ? $cylsize - $frac : 0;
185$imgsize += $padding;
186$c = int($imgsize/$cylsize);
187if ($c > 1024) {
188    print STDERR "Warning: more than 1024 cylinders ($c).\n";
189    print STDERR "Not all BIOSes will be able to boot this device.\n";
190    $cc = 1024;
191} else {
192    $cc = $c;
193}
194
195# Preserve id when run again
196if (defined($opt{'id'})) {
197    $id = pack("V", doh($opt{'id'}));
198} else {
199    seek(FILE, 440, SEEK_SET) or die "$0: $file: $!\n";
200    read(FILE, $id, 4);
201    if ($id eq "\x00\x00\x00\x00") {
202	$id = pack("V", get_random());
203    }
204}
205
206# Print the MBR and partition table
207seek(FILE, 0, SEEK_SET) or die "$0: $file: $!\n";
208
209for ($i = 0; $i <= $opt{'hd0'}+3*$opt{'partok'}; $i++) {
210    $mbr = get_hex_data();
211}
212if ( length($mbr) > 432 ) {
213    die "$0: Bad MBR code\n";
214}
215
216$mbr .= "\0" x (432 - length($mbr));
217
218$mbr .= pack("VV", $de_lba*4, 0); 	# Offset 432: LBA of isolinux.bin
219$mbr .= $id;				# Offset 440: MBR ID
220$mbr .= "\0\0";				# Offset 446: actual partition table
221
222# Print partition table
223$offset  = $opt{'offset'};
224$psize   = $c*$h*$s - $offset;
225$bhead   = int($offset/$s) % $h;
226$bsect   = ($offset % $s) + 1;
227$bcyl    = int($offset/($h*$s));
228$bsect  += ($bcyl & 0x300) >> 2;
229$bcyl   &= 0xff;
230$ehead   = $h-1;
231$esect   = $s + ((($cc-1) & 0x300) >> 2);
232$ecyl    = ($cc-1) & 0xff;
233$fstype  = $opt{'type'};	# Partition type
234$pentry  = $opt{'entry'};	# Partition slot
235
236for ( $i = 1 ; $i <= 4 ; $i++ ) {
237    if ( $i == $pentry ) {
238	$mbr .= pack("CCCCCCCCVV", 0x80, $bhead, $bsect, $bcyl, $fstype,
239		     $ehead, $esect, $ecyl, $offset, $psize);
240    } else {
241	$mbr .= "\0" x 16;
242    }
243}
244$mbr .= "\x55\xaa";
245
246print FILE $mbr;
247
248# Pad the image to a fake cylinder boundary
249seek(FILE, $imgstat[7], SEEK_SET) or die "$0: $file: $!\n";
250if ($padding) {
251    print FILE "\0" x $padding;
252}
253
254# Done...
255close(FILE);
256
257exit 0;
258__END__
25933 ed 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
26090 90 90 90 90 90 90 33 ed fa 8e d5 bc 0 7c fb fc 66 31 db 66 31 c9 66 53
26166 51 6 57 8e dd 8e c5 52 be 0 7c bf 0 6 b9 0 1 f3 a5 ea 4b 6 0 0 52 b4 41
262bb aa 55 31 c9 30 f6 f9 cd 13 72 16 81 fb 55 aa 75 10 83 e1 1 74 b 66 c7 6
263f1 6 b4 42 eb 15 eb 0 5a 51 b4 8 cd 13 83 e1 3f 5b 51 f b6 c6 40 50 f7 e1
26453 52 50 bb 0 7c b9 4 0 66 a1 b0 7 e8 44 0 f 82 80 0 66 40 80 c7 2 e2 f2 66
26581 3e 40 7c fb c0 78 70 75 9 fa bc ec 7b ea 44 7c 0 0 e8 83 0 69 73 6f 6c
26669 6e 75 78 2e 62 69 6e 20 6d 69 73 73 69 6e 67 20 6f 72 20 63 6f 72 72 75
26770 74 2e d a 66 60 66 31 d2 66 3 6 f8 7b 66 13 16 fc 7b 66 52 66 50 6 53 6a
2681 6a 10 89 e6 66 f7 36 e8 7b c0 e4 6 88 e1 88 c5 92 f6 36 ee 7b 88 c6 8 e1
26941 b8 1 2 8a 16 f2 7b cd 13 8d 64 10 66 61 c3 e8 1e 0 4f 70 65 72 61 74 69
2706e 67 20 73 79 73 74 65 6d 20 6c 6f 61 64 20 65 72 72 6f 72 2e d a 5e ac b4
271e 8a 3e 62 4 b3 7 cd 10 3c a 75 f1 cd 18 f4 eb fd 0 0 0 0 0 0 0 0 0 0 0 0
2720 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2730 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2740 0 0 0 0 0 0 0 0 0 0 0 0 0
275*
27633 ed 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
27790 90 90 90 90 90 90 33 ed fa 8e d5 bc 0 7c fb fc 66 31 db 66 31 c9 66 53
27866 51 6 57 8e dd 8e c5 b2 80 52 be 0 7c bf 0 6 b9 0 1 f3 a5 ea 4d 6 0 0 52
279b4 41 bb aa 55 31 c9 30 f6 f9 cd 13 72 16 81 fb 55 aa 75 10 83 e1 1 74 b 66
280c7 6 f3 6 b4 42 eb 15 eb 0 5a 51 b4 8 cd 13 83 e1 3f 5b 51 f b6 c6 40 50 f7
281e1 53 52 50 bb 0 7c b9 4 0 66 a1 b0 7 e8 44 0 f 82 80 0 66 40 80 c7 2 e2 f2
28266 81 3e 40 7c fb c0 78 70 75 9 fa bc ec 7b ea 44 7c 0 0 e8 83 0 69 73 6f
2836c 69 6e 75 78 2e 62 69 6e 20 6d 69 73 73 69 6e 67 20 6f 72 20 63 6f 72 72
28475 70 74 2e d a 66 60 66 31 d2 66 3 6 f8 7b 66 13 16 fc 7b 66 52 66 50 6 53
2856a 1 6a 10 89 e6 66 f7 36 e8 7b c0 e4 6 88 e1 88 c5 92 f6 36 ee 7b 88 c6 8
286e1 41 b8 1 2 8a 16 f2 7b cd 13 8d 64 10 66 61 c3 e8 1e 0 4f 70 65 72 61 74
28769 6e 67 20 73 79 73 74 65 6d 20 6c 6f 61 64 20 65 72 72 6f 72 2e d a 5e ac
288b4 e 8a 3e 62 4 b3 7 cd 10 3c a 75 f1 cd 18 f4 eb fd 0 0 0 0 0 0 0 0 0 0 0
2890 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2900 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2910 0 0 0 0 0 0 0 0 0 0 0 0
292*
29333 ed 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
29490 90 90 90 90 90 90 33 ed fa 8e d5 bc 0 7c fb fc 66 31 db 66 31 c9 66 53
29566 51 6 57 8e dd 8e c5 60 b4 2 cd 16 a8 4 61 74 2 b2 80 52 be 0 7c bf 0 6
296b9 0 1 f3 a5 ea 57 6 0 0 52 b4 41 bb aa 55 31 c9 30 f6 f9 cd 13 72 16 81 fb
29755 aa 75 10 83 e1 1 74 b 66 c7 6 fd 6 b4 42 eb 15 eb 0 5a 51 b4 8 cd 13 83
298e1 3f 5b 51 f b6 c6 40 50 f7 e1 53 52 50 bb 0 7c b9 4 0 66 a1 b0 7 e8 44 0
299f 82 80 0 66 40 80 c7 2 e2 f2 66 81 3e 40 7c fb c0 78 70 75 9 fa bc ec 7b
300ea 44 7c 0 0 e8 83 0 69 73 6f 6c 69 6e 75 78 2e 62 69 6e 20 6d 69 73 73 69
3016e 67 20 6f 72 20 63 6f 72 72 75 70 74 2e d a 66 60 66 31 d2 66 3 6 f8 7b
30266 13 16 fc 7b 66 52 66 50 6 53 6a 1 6a 10 89 e6 66 f7 36 e8 7b c0 e4 6 88
303e1 88 c5 92 f6 36 ee 7b 88 c6 8 e1 41 b8 1 2 8a 16 f2 7b cd 13 8d 64 10 66
30461 c3 e8 1e 0 4f 70 65 72 61 74 69 6e 67 20 73 79 73 74 65 6d 20 6c 6f 61
30564 20 65 72 72 6f 72 2e d a 5e ac b4 e 8a 3e 62 4 b3 7 cd 10 3c a 75 f1 cd
30618 f4 eb fd 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3070 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3080 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
309*
31033 ed 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
31190 90 90 90 90 90 90 33 ed fa 8e d5 bc 0 7c fb fc 66 31 db 66 31 c9 21 f6
31274 26 f6 4 7f 75 21 38 4c 4 74 1c 66 3d 21 47 50 58 75 10 80 7c 4 ed 75 a
31366 8b 4c 34 66 8b 5c 38 eb 4 66 8b 4c 8 66 53 66 51 6 57 8e dd 8e c5 52 be
3140 7c bf 0 6 b9 0 1 f3 a5 ea 75 6 0 0 52 b4 41 bb aa 55 31 c9 30 f6 f9 cd 13
31572 16 81 fb 55 aa 75 10 83 e1 1 74 b 66 c7 6 1b 7 b4 42 eb 15 eb 0 5a 51 b4
3168 cd 13 83 e1 3f 5b 51 f b6 c6 40 50 f7 e1 53 52 50 bb 0 7c b9 4 0 66 a1 b0
3177 e8 44 0 f 82 80 0 66 40 80 c7 2 e2 f2 66 81 3e 40 7c fb c0 78 70 75 9 fa
318bc ec 7b ea 44 7c 0 0 e8 83 0 69 73 6f 6c 69 6e 75 78 2e 62 69 6e 20 6d 69
31973 73 69 6e 67 20 6f 72 20 63 6f 72 72 75 70 74 2e d a 66 60 66 31 d2 66 3
3206 f8 7b 66 13 16 fc 7b 66 52 66 50 6 53 6a 1 6a 10 89 e6 66 f7 36 e8 7b c0
321e4 6 88 e1 88 c5 92 f6 36 ee 7b 88 c6 8 e1 41 b8 1 2 8a 16 f2 7b cd 13 8d
32264 10 66 61 c3 e8 1e 0 4f 70 65 72 61 74 69 6e 67 20 73 79 73 74 65 6d 20
3236c 6f 61 64 20 65 72 72 6f 72 2e d a 5e ac b4 e 8a 3e 62 4 b3 7 cd 10 3c a
32475 f1 cd 18 f4 eb fd 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
326*
32733 ed 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
32890 90 90 90 90 90 90 33 ed fa 8e d5 bc 0 7c fb fc 66 31 db 66 31 c9 21 f6
32974 26 f6 4 7f 75 21 38 4c 4 74 1c 66 3d 21 47 50 58 75 10 80 7c 4 ed 75 a
33066 8b 4c 34 66 8b 5c 38 eb 4 66 8b 4c 8 66 53 66 51 6 57 8e dd 8e c5 b2 80
33152 be 0 7c bf 0 6 b9 0 1 f3 a5 ea 77 6 0 0 52 b4 41 bb aa 55 31 c9 30 f6 f9
332cd 13 72 16 81 fb 55 aa 75 10 83 e1 1 74 b 66 c7 6 1d 7 b4 42 eb 15 eb 0 5a
33351 b4 8 cd 13 83 e1 3f 5b 51 f b6 c6 40 50 f7 e1 53 52 50 bb 0 7c b9 4 0 66
334a1 b0 7 e8 44 0 f 82 80 0 66 40 80 c7 2 e2 f2 66 81 3e 40 7c fb c0 78 70 75
3359 fa bc ec 7b ea 44 7c 0 0 e8 83 0 69 73 6f 6c 69 6e 75 78 2e 62 69 6e 20
3366d 69 73 73 69 6e 67 20 6f 72 20 63 6f 72 72 75 70 74 2e d a 66 60 66 31 d2
33766 3 6 f8 7b 66 13 16 fc 7b 66 52 66 50 6 53 6a 1 6a 10 89 e6 66 f7 36 e8
3387b c0 e4 6 88 e1 88 c5 92 f6 36 ee 7b 88 c6 8 e1 41 b8 1 2 8a 16 f2 7b cd
33913 8d 64 10 66 61 c3 e8 1e 0 4f 70 65 72 61 74 69 6e 67 20 73 79 73 74 65
3406d 20 6c 6f 61 64 20 65 72 72 6f 72 2e d a 5e ac b4 e 8a 3e 62 4 b3 7 cd 10
3413c a 75 f1 cd 18 f4 eb fd 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3420 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
343*
34433 ed 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
34590 90 90 90 90 90 90 33 ed fa 8e d5 bc 0 7c fb fc 66 31 db 66 31 c9 21 f6
34674 26 f6 4 7f 75 21 38 4c 4 74 1c 66 3d 21 47 50 58 75 10 80 7c 4 ed 75 a
34766 8b 4c 34 66 8b 5c 38 eb 4 66 8b 4c 8 66 53 66 51 6 57 8e dd 8e c5 60 b4
3482 cd 16 a8 4 61 74 2 b2 80 52 be 0 7c bf 0 6 b9 0 1 f3 a5 ea 81 6 0 0 52 b4
34941 bb aa 55 31 c9 30 f6 f9 cd 13 72 16 81 fb 55 aa 75 10 83 e1 1 74 b 66 c7
3506 27 7 b4 42 eb 15 eb 0 5a 51 b4 8 cd 13 83 e1 3f 5b 51 f b6 c6 40 50 f7 e1
35153 52 50 bb 0 7c b9 4 0 66 a1 b0 7 e8 44 0 f 82 80 0 66 40 80 c7 2 e2 f2 66
35281 3e 40 7c fb c0 78 70 75 9 fa bc ec 7b ea 44 7c 0 0 e8 83 0 69 73 6f 6c
35369 6e 75 78 2e 62 69 6e 20 6d 69 73 73 69 6e 67 20 6f 72 20 63 6f 72 72 75
35470 74 2e d a 66 60 66 31 d2 66 3 6 f8 7b 66 13 16 fc 7b 66 52 66 50 6 53 6a
3551 6a 10 89 e6 66 f7 36 e8 7b c0 e4 6 88 e1 88 c5 92 f6 36 ee 7b 88 c6 8 e1
35641 b8 1 2 8a 16 f2 7b cd 13 8d 64 10 66 61 c3 e8 1e 0 4f 70 65 72 61 74 69
3576e 67 20 73 79 73 74 65 6d 20 6c 6f 61 64 20 65 72 72 6f 72 2e d a 5e ac b4
358e 8a 3e 62 4 b3 7 cd 10 3c a 75 f1 cd 18 f4 eb fd 0 0 0 0 0 0 0 0 0 0 0 0
3590 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
360*
361