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.
22 * El Torito bootable ISO image format
30 #include <bootsector.h>
32 #include <gpxe/uaccess.h>
33 #include <gpxe/image.h>
34 #include <gpxe/segment.h>
35 #include <gpxe/ramdisk.h>
36 #include <gpxe/shutdown.h>
38 #define ISO9660_BLKSIZE 2048
39 #define ELTORITO_VOL_DESC_OFFSET ( 17 * ISO9660_BLKSIZE )
41 /** An El Torito Boot Record Volume Descriptor */
42 struct eltorito_vol_desc {
43 /** Boot record indicator; must be 0 */
44 uint8_t record_indicator;
45 /** ISO-9660 identifier; must be "CD001" */
46 uint8_t iso9660_id[5];
47 /** Version, must be 1 */
49 /** Boot system indicator; must be "EL TORITO SPECIFICATION" */
50 uint8_t system_indicator[32];
53 /** Boot catalog sector */
55 } __attribute__ (( packed ));
57 /** An El Torito Boot Catalog Validation Entry */
58 struct eltorito_validation_entry {
59 /** Header ID; must be 1 */
71 uint8_t id_string[24];
74 /** Signature; must be 0xaa55 */
76 } __attribute__ (( packed ));
78 /** A bootable entry in the El Torito Boot Catalog */
79 struct eltorito_boot_entry {
82 * Must be @c ELTORITO_BOOTABLE for a bootable ISO image
90 uint16_t load_segment;
97 /** Starting sector */
100 uint8_t reserved_b[20];
101 } __attribute__ (( packed ));
103 /** Boot indicator for a bootable ISO image */
104 #define ELTORITO_BOOTABLE 0x88
106 /** El Torito media types */
107 enum eltorito_media_type {
109 ELTORITO_NO_EMULATION = 0,
112 struct image_type eltorito_image_type __image_type ( PROBE_NORMAL );
115 * Calculate 16-bit word checksum
117 * @v data Data to checksum
118 * @v len Length (in bytes, must be even)
121 static unsigned int word_checksum ( void *data, size_t len ) {
125 for ( words = data ; len ; words++, len -= 2 ) {
132 * Execute El Torito image
134 * @v image El Torito image
135 * @ret rc Return status code
137 static int eltorito_exec ( struct image *image ) {
138 struct ramdisk ramdisk;
139 struct int13_drive int13_drive;
140 unsigned int load_segment = image->priv.ul;
141 unsigned int load_offset = ( load_segment ? 0 : 0x7c00 );
144 memset ( &ramdisk, 0, sizeof ( ramdisk ) );
145 init_ramdisk ( &ramdisk, image->data, image->len, ISO9660_BLKSIZE );
147 memset ( &int13_drive, 0, sizeof ( int13_drive ) );
148 int13_drive.blockdev = &ramdisk.blockdev;
149 register_int13_drive ( &int13_drive );
151 if ( ( rc = call_bootsector ( load_segment, load_offset,
152 int13_drive.drive ) ) != 0 ) {
153 DBGC ( image, "ElTorito %p boot failed: %s\n",
154 image, strerror ( rc ) );
158 rc = -ECANCELED; /* -EIMPOSSIBLE */
160 unregister_int13_drive ( &int13_drive );
165 * Read and verify El Torito Boot Record Volume Descriptor
167 * @v image El Torito file
168 * @ret catalog_offset Offset of Boot Catalog
169 * @ret rc Return status code
171 static int eltorito_read_voldesc ( struct image *image,
172 unsigned long *catalog_offset ) {
173 static const struct eltorito_vol_desc vol_desc_signature = {
174 .record_indicator = 0,
175 .iso9660_id = "CD001",
177 .system_indicator = "EL TORITO SPECIFICATION",
179 struct eltorito_vol_desc vol_desc;
182 if ( image->len < ( ELTORITO_VOL_DESC_OFFSET + ISO9660_BLKSIZE ) ) {
183 DBGC ( image, "ElTorito %p too short\n", image );
187 /* Read and verify Boot Record Volume Descriptor */
188 copy_from_user ( &vol_desc, image->data, ELTORITO_VOL_DESC_OFFSET,
189 sizeof ( vol_desc ) );
190 if ( memcmp ( &vol_desc, &vol_desc_signature,
191 offsetof ( typeof ( vol_desc ), sector ) ) != 0 ) {
192 DBGC ( image, "ElTorito %p invalid Boot Record Volume "
193 "Descriptor\n", image );
196 *catalog_offset = ( vol_desc.sector * ISO9660_BLKSIZE );
198 DBGC ( image, "ElTorito %p boot catalog at offset %#lx\n",
199 image, *catalog_offset );
205 * Read and verify El Torito Boot Catalog
207 * @v image El Torito file
208 * @v catalog_offset Offset of Boot Catalog
209 * @ret boot_entry El Torito boot entry
210 * @ret rc Return status code
212 static int eltorito_read_catalog ( struct image *image,
213 unsigned long catalog_offset,
214 struct eltorito_boot_entry *boot_entry ) {
215 struct eltorito_validation_entry validation_entry;
218 if ( image->len < ( catalog_offset + ISO9660_BLKSIZE ) ) {
219 DBGC ( image, "ElTorito %p bad boot catalog offset %#lx\n",
220 image, catalog_offset );
224 /* Read and verify the Validation Entry of the Boot Catalog */
225 copy_from_user ( &validation_entry, image->data, catalog_offset,
226 sizeof ( validation_entry ) );
227 if ( word_checksum ( &validation_entry,
228 sizeof ( validation_entry ) ) != 0 ) {
229 DBGC ( image, "ElTorito %p bad Validation Entry checksum\n",
234 /* Read and verify the Initial/Default entry */
235 copy_from_user ( boot_entry, image->data,
236 ( catalog_offset + sizeof ( validation_entry ) ),
237 sizeof ( *boot_entry ) );
238 if ( boot_entry->indicator != ELTORITO_BOOTABLE ) {
239 DBGC ( image, "ElTorito %p not bootable\n", image );
242 if ( boot_entry->media_type != ELTORITO_NO_EMULATION ) {
243 DBGC ( image, "ElTorito %p cannot support media type %d\n",
244 image, boot_entry->media_type );
248 DBGC ( image, "ElTorito %p media type %d segment %04x\n",
249 image, boot_entry->media_type, boot_entry->load_segment );
255 * Load El Torito virtual disk image into memory
257 * @v image El Torito file
258 * @v boot_entry El Torito boot entry
259 * @ret rc Return status code
261 static int eltorito_load_disk ( struct image *image,
262 struct eltorito_boot_entry *boot_entry ) {
263 unsigned long start = ( boot_entry->start * ISO9660_BLKSIZE );
264 unsigned long length = ( boot_entry->length * ISO9660_BLKSIZE );
265 unsigned int load_segment;
270 if ( image->len < ( start + length ) ) {
271 DBGC ( image, "ElTorito %p virtual disk lies outside image\n",
275 DBGC ( image, "ElTorito %p virtual disk at %#lx+%#lx\n",
276 image, start, length );
278 /* Calculate load address */
279 load_segment = boot_entry->load_segment;
280 buffer = real_to_user ( load_segment, ( load_segment ? 0 : 0x7c00 ) );
282 /* Verify and prepare segment */
283 if ( ( rc = prep_segment ( buffer, length, length ) ) != 0 ) {
284 DBGC ( image, "ElTorito %p could not prepare segment: %s\n",
285 image, strerror ( rc ) );
289 /* Copy image to segment */
290 memcpy_user ( buffer, 0, image->data, start, length );
296 * Load El Torito image into memory
298 * @v image El Torito file
299 * @ret rc Return status code
301 int eltorito_load ( struct image *image ) {
302 struct eltorito_boot_entry boot_entry;
303 unsigned long bootcat_offset;
306 /* Read Boot Record Volume Descriptor, if present */
307 if ( ( rc = eltorito_read_voldesc ( image, &bootcat_offset ) ) != 0 )
310 /* This is an El Torito image, valid or otherwise */
312 image->type = &eltorito_image_type;
314 /* Read Boot Catalog */
315 if ( ( rc = eltorito_read_catalog ( image, bootcat_offset,
316 &boot_entry ) ) != 0 )
319 /* Load Virtual Disk image */
320 if ( ( rc = eltorito_load_disk ( image, &boot_entry ) ) != 0 )
323 /* Record load segment in image private data field */
324 image->priv.ul = boot_entry.load_segment;
329 /** El Torito image type */
330 struct image_type eltorito_image_type __image_type ( PROBE_NORMAL ) = {
332 .load = eltorito_load,
333 .exec = eltorito_exec,