Explorar el Código

[int13] Add support for El Torito bootable CD-ROM images

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown hace 13 años
padre
commit
00d0226fee
Se han modificado 2 ficheros con 486 adiciones y 48 borrados
  1. 133
    0
      src/arch/i386/include/int13.h
  2. 353
    48
      src/arch/i386/interface/pcbios/int13.c

+ 133
- 0
src/arch/i386/include/int13.h Ver fichero

@@ -45,6 +45,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
45 45
 #define INT13_GET_EXTENDED_PARAMETERS	0x48
46 46
 /** Get CD-ROM status / terminate emulation */
47 47
 #define INT13_CDROM_STATUS_TERMINATE	0x4b
48
+/** Read CD-ROM boot catalog */
49
+#define INT13_CDROM_READ_BOOT_CATALOG	0x4d
48 50
 
49 51
 /** @} */
50 52
 
@@ -217,6 +219,18 @@ struct int13_cdrom_specification {
217 219
 	uint8_t head;
218 220
 } __attribute__ (( packed ));
219 221
 
222
+/** Bootable CD-ROM boot catalog command packet */
223
+struct int13_cdrom_boot_catalog_command {
224
+	/** Size of packet in bytes */
225
+	uint8_t size;
226
+	/** Number of sectors of boot catalog to read */
227
+	uint8_t count;
228
+	/** Buffer for boot catalog */
229
+	uint32_t buffer;
230
+	/** First sector in boot catalog to transfer */
231
+	uint16_t start;
232
+} __attribute__ (( packed ));
233
+
220 234
 /** A C/H/S address within a partition table entry */
221 235
 struct partition_chs {
222 236
 	/** Head number */
@@ -261,4 +275,123 @@ struct master_boot_record {
261 275
 	uint16_t magic;
262 276
 } __attribute__ (( packed ));
263 277
 
278
+/** MBR magic signature */
279
+#define INT13_MBR_MAGIC 0xaa55
280
+
281
+/** ISO9660 block size */
282
+#define ISO9660_BLKSIZE 2048
283
+
284
+/** An ISO9660 Primary Volume Descriptor (fixed portion) */
285
+struct iso9660_primary_descriptor_fixed {
286
+	/** Descriptor type */
287
+	uint8_t type;
288
+	/** Identifier ("CD001") */
289
+	uint8_t id[5];
290
+} __attribute__ (( packed ));
291
+
292
+/** An ISO9660 Primary Volume Descriptor */
293
+struct iso9660_primary_descriptor {
294
+	/** Fixed portion */
295
+	struct iso9660_primary_descriptor_fixed fixed;
296
+} __attribute__ (( packed ));
297
+
298
+/** ISO9660 Primary Volume Descriptor type */
299
+#define ISO9660_TYPE_PRIMARY 0x01
300
+
301
+/** ISO9660 identifier */
302
+#define ISO9660_ID "CD001"
303
+
304
+/** ISO9660 Primary Volume Descriptor block address */
305
+#define ISO9660_PRIMARY_LBA 16
306
+
307
+/** An El Torito Boot Record Volume Descriptor (fixed portion) */
308
+struct eltorito_descriptor_fixed {
309
+	/** Descriptor type */
310
+	uint8_t type;
311
+	/** Identifier ("CD001") */
312
+	uint8_t id[5];
313
+	/** Version, must be 1 */
314
+	uint8_t version;
315
+	/** Boot system indicator; must be "EL TORITO SPECIFICATION" */
316
+	uint8_t system_id[32];
317
+} __attribute__ (( packed ));
318
+
319
+/** An El Torito Boot Record Volume Descriptor */
320
+struct eltorito_descriptor {
321
+	/** Fixed portion */
322
+	struct eltorito_descriptor_fixed fixed;
323
+	/** Unused */
324
+	uint8_t unused[32];
325
+	/** Boot catalog sector */
326
+	uint32_t sector;
327
+} __attribute__ (( packed ));
328
+
329
+/** ISO9660 Boot Volume Descriptor type */
330
+#define ISO9660_TYPE_BOOT 0x00
331
+
332
+/** El Torito Boot Record Volume Descriptor block address */
333
+#define ELTORITO_LBA 17
334
+
335
+/** An El Torito Boot Catalog Validation Entry */
336
+struct eltorito_validation_entry {
337
+	/** Header ID; must be 1 */
338
+	uint8_t header_id;
339
+	/** Platform ID
340
+	 *
341
+	 * 0 = 80x86
342
+	 * 1 = PowerPC
343
+	 * 2 = Mac
344
+	 */
345
+	uint8_t platform_id;
346
+	/** Reserved */
347
+	uint16_t reserved;
348
+	/** ID string */
349
+	uint8_t id_string[24];
350
+	/** Checksum word */
351
+	uint16_t checksum;
352
+	/** Signature; must be 0xaa55 */
353
+	uint16_t signature;
354
+} __attribute__ (( packed ));
355
+
356
+/** El Torito platform IDs */
357
+enum eltorito_platform_id {
358
+	ELTORITO_PLATFORM_X86 = 0x00,
359
+	ELTORITO_PLATFORM_POWERPC = 0x01,
360
+	ELTORITO_PLATFORM_MAC = 0x02,
361
+};
362
+
363
+/** A bootable entry in the El Torito Boot Catalog */
364
+struct eltorito_boot_entry {
365
+	/** Boot indicator
366
+	 *
367
+	 * Must be @c ELTORITO_BOOTABLE for a bootable ISO image
368
+	 */
369
+	uint8_t indicator;
370
+	/** Media type
371
+	 *
372
+	 */
373
+	uint8_t media_type;
374
+	/** Load segment */
375
+	uint16_t load_segment;
376
+	/** System type */
377
+	uint8_t filesystem;
378
+	/** Unused */
379
+	uint8_t reserved_a;
380
+	/** Sector count */
381
+	uint16_t length;
382
+	/** Starting sector */
383
+	uint32_t start;
384
+	/** Unused */
385
+	uint8_t reserved_b[20];
386
+} __attribute__ (( packed ));
387
+
388
+/** Boot indicator for a bootable ISO image */
389
+#define ELTORITO_BOOTABLE 0x88
390
+
391
+/** El Torito media types */
392
+enum eltorito_media_type {
393
+	/** No emulation */
394
+	ELTORITO_NO_EMULATION = 0,
395
+};
396
+
264 397
 #endif /* INT13_H */

+ 353
- 48
src/arch/i386/interface/pcbios/int13.c Ver fichero

@@ -91,6 +91,13 @@ struct int13_drive {
91 91
 
92 92
 	/** Block device capacity */
93 93
 	struct block_device_capacity capacity;
94
+	/** INT 13 emulated blocksize shift
95
+	 *
96
+	 * To allow for emulation of CD-ROM access, this represents
97
+	 * the left-shift required to translate from INT 13 blocks to
98
+	 * underlying blocks.
99
+	 */
100
+	unsigned int blksize_shift;
94 101
 
95 102
 	/** Number of cylinders
96 103
 	 *
@@ -117,6 +124,9 @@ struct int13_drive {
117 124
 	 */
118 125
 	unsigned int sectors_per_track;
119 126
 
127
+	/** Address of El Torito boot catalog (if any) */
128
+	unsigned int boot_catalog;
129
+
120 130
 	/** Underlying device status, if in error */
121 131
 	int block_rc;
122 132
 	/** Status of last operation */
@@ -142,6 +152,37 @@ static LIST_HEAD ( int13s );
142 152
  */
143 153
 static uint8_t num_drives;
144 154
 
155
+/**
156
+ * Calculate INT 13 drive sector size
157
+ *
158
+ * @v int13		Emulated drive
159
+ * @ret blksize		Sector size
160
+ */
161
+static inline unsigned int int13_blksize ( struct int13_drive *int13 ) {
162
+	return ( int13->capacity.blksize << int13->blksize_shift );
163
+}
164
+
165
+/**
166
+ * Calculate INT 13 drive capacity
167
+ *
168
+ * @v int13		Emulated drive
169
+ * @ret blocks		Number of blocks
170
+ */
171
+static inline uint64_t int13_capacity ( struct int13_drive *int13 ) {
172
+	return ( int13->capacity.blocks >> int13->blksize_shift );
173
+}
174
+
175
+/**
176
+ * Calculate INT 13 drive capacity (limited to 32 bits)
177
+ *
178
+ * @v int13		Emulated drive
179
+ * @ret blocks		Number of blocks
180
+ */
181
+static inline uint32_t int13_capacity32 ( struct int13_drive *int13 ) {
182
+	uint64_t capacity = int13_capacity ( int13 );
183
+	return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff );
184
+}
185
+
145 186
 /** An INT 13 command */
146 187
 struct int13_command {
147 188
 	/** Status */
@@ -319,6 +360,10 @@ static int int13_rw ( struct int13_drive *int13, uint64_t lba,
319 360
 	size_t frag_len;
320 361
 	int rc;
321 362
 
363
+	/* Translate to underlying blocksize */
364
+	lba <<= int13->blksize_shift;
365
+	count <<= int13->blksize_shift;
366
+
322 367
 	while ( count ) {
323 368
 
324 369
 		/* Determine fragment length */
@@ -370,30 +415,111 @@ static int int13_read_capacity ( struct int13_drive *int13 ) {
370 415
 	return 0;
371 416
 }
372 417
 
418
+/**
419
+ * Parse ISO9660 parameters
420
+ *
421
+ * @v int13		Emulated drive
422
+ * @v scratch		Scratch area for single-sector reads
423
+ * @ret rc		Return status code
424
+ *
425
+ * Reads and parses ISO9660 parameters, if present.
426
+ */
427
+static int int13_parse_iso9660 ( struct int13_drive *int13, void *scratch ) {
428
+	static const struct iso9660_primary_descriptor_fixed primary_check = {
429
+		.type = ISO9660_TYPE_PRIMARY,
430
+		.id = ISO9660_ID,
431
+	};
432
+	struct iso9660_primary_descriptor *primary = scratch;
433
+	static const struct eltorito_descriptor_fixed boot_check = {
434
+		.type = ISO9660_TYPE_BOOT,
435
+		.id = ISO9660_ID,
436
+		.version = 1,
437
+		.system_id = "EL TORITO SPECIFICATION",
438
+	};
439
+	struct eltorito_descriptor *boot = scratch;
440
+	unsigned int blksize;
441
+	unsigned int blksize_shift;
442
+	int rc;
443
+
444
+	/* Calculate required blocksize shift */
445
+	blksize = int13_blksize ( int13 );
446
+	blksize_shift = 0;
447
+	while ( blksize < ISO9660_BLKSIZE ) {
448
+		blksize <<= 1;
449
+		blksize_shift++;
450
+	}
451
+	if ( blksize > ISO9660_BLKSIZE ) {
452
+		/* Do nothing if the blksize is invalid for CD-ROM access */
453
+		return 0;
454
+	}
455
+
456
+	/* Read primary volume descriptor */
457
+	if ( ( rc = int13_rw ( int13,
458
+			       ( ISO9660_PRIMARY_LBA << blksize_shift ), 1,
459
+			       virt_to_user ( primary ), block_read ) ) != 0 ){
460
+		DBGC ( int13, "INT13 drive %02x could not read ISO9660 "
461
+		       "primary volume descriptor: %s\n",
462
+		       int13->drive, strerror ( rc ) );
463
+		return rc;
464
+	}
465
+
466
+	/* Do nothing unless this is an ISO image */
467
+	if ( memcmp ( primary, &primary_check, sizeof ( primary_check ) ) != 0 )
468
+		return 0;
469
+	DBGC ( int13, "INT13 drive %02x contains an ISO9660 filesystem; "
470
+	       "treating as CD-ROM\n", int13->drive );
471
+
472
+	/* Read boot record volume descriptor */
473
+	if ( ( rc = int13_rw ( int13,
474
+			       ( ELTORITO_LBA << blksize_shift ), 1,
475
+			       virt_to_user ( boot ), block_read ) ) != 0 ) {
476
+		DBGC ( int13, "INT13 drive %02x could not read El Torito boot "
477
+		       "record volume descriptor: %s\n",
478
+		       int13->drive, strerror ( rc ) );
479
+		return rc;
480
+	}
481
+
482
+	/* Check for an El Torito boot catalog */
483
+	if ( memcmp ( boot, &boot_check, sizeof ( boot_check ) ) == 0 ) {
484
+		int13->boot_catalog = boot->sector;
485
+		DBGC ( int13, "INT13 drive %02x has an El Torito boot catalog "
486
+		       "at LBA %08x\n", int13->drive, int13->boot_catalog );
487
+	} else {
488
+		DBGC ( int13, "INT13 drive %02x has no El Torito boot "
489
+		       "catalog\n", int13->drive );
490
+	}
491
+
492
+	/* Configure drive for no-emulation CD-ROM access */
493
+	int13->blksize_shift += blksize_shift;
494
+
495
+	return 0;
496
+}
497
+
373 498
 /**
374 499
  * Guess INT 13 drive geometry
375 500
  *
376 501
  * @v int13		Emulated drive
502
+ * @v scratch		Scratch area for single-sector reads
377 503
  * @ret rc		Return status code
378 504
  *
379 505
  * Guesses the drive geometry by inspecting the partition table.
380 506
  */
381
-static int int13_guess_geometry ( struct int13_drive *int13 ) {
382
-	struct master_boot_record mbr;
507
+static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
508
+	struct master_boot_record *mbr = scratch;
383 509
 	struct partition_table_entry *partition;
384 510
 	unsigned int guessed_heads = 255;
385 511
 	unsigned int guessed_sectors_per_track = 63;
386
-	unsigned long blocks;
387
-	unsigned long blocks_per_cyl;
512
+	unsigned int blocks;
513
+	unsigned int blocks_per_cyl;
388 514
 	unsigned int i;
389 515
 	int rc;
390 516
 
391 517
 	/* Don't even try when the blksize is invalid for C/H/S access */
392
-	if ( int13->capacity.blksize != INT13_BLKSIZE )
518
+	if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
393 519
 		return 0;
394 520
 
395 521
 	/* Read partition table */
396
-	if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( &mbr ),
522
+	if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( mbr ),
397 523
 			       block_read ) ) != 0 ) {
398 524
 		DBGC ( int13, "INT13 drive %02x could not read partition "
399 525
 		       "table to guess geometry: %s\n",
@@ -401,15 +527,15 @@ static int int13_guess_geometry ( struct int13_drive *int13 ) {
401 527
 		return rc;
402 528
 	}
403 529
 	DBGC2 ( int13, "INT13 drive %02x has MBR:\n", int13->drive );
404
-	DBGC2_HDA ( int13, 0, &mbr, sizeof ( mbr ) );
530
+	DBGC2_HDA ( int13, 0, mbr, sizeof ( *mbr ) );
405 531
 	DBGC ( int13, "INT13 drive %02x has signature %08x\n",
406
-	       int13->drive, mbr.signature );
532
+	       int13->drive, mbr->signature );
407 533
 
408 534
 	/* Scan through partition table and modify guesses for heads
409 535
 	 * and sectors_per_track if we find any used partitions.
410 536
 	 */
411 537
 	for ( i = 0 ; i < 4 ; i++ ) {
412
-		partition = &mbr.partitions[i];
538
+		partition = &mbr->partitions[i];
413 539
 		if ( ! partition->type )
414 540
 			continue;
415 541
 		guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 );
@@ -426,8 +552,7 @@ static int int13_guess_geometry ( struct int13_drive *int13 ) {
426 552
 		int13->sectors_per_track = guessed_sectors_per_track;
427 553
 	if ( ! int13->cylinders ) {
428 554
 		/* Avoid attempting a 64-bit divide on a 32-bit system */
429
-		blocks = ( ( int13->capacity.blocks <= ULONG_MAX ) ?
430
-			   int13->capacity.blocks : ULONG_MAX );
555
+		blocks = int13_capacity32 ( int13 );
431 556
 		blocks_per_cyl = ( int13->heads * int13->sectors_per_track );
432 557
 		assert ( blocks_per_cyl != 0 );
433 558
 		int13->cylinders = ( blocks / blocks_per_cyl );
@@ -535,10 +660,10 @@ static int int13_rw_sectors ( struct int13_drive *int13,
535 660
 	int rc;
536 661
 
537 662
 	/* Validate blocksize */
538
-	if ( int13->capacity.blksize != INT13_BLKSIZE ) {
663
+	if ( int13_blksize ( int13 ) != INT13_BLKSIZE ) {
539 664
 		DBGC ( int13, "\nINT 13 drive %02x invalid blocksize (%zd) "
540 665
 		       "for non-extended read/write\n",
541
-		       int13->drive, int13->capacity.blksize );
666
+		       int13->drive, int13_blksize ( int13 ) );
542 667
 		return -INT13_STATUS_INVALID;
543 668
 	}
544 669
 	
@@ -625,6 +750,14 @@ static int int13_get_parameters ( struct int13_drive *int13,
625 750
 
626 751
 	DBGC2 ( int13, "Get drive parameters\n" );
627 752
 
753
+	/* Validate blocksize */
754
+	if ( int13_blksize ( int13 ) != INT13_BLKSIZE ) {
755
+		DBGC ( int13, "\nINT 13 drive %02x invalid blocksize (%zd) "
756
+		       "for non-extended parameters\n",
757
+		       int13->drive, int13_blksize ( int13 ) );
758
+		return -INT13_STATUS_INVALID;
759
+	}
760
+
628 761
 	ix86->regs.ch = ( max_cylinder & 0xff );
629 762
 	ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
630 763
 	ix86->regs.dh = max_head;
@@ -645,8 +778,7 @@ static int int13_get_disk_type ( struct int13_drive *int13,
645 778
 	uint32_t blocks;
646 779
 
647 780
 	DBGC2 ( int13, "Get disk type\n" );
648
-	blocks = ( ( int13->capacity.blocks <= 0xffffffffUL ) ?
649
-		   int13->capacity.blocks : 0xffffffffUL );
781
+	blocks = int13_capacity32 ( int13 );
650 782
 	ix86->regs.cx = ( blocks >> 16 );
651 783
 	ix86->regs.dx = ( blocks & 0xffff );
652 784
 	return INT13_DISK_TYPE_HDD;
@@ -916,14 +1048,14 @@ static int int13_get_extended_parameters ( struct int13_drive *int13,
916 1048
 	memset ( &params, 0, sizeof ( params ) );
917 1049
 	params.flags = INT13_FL_DMA_TRANSPARENT;
918 1050
 	if ( ( int13->cylinders < 1024 ) &&
919
-	     ( int13->capacity.blocks <= INT13_MAX_CHS_SECTORS ) ) {
1051
+	     ( int13_capacity ( int13 ) <= INT13_MAX_CHS_SECTORS ) ) {
920 1052
 		params.flags |= INT13_FL_CHS_VALID;
921 1053
 	}
922 1054
 	params.cylinders = int13->cylinders;
923 1055
 	params.heads = int13->heads;
924 1056
 	params.sectors_per_track = int13->sectors_per_track;
925
-	params.sectors = int13->capacity.blocks;
926
-	params.sector_size = int13->capacity.blksize;
1057
+	params.sectors = int13_capacity ( int13 );
1058
+	params.sector_size = int13_blksize ( int13 );
927 1059
 	memset ( &params.dpte, 0xff, sizeof ( params.dpte ) );
928 1060
 	if ( ( rc = int13_device_path_info ( int13, &params.dpi ) ) != 0 ) {
929 1061
 		DBGC ( int13, "INT13 drive %02x could not provide device "
@@ -958,6 +1090,41 @@ static int int13_get_extended_parameters ( struct int13_drive *int13,
958 1090
 	return 0;
959 1091
 }
960 1092
 
1093
+/**
1094
+ * INT 13, 4d - Read CD-ROM boot catalog
1095
+ *
1096
+ * @v int13		Emulated drive
1097
+ * @v ds:si		Command packet
1098
+ * @ret status		Status code
1099
+ */
1100
+static int int13_cdrom_read_boot_catalog ( struct int13_drive *int13,
1101
+					   struct i386_all_regs *ix86 ) {
1102
+	struct int13_cdrom_boot_catalog_command command;
1103
+	int rc;
1104
+
1105
+	/* Fail if we have no boot catalog */
1106
+	if ( ! int13->boot_catalog ) {
1107
+		DBGC ( int13, "INT13 drive %02x has no boot catalog\n",
1108
+		       int13->drive );
1109
+		return -INT13_STATUS_INVALID;
1110
+	}
1111
+
1112
+	/* Read parameters from command packet */
1113
+	copy_from_real ( &command, ix86->segs.ds, ix86->regs.si,
1114
+			 sizeof ( command ) );
1115
+
1116
+	/* Read from boot catalog */
1117
+	if ( ( rc = int13_rw ( int13, ( int13->boot_catalog + command.start ),
1118
+			       command.count, phys_to_user ( command.buffer ),
1119
+			       block_read ) ) != 0 ) {
1120
+		DBGC ( int13, "INT13 drive %02x could not read boot catalog: "
1121
+		       "%s\n", int13->drive, strerror ( rc ) );
1122
+		return -INT13_STATUS_READ_ERROR;
1123
+	}
1124
+
1125
+	return 0;
1126
+}
1127
+
961 1128
 /**
962 1129
  * INT 13 handler
963 1130
  *
@@ -1025,6 +1192,9 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
1025 1192
 		case INT13_GET_EXTENDED_PARAMETERS:
1026 1193
 			status = int13_get_extended_parameters ( int13, ix86 );
1027 1194
 			break;
1195
+		case INT13_CDROM_READ_BOOT_CATALOG:
1196
+			status = int13_cdrom_read_boot_catalog ( int13, ix86 );
1197
+			break;
1028 1198
 		default:
1029 1199
 			DBGC2 ( int13, "*** Unrecognised INT13 ***\n" );
1030 1200
 			status = -INT13_STATUS_INVALID;
@@ -1174,6 +1344,7 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
1174 1344
 	struct int13_drive *int13;
1175 1345
 	uint8_t num_drives;
1176 1346
 	unsigned int natural_drive;
1347
+	void *scratch;
1177 1348
 	int rc;
1178 1349
 
1179 1350
 	/* Calculate natural drive number */
@@ -1206,10 +1377,19 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
1206 1377
 
1207 1378
 	/* Read device capacity */
1208 1379
 	if ( ( rc = int13_read_capacity ( int13 ) ) != 0 )
1209
-		return rc;
1380
+		goto err_read_capacity;
1381
+
1382
+	/* Allocate scratch area */
1383
+	scratch = malloc ( int13_blksize ( int13 ) );
1384
+	if ( ! scratch )
1385
+		goto err_alloc_scratch;
1386
+
1387
+	/* Parse parameters, if present */
1388
+	if ( ( rc = int13_parse_iso9660 ( int13, scratch ) ) != 0 )
1389
+		goto err_parse_iso9660;
1210 1390
 
1211 1391
 	/* Give drive a default geometry */
1212
-	if ( ( rc = int13_guess_geometry ( int13 ) ) != 0 )
1392
+	if ( ( rc = int13_guess_geometry ( int13, scratch ) ) != 0 )
1213 1393
 		goto err_guess_geometry;
1214 1394
 
1215 1395
 	DBGC ( int13, "INT13 drive %02x (naturally %02x) registered with C/H/S "
@@ -1228,9 +1408,14 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
1228 1408
 	/* Update BIOS drive count */
1229 1409
 	int13_set_num_drives();
1230 1410
 
1411
+	free ( scratch );
1231 1412
 	return 0;
1232 1413
 
1233 1414
  err_guess_geometry:
1415
+ err_parse_iso9660:
1416
+	free ( scratch );
1417
+ err_alloc_scratch:
1418
+ err_read_capacity:
1234 1419
  err_reopen_block:
1235 1420
 	intf_shutdown ( &int13->block, rc );
1236 1421
 	ref_put ( &int13->refcnt );
@@ -1297,53 +1482,172 @@ static void int13_unhook ( unsigned int drive ) {
1297 1482
 }
1298 1483
 
1299 1484
 /**
1300
- * Attempt to boot from an INT 13 drive
1485
+ * Load and verify master boot record from INT 13 drive
1301 1486
  *
1302 1487
  * @v drive		Drive number
1488
+ * @v address		Boot code address to fill in
1303 1489
  * @ret rc		Return status code
1304
- *
1305
- * This boots from the specified INT 13 drive by loading the Master
1306
- * Boot Record to 0000:7c00 and jumping to it.  INT 18 is hooked to
1307
- * capture an attempt by the MBR to boot the next device.  (This is
1308
- * the closest thing to a return path from an MBR).
1309
- *
1310
- * Note that this function can never return success, by definition.
1311 1490
  */
1312
-static int int13_boot ( unsigned int drive ) {
1313
-	struct memory_map memmap;
1314
-	int status, signature;
1315
-	int discard_c, discard_d;
1316
-	int rc;
1317
-
1318
-	DBG ( "INT13 drive %02x booting\n", drive );
1319
-
1320
-	/* Use INT 13 to read the boot sector */
1491
+static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
1492
+	uint8_t status;
1493
+	int discard_b, discard_c, discard_d;
1494
+	uint16_t magic;
1495
+
1496
+	/* Use INT 13, 02 to read the MBR */
1497
+	address->segment = 0;
1498
+	address->offset = 0x7c00;
1321 1499
 	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
1322
-					   "pushw $0\n\t"
1500
+					   "pushl %%ebx\n\t"
1501
+					   "popw %%bx\n\t"
1323 1502
 					   "popw %%es\n\t"
1324 1503
 					   "stc\n\t"
1325 1504
 					   "sti\n\t"
1326 1505
 					   "int $0x13\n\t"
1327 1506
 					   "sti\n\t" /* BIOS bugs */
1328 1507
 					   "jc 1f\n\t"
1329
-					   "xorl %%eax, %%eax\n\t"
1508
+					   "xorw %%ax, %%ax\n\t"
1330 1509
 					   "\n1:\n\t"
1331
-					   "movzwl %%es:0x7dfe, %%ebx\n\t"
1332 1510
 					   "popw %%es\n\t" )
1333
-			       : "=a" ( status ), "=b" ( signature ),
1511
+			       : "=a" ( status ), "=b" ( discard_b ),
1334 1512
 				 "=c" ( discard_c ), "=d" ( discard_d )
1335
-			       : "a" ( 0x0201 ), "b" ( 0x7c00 ),
1513
+			       : "a" ( 0x0201 ), "b" ( *address ),
1336 1514
 				 "c" ( 1 ), "d" ( drive ) );
1337
-	if ( status )
1515
+	if ( status ) {
1516
+		DBG ( "INT13 drive %02x could not read MBR (status %02x)\n",
1517
+		      drive, status );
1338 1518
 		return -EIO;
1519
+	}
1339 1520
 
1340
-	/* Check signature is correct */
1341
-	if ( signature != be16_to_cpu ( 0x55aa ) ) {
1342
-		DBG ( "INT13 drive %02x invalid disk signature %#04x (should "
1343
-		      "be 0x55aa)\n", drive, cpu_to_be16 ( signature ) );
1521
+	/* Check magic signature */
1522
+	get_real ( magic, address->segment,
1523
+		   ( address->offset +
1524
+		     offsetof ( struct master_boot_record, magic ) ) );
1525
+	if ( magic != INT13_MBR_MAGIC ) {
1526
+		DBG ( "INT13 drive %02x does not contain a valid MBR\n",
1527
+		      drive );
1344 1528
 		return -ENOEXEC;
1345 1529
 	}
1346 1530
 
1531
+	return 0;
1532
+}
1533
+
1534
+/** El Torito boot catalog command packet */
1535
+static struct int13_cdrom_boot_catalog_command __data16 ( eltorito_cmd ) = {
1536
+	.size = sizeof ( struct int13_cdrom_boot_catalog_command ),
1537
+	.count = 1,
1538
+	.buffer = 0x7c00,
1539
+	.start = 0,
1540
+};
1541
+#define eltorito_cmd __use_data16 ( eltorito_cmd )
1542
+
1543
+/** El Torito disk address packet */
1544
+static struct int13_disk_address __bss16 ( eltorito_address );
1545
+#define eltorito_address __use_data16 ( eltorito_address )
1546
+
1547
+/**
1548
+ * Load and verify El Torito boot record from INT 13 drive
1549
+ *
1550
+ * @v drive		Drive number
1551
+ * @v address		Boot code address to fill in
1552
+ * @ret rc		Return status code
1553
+ */
1554
+static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
1555
+	struct {
1556
+		struct eltorito_validation_entry valid;
1557
+		struct eltorito_boot_entry boot;
1558
+	} __attribute__ (( packed )) catalog;
1559
+	uint8_t status;
1560
+
1561
+	/* Use INT 13, 4d to read the boot catalog */
1562
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
1563
+					   "sti\n\t"
1564
+					   "int $0x13\n\t"
1565
+					   "sti\n\t" /* BIOS bugs */
1566
+					   "jc 1f\n\t"
1567
+					   "xorw %%ax, %%ax\n\t"
1568
+					   "\n1:\n\t" )
1569
+			       : "=a" ( status )
1570
+			       : "a" ( 0x4d00 ), "d" ( drive ),
1571
+				 "S" ( __from_data16 ( &eltorito_cmd ) ) );
1572
+	if ( status ) {
1573
+		DBG ( "INT13 drive %02x could not read El Torito boot catalog "
1574
+		      "(status %02x)\n", drive, status );
1575
+		return -EIO;
1576
+	}
1577
+	copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0,
1578
+			 sizeof ( catalog ) );
1579
+
1580
+	/* Sanity checks */
1581
+	if ( catalog.valid.platform_id != ELTORITO_PLATFORM_X86 ) {
1582
+		DBG ( "INT13 drive %02x El Torito specifies unknown platform "
1583
+		      "%02x\n", drive, catalog.valid.platform_id );
1584
+		return -ENOEXEC;
1585
+	}
1586
+	if ( catalog.boot.indicator != ELTORITO_BOOTABLE ) {
1587
+		DBG ( "INT13 drive %02x El Torito is not bootable\n", drive );
1588
+		return -ENOEXEC;
1589
+	}
1590
+	if ( catalog.boot.media_type != ELTORITO_NO_EMULATION ) {
1591
+		DBG ( "INT13 drive %02x El Torito requires emulation "
1592
+		       "type %02x\n", drive, catalog.boot.media_type );
1593
+		return -ENOTSUP;
1594
+	}
1595
+	DBG ( "INT13 drive %02x El Torito boot image at LBA %08x (count %d)\n",
1596
+	      drive, catalog.boot.start, catalog.boot.length );
1597
+	address->segment = ( catalog.boot.load_segment ?
1598
+			     catalog.boot.load_segment : 0x7c0 );
1599
+	address->offset = 0;
1600
+	DBG ( "INT13 drive %02x El Torito boot image loads at %04x:%04x\n",
1601
+	      drive, address->segment, address->offset );
1602
+
1603
+	/* Use INT 13, 42 to read the boot image */
1604
+	eltorito_address.bufsize =
1605
+		offsetof ( typeof ( eltorito_address ), buffer_phys );
1606
+	eltorito_address.count = catalog.boot.length;
1607
+	eltorito_address.buffer = *address;
1608
+	eltorito_address.lba = catalog.boot.start;
1609
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
1610
+					   "sti\n\t"
1611
+					   "int $0x13\n\t"
1612
+					   "sti\n\t" /* BIOS bugs */
1613
+					   "jc 1f\n\t"
1614
+					   "xorw %%ax, %%ax\n\t"
1615
+					   "\n1:\n\t" )
1616
+			       : "=a" ( status )
1617
+			       : "a" ( 0x4200 ), "d" ( drive ),
1618
+				 "S" ( __from_data16 ( &eltorito_address ) ) );
1619
+	if ( status ) {
1620
+		DBG ( "INT13 drive %02x could not read El Torito boot image "
1621
+		      "(status %02x)\n", drive, status );
1622
+		return -EIO;
1623
+	}
1624
+
1625
+	return 0;
1626
+}
1627
+
1628
+/**
1629
+ * Attempt to boot from an INT 13 drive
1630
+ *
1631
+ * @v drive		Drive number
1632
+ * @ret rc		Return status code
1633
+ *
1634
+ * This boots from the specified INT 13 drive by loading the Master
1635
+ * Boot Record to 0000:7c00 and jumping to it.  INT 18 is hooked to
1636
+ * capture an attempt by the MBR to boot the next device.  (This is
1637
+ * the closest thing to a return path from an MBR).
1638
+ *
1639
+ * Note that this function can never return success, by definition.
1640
+ */
1641
+static int int13_boot ( unsigned int drive ) {
1642
+	struct memory_map memmap;
1643
+	struct segoff address;
1644
+	int rc;
1645
+
1646
+	/* Look for a usable boot sector */
1647
+	if ( ( ( rc = int13_load_mbr ( drive, &address ) ) != 0 ) &&
1648
+	     ( ( rc = int13_load_eltorito ( drive, &address ) ) != 0 ) )
1649
+		return rc;
1650
+
1347 1651
 	/* Dump out memory map prior to boot, if memmap debugging is
1348 1652
 	 * enabled.  Not required for program flow, but we have so
1349 1653
 	 * many problems that turn out to be memory-map related that
@@ -1352,7 +1656,8 @@ static int int13_boot ( unsigned int drive ) {
1352 1656
 	get_memmap ( &memmap );
1353 1657
 
1354 1658
 	/* Jump to boot sector */
1355
-	if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) {
1659
+	if ( ( rc = call_bootsector ( address.segment, address.offset,
1660
+				      drive ) ) != 0 ) {
1356 1661
 		DBG ( "INT13 drive %02x boot returned: %s\n",
1357 1662
 		      drive, strerror ( rc ) );
1358 1663
 		return rc;

Loading…
Cancelar
Guardar