2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 FILE_LICENCE ( GPL2_OR_LATER
);
24 * El Torito bootable ISO image format
32 #include <bootsector.h>
34 #include <gpxe/uaccess.h>
35 #include <gpxe/image.h>
36 #include <gpxe/segment.h>
37 #include <gpxe/ramdisk.h>
38 #include <gpxe/init.h>
40 #define ISO9660_BLKSIZE 2048
41 #define ELTORITO_VOL_DESC_OFFSET ( 17 * ISO9660_BLKSIZE )
43 /** An El Torito Boot Record Volume Descriptor */
44 struct eltorito_vol_desc
{
45 /** Boot record indicator; must be 0 */
46 uint8_t record_indicator
;
47 /** ISO-9660 identifier; must be "CD001" */
48 uint8_t iso9660_id
[5];
49 /** Version, must be 1 */
51 /** Boot system indicator; must be "EL TORITO SPECIFICATION" */
52 uint8_t system_indicator
[32];
55 /** Boot catalog sector */
57 } __attribute__ (( packed
));
59 /** An El Torito Boot Catalog Validation Entry */
60 struct eltorito_validation_entry
{
61 /** Header ID; must be 1 */
73 uint8_t id_string
[24];
76 /** Signature; must be 0xaa55 */
78 } __attribute__ (( packed
));
80 /** A bootable entry in the El Torito Boot Catalog */
81 struct eltorito_boot_entry
{
84 * Must be @c ELTORITO_BOOTABLE for a bootable ISO image
92 uint16_t load_segment
;
99 /** Starting sector */
102 uint8_t reserved_b
[20];
103 } __attribute__ (( packed
));
105 /** Boot indicator for a bootable ISO image */
106 #define ELTORITO_BOOTABLE 0x88
108 /** El Torito media types */
109 enum eltorito_media_type
{
111 ELTORITO_NO_EMULATION
= 0,
114 struct image_type eltorito_image_type
__image_type ( PROBE_NORMAL
);
117 * Calculate 16-bit word checksum
119 * @v data Data to checksum
120 * @v len Length (in bytes, must be even)
123 static unsigned int word_checksum ( void *data
, size_t len
) {
127 for ( words
= data
; len
; words
++, len
-= 2 ) {
134 * Execute El Torito image
136 * @v image El Torito image
137 * @ret rc Return status code
139 static int eltorito_exec ( struct image
*image
) {
140 struct ramdisk ramdisk
;
141 struct int13_drive int13_drive
;
142 unsigned int load_segment
= image
->priv
.ul
;
143 unsigned int load_offset
= ( load_segment
? 0 : 0x7c00 );
146 memset ( &ramdisk
, 0, sizeof ( ramdisk
) );
147 init_ramdisk ( &ramdisk
, image
->data
, image
->len
, ISO9660_BLKSIZE
);
149 memset ( &int13_drive
, 0, sizeof ( int13_drive
) );
150 int13_drive
.blockdev
= &ramdisk
.blockdev
;
151 register_int13_drive ( &int13_drive
);
153 if ( ( rc
= call_bootsector ( load_segment
, load_offset
,
154 int13_drive
.drive
) ) != 0 ) {
155 DBGC ( image
, "ElTorito %p boot failed: %s\n",
156 image
, strerror ( rc
) );
160 rc
= -ECANCELED
; /* -EIMPOSSIBLE */
162 unregister_int13_drive ( &int13_drive
);
167 * Read and verify El Torito Boot Record Volume Descriptor
169 * @v image El Torito file
170 * @ret catalog_offset Offset of Boot Catalog
171 * @ret rc Return status code
173 static int eltorito_read_voldesc ( struct image
*image
,
174 unsigned long *catalog_offset
) {
175 static const struct eltorito_vol_desc vol_desc_signature
= {
176 .record_indicator
= 0,
177 .iso9660_id
= "CD001",
179 .system_indicator
= "EL TORITO SPECIFICATION",
181 struct eltorito_vol_desc vol_desc
;
184 if ( image
->len
< ( ELTORITO_VOL_DESC_OFFSET
+ ISO9660_BLKSIZE
) ) {
185 DBGC ( image
, "ElTorito %p too short\n", image
);
189 /* Read and verify Boot Record Volume Descriptor */
190 copy_from_user ( &vol_desc
, image
->data
, ELTORITO_VOL_DESC_OFFSET
,
191 sizeof ( vol_desc
) );
192 if ( memcmp ( &vol_desc
, &vol_desc_signature
,
193 offsetof ( typeof ( vol_desc
), sector
) ) != 0 ) {
194 DBGC ( image
, "ElTorito %p invalid Boot Record Volume "
195 "Descriptor\n", image
);
198 *catalog_offset
= ( vol_desc
.sector
* ISO9660_BLKSIZE
);
200 DBGC ( image
, "ElTorito %p boot catalog at offset %#lx\n",
201 image
, *catalog_offset
);
207 * Read and verify El Torito Boot Catalog
209 * @v image El Torito file
210 * @v catalog_offset Offset of Boot Catalog
211 * @ret boot_entry El Torito boot entry
212 * @ret rc Return status code
214 static int eltorito_read_catalog ( struct image
*image
,
215 unsigned long catalog_offset
,
216 struct eltorito_boot_entry
*boot_entry
) {
217 struct eltorito_validation_entry validation_entry
;
220 if ( image
->len
< ( catalog_offset
+ ISO9660_BLKSIZE
) ) {
221 DBGC ( image
, "ElTorito %p bad boot catalog offset %#lx\n",
222 image
, catalog_offset
);
226 /* Read and verify the Validation Entry of the Boot Catalog */
227 copy_from_user ( &validation_entry
, image
->data
, catalog_offset
,
228 sizeof ( validation_entry
) );
229 if ( word_checksum ( &validation_entry
,
230 sizeof ( validation_entry
) ) != 0 ) {
231 DBGC ( image
, "ElTorito %p bad Validation Entry checksum\n",
236 /* Read and verify the Initial/Default entry */
237 copy_from_user ( boot_entry
, image
->data
,
238 ( catalog_offset
+ sizeof ( validation_entry
) ),
239 sizeof ( *boot_entry
) );
240 if ( boot_entry
->indicator
!= ELTORITO_BOOTABLE
) {
241 DBGC ( image
, "ElTorito %p not bootable\n", image
);
244 if ( boot_entry
->media_type
!= ELTORITO_NO_EMULATION
) {
245 DBGC ( image
, "ElTorito %p cannot support media type %d\n",
246 image
, boot_entry
->media_type
);
250 DBGC ( image
, "ElTorito %p media type %d segment %04x\n",
251 image
, boot_entry
->media_type
, boot_entry
->load_segment
);
257 * Load El Torito virtual disk image into memory
259 * @v image El Torito file
260 * @v boot_entry El Torito boot entry
261 * @ret rc Return status code
263 static int eltorito_load_disk ( struct image
*image
,
264 struct eltorito_boot_entry
*boot_entry
) {
265 unsigned long start
= ( boot_entry
->start
* ISO9660_BLKSIZE
);
266 unsigned long length
= ( boot_entry
->length
* ISO9660_BLKSIZE
);
267 unsigned int load_segment
;
272 if ( image
->len
< ( start
+ length
) ) {
273 DBGC ( image
, "ElTorito %p virtual disk lies outside image\n",
277 DBGC ( image
, "ElTorito %p virtual disk at %#lx+%#lx\n",
278 image
, start
, length
);
280 /* Calculate load address */
281 load_segment
= boot_entry
->load_segment
;
282 buffer
= real_to_user ( load_segment
, ( load_segment
? 0 : 0x7c00 ) );
284 /* Verify and prepare segment */
285 if ( ( rc
= prep_segment ( buffer
, length
, length
) ) != 0 ) {
286 DBGC ( image
, "ElTorito %p could not prepare segment: %s\n",
287 image
, strerror ( rc
) );
291 /* Copy image to segment */
292 memcpy_user ( buffer
, 0, image
->data
, start
, length
);
298 * Load El Torito image into memory
300 * @v image El Torito file
301 * @ret rc Return status code
303 static int eltorito_load ( struct image
*image
) {
304 struct eltorito_boot_entry boot_entry
;
305 unsigned long bootcat_offset
;
308 /* Read Boot Record Volume Descriptor, if present */
309 if ( ( rc
= eltorito_read_voldesc ( image
, &bootcat_offset
) ) != 0 )
312 /* This is an El Torito image, valid or otherwise */
314 image
->type
= &eltorito_image_type
;
316 /* Read Boot Catalog */
317 if ( ( rc
= eltorito_read_catalog ( image
, bootcat_offset
,
318 &boot_entry
) ) != 0 )
321 /* Load Virtual Disk image */
322 if ( ( rc
= eltorito_load_disk ( image
, &boot_entry
) ) != 0 )
325 /* Record load segment in image private data field */
326 image
->priv
.ul
= boot_entry
.load_segment
;
331 /** El Torito image type */
332 struct image_type eltorito_image_type
__image_type ( PROBE_NORMAL
) = {
334 .load
= eltorito_load
,
335 .exec
= eltorito_exec
,