Просмотр исходного кода

[int13] Add support for emulating floppy disk drives

Tested-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 лет назад
Родитель
Сommit
4dbb193c33
3 измененных файлов: 297 добавлений и 56 удалений
  1. 1
    0
      src/arch/i386/include/bios.h
  2. 52
    0
      src/arch/i386/include/int13.h
  3. 244
    56
      src/arch/i386/interface/pcbios/int13.c

+ 1
- 0
src/arch/i386/include/bios.h Просмотреть файл

@@ -4,6 +4,7 @@
4 4
 FILE_LICENCE ( GPL2_OR_LATER );
5 5
 
6 6
 #define BDA_SEG 0x0040
7
+#define BDA_EQUIPMENT_WORD 0x0010
7 8
 #define BDA_FBMS 0x0013
8 9
 #define BDA_NUM_DRIVES 0x0075
9 10
 

+ 52
- 0
src/arch/i386/include/int13.h Просмотреть файл

@@ -71,6 +71,19 @@ FILE_LICENCE ( GPL2_OR_LATER );
71 71
 /** Block size for non-extended INT 13 calls */
72 72
 #define INT13_BLKSIZE 512
73 73
 
74
+/** @defgroup int13fddtype INT 13 floppy disk drive types
75
+ * @{
76
+ */
77
+
78
+/** 360K */
79
+#define INT13_FDD_TYPE_360K		0x01
80
+/** 1.2M */
81
+#define INT13_FDD_TYPE_1M2		0x02
82
+/** 720K */
83
+#define INT13_FDD_TYPE_720K		0x03
84
+/** 1.44M */
85
+#define INT13_FDD_TYPE_1M44		0x04
86
+
74 87
 /** An INT 13 disk address packet */
75 88
 struct int13_disk_address {
76 89
 	/** Size of the packet, in bytes */
@@ -394,4 +407,43 @@ enum eltorito_media_type {
394 407
 	ELTORITO_NO_EMULATION = 0,
395 408
 };
396 409
 
410
+/** A floppy disk geometry */
411
+struct int13_fdd_geometry {
412
+	/** Number of tracks */
413
+	uint8_t tracks;
414
+	/** Number of heads and sectors per track */
415
+	uint8_t heads_spt;
416
+};
417
+
418
+/** Define a floppy disk geometry */
419
+#define INT13_FDD_GEOMETRY( cylinders, heads, sectors )			\
420
+	{								\
421
+		.tracks = (cylinders),					\
422
+		.heads_spt = ( ( (heads) << 6 ) | (sectors) ),		\
423
+	}
424
+
425
+/** Get floppy disk number of cylinders */
426
+#define INT13_FDD_CYLINDERS( geometry ) ( (geometry)->tracks )
427
+
428
+/** Get floppy disk number of heads */
429
+#define INT13_FDD_HEADS( geometry ) ( (geometry)->heads_spt >> 6 )
430
+
431
+/** Get floppy disk number of sectors per track */
432
+#define INT13_FDD_SECTORS( geometry ) ( (geometry)->heads_spt & 0x3f )
433
+
434
+/** A floppy drive parameter table */
435
+struct int13_fdd_parameters {
436
+	uint8_t step_rate__head_unload;
437
+	uint8_t head_load__ndma;
438
+	uint8_t motor_off_delay;
439
+	uint8_t bytes_per_sector;
440
+	uint8_t sectors_per_track;
441
+	uint8_t gap_length;
442
+	uint8_t data_length;
443
+	uint8_t format_gap_length;
444
+	uint8_t format_filler;
445
+	uint8_t head_settle_time;
446
+	uint8_t motor_start_time;
447
+} __attribute__ (( packed ));
448
+
397 449
 #endif /* INT13_H */

+ 244
- 56
src/arch/i386/interface/pcbios/int13.c Просмотреть файл

@@ -75,9 +75,9 @@ struct int13_drive {
75 75
 	/** Underlying block device interface */
76 76
 	struct interface block;
77 77
 
78
-	/** BIOS in-use drive number (0x80-0xff) */
78
+	/** BIOS in-use drive number (0x00-0xff) */
79 79
 	unsigned int drive;
80
-	/** BIOS natural drive number (0x80-0xff)
80
+	/** BIOS natural drive number (0x00-0xff)
81 81
 	 *
82 82
 	 * This is the drive number that would have been assigned by
83 83
 	 * 'naturally' appending the drive to the end of the BIOS
@@ -142,17 +142,44 @@ static struct segoff __text16 ( int13_vector );
142 142
 /** Assembly wrapper */
143 143
 extern void int13_wrapper ( void );
144 144
 
145
+/** Dummy floppy disk parameter table */
146
+static struct int13_fdd_parameters __data16 ( int13_fdd_params ) = {
147
+	/* 512 bytes per sector */
148
+	.bytes_per_sector = 0x02,
149
+	/* Highest sectors per track that we ever return */
150
+	.sectors_per_track = 48,
151
+};
152
+#define int13_fdd_params __use_data16 ( int13_fdd_params )
153
+
145 154
 /** List of registered emulated drives */
146 155
 static LIST_HEAD ( int13s );
147 156
 
148 157
 /**
149
- * Number of BIOS drives
158
+ * Equipment word
159
+ *
160
+ * This is a cached copy of the BIOS Data Area equipment word at
161
+ * 40:10.
162
+ */
163
+static uint16_t equipment_word;
164
+
165
+/**
166
+ * Number of BIOS floppy disk drives
150 167
  *
151
- * Note that this is the number of drives in the system as a whole
152
- * (i.e. a mirror of the counter at 40:75), rather than a count of the
153
- * number of emulated drives.
168
+ * This is derived from the equipment word.  It is held in .text16 to
169
+ * allow for easy access by the INT 13,08 wrapper.
154 170
  */
155
-static uint8_t num_drives;
171
+static uint8_t __text16 ( num_fdds );
172
+#define num_fdds __use_text16 ( num_fdds )
173
+
174
+/**
175
+ * Number of BIOS hard disk drives
176
+ *
177
+ * This is a cached copy of the BIOS Data Area number of hard disk
178
+ * drives at 40:75.  It is held in .text16 to allow for easy access by
179
+ * the INT 13,08 wrapper.
180
+ */
181
+static uint8_t __text16 ( num_drives );
182
+#define num_drives __use_text16 ( num_drives )
156 183
 
157 184
 /**
158 185
  * Calculate INT 13 drive sector size
@@ -185,6 +212,16 @@ static inline uint32_t int13_capacity32 ( struct int13_drive *int13 ) {
185 212
 	return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff );
186 213
 }
187 214
 
215
+/**
216
+ * Test if INT 13 drive is a floppy disk drive
217
+ *
218
+ * @v int13		Emulated drive
219
+ * @ret is_fdd		Emulated drive is a floppy disk
220
+ */
221
+static inline int int13_is_fdd ( struct int13_drive *int13 ) {
222
+	return ( ! ( int13->drive & 0x80 ) );
223
+}
224
+
188 225
 /** An INT 13 command */
189 226
 struct int13_command {
190 227
 	/** Status */
@@ -499,33 +536,33 @@ static int int13_parse_iso9660 ( struct int13_drive *int13, void *scratch ) {
499 536
 }
500 537
 
501 538
 /**
502
- * Guess INT 13 drive geometry
539
+ * Guess INT 13 hard disk drive geometry
503 540
  *
504 541
  * @v int13		Emulated drive
505 542
  * @v scratch		Scratch area for single-sector reads
543
+ * @ret heads		Guessed number of heads
544
+ * @ret sectors		Guessed number of sectors per track
506 545
  * @ret rc		Return status code
507 546
  *
508 547
  * Guesses the drive geometry by inspecting the partition table.
509 548
  */
510
-static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
549
+static int int13_guess_geometry_hdd ( struct int13_drive *int13, void *scratch,
550
+				      unsigned int *heads,
551
+				      unsigned int *sectors ) {
511 552
 	struct master_boot_record *mbr = scratch;
512 553
 	struct partition_table_entry *partition;
513
-	unsigned int guessed_heads = 255;
514
-	unsigned int guessed_sectors_per_track = 63;
515
-	unsigned int blocks;
516
-	unsigned int blocks_per_cyl;
517 554
 	unsigned int i;
518 555
 	int rc;
519 556
 
520
-	/* Don't even try when the blksize is invalid for C/H/S access */
521
-	if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
522
-		return 0;
557
+	/* Default guess is xx/255/63 */
558
+	*heads = 255;
559
+	*sectors = 63;
523 560
 
524 561
 	/* Read partition table */
525 562
 	if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( mbr ),
526 563
 			       block_read ) ) != 0 ) {
527
-		DBGC ( int13, "INT13 drive %02x could not read partition "
528
-		       "table to guess geometry: %s\n",
564
+		DBGC ( int13, "INT13 drive %02x could not read "
565
+		       "partition table to guess geometry: %s\n",
529 566
 		       int13->drive, strerror ( rc ) );
530 567
 		return rc;
531 568
 	}
@@ -534,25 +571,126 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
534 571
 	DBGC ( int13, "INT13 drive %02x has signature %08x\n",
535 572
 	       int13->drive, mbr->signature );
536 573
 
537
-	/* Scan through partition table and modify guesses for heads
538
-	 * and sectors_per_track if we find any used partitions.
574
+	/* Scan through partition table and modify guesses for
575
+	 * heads and sectors_per_track if we find any used
576
+	 * partitions.
539 577
 	 */
540 578
 	for ( i = 0 ; i < 4 ; i++ ) {
541 579
 		partition = &mbr->partitions[i];
542 580
 		if ( ! partition->type )
543 581
 			continue;
544
-		guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 );
545
-		guessed_sectors_per_track = PART_SECTOR ( partition->chs_end );
582
+		*heads = ( PART_HEAD ( partition->chs_end ) + 1 );
583
+		*sectors = PART_SECTOR ( partition->chs_end );
546 584
 		DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
547
-		       "on partition %d\n", int13->drive, guessed_heads,
548
-		       guessed_sectors_per_track, ( i + 1 ) );
585
+		       "on partition %d\n",
586
+		       int13->drive, *heads, *sectors, ( i + 1 ) );
587
+	}
588
+
589
+	return 0;
590
+}
591
+
592
+/** Recognised floppy disk geometries */
593
+static const struct int13_fdd_geometry int13_fdd_geometries[] = {
594
+	INT13_FDD_GEOMETRY ( 40, 1, 8 ),
595
+	INT13_FDD_GEOMETRY ( 40, 1, 9 ),
596
+	INT13_FDD_GEOMETRY ( 40, 2, 8 ),
597
+	INT13_FDD_GEOMETRY ( 40, 1, 9 ),
598
+	INT13_FDD_GEOMETRY ( 80, 2, 8 ),
599
+	INT13_FDD_GEOMETRY ( 80, 2, 9 ),
600
+	INT13_FDD_GEOMETRY ( 80, 2, 15 ),
601
+	INT13_FDD_GEOMETRY ( 80, 2, 18 ),
602
+	INT13_FDD_GEOMETRY ( 80, 2, 20 ),
603
+	INT13_FDD_GEOMETRY ( 80, 2, 21 ),
604
+	INT13_FDD_GEOMETRY ( 82, 2, 21 ),
605
+	INT13_FDD_GEOMETRY ( 83, 2, 21 ),
606
+	INT13_FDD_GEOMETRY ( 80, 2, 22 ),
607
+	INT13_FDD_GEOMETRY ( 80, 2, 23 ),
608
+	INT13_FDD_GEOMETRY ( 80, 2, 24 ),
609
+	INT13_FDD_GEOMETRY ( 80, 2, 36 ),
610
+	INT13_FDD_GEOMETRY ( 80, 2, 39 ),
611
+	INT13_FDD_GEOMETRY ( 80, 2, 40 ),
612
+	INT13_FDD_GEOMETRY ( 80, 2, 44 ),
613
+	INT13_FDD_GEOMETRY ( 80, 2, 48 ),
614
+};
615
+
616
+/**
617
+ * Guess INT 13 floppy disk drive geometry
618
+ *
619
+ * @v int13		Emulated drive
620
+ * @ret heads		Guessed number of heads
621
+ * @ret sectors		Guessed number of sectors per track
622
+ * @ret rc		Return status code
623
+ *
624
+ * Guesses the drive geometry by inspecting the disk size.
625
+ */
626
+static int int13_guess_geometry_fdd ( struct int13_drive *int13,
627
+				      unsigned int *heads,
628
+				      unsigned int *sectors ) {
629
+	unsigned int blocks = int13_blksize ( int13 );
630
+	const struct int13_fdd_geometry *geometry;
631
+	unsigned int cylinders;
632
+	unsigned int i;
633
+
634
+	/* Look for a match against a known geometry */
635
+	for ( i = 0 ; i < ( sizeof ( int13_fdd_geometries ) /
636
+			    sizeof ( int13_fdd_geometries[0] ) ) ; i++ ) {
637
+		geometry = &int13_fdd_geometries[i];
638
+		cylinders = INT13_FDD_CYLINDERS ( geometry );
639
+		*heads = INT13_FDD_HEADS ( geometry );
640
+		*sectors = INT13_FDD_SECTORS ( geometry );
641
+		if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) {
642
+			DBGC ( int13, "INT13 drive %02x guessing C/H/S "
643
+			       "%d/%d/%d based on size %dK\n", int13->drive,
644
+			       cylinders, *heads, *sectors, ( blocks / 2 ) );
645
+			return 0;
646
+		}
647
+	}
648
+
649
+	/* Otherwise, assume a partial disk image in the most common
650
+	 * format (1440K, 80/2/18).
651
+	 */
652
+	*heads = 2;
653
+	*sectors = 18;
654
+	DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
655
+	       "%dK\n", int13->drive, *heads, *sectors, ( blocks / 2 ) );
656
+	return 0;
657
+}
658
+
659
+/**
660
+ * Guess INT 13 drive geometry
661
+ *
662
+ * @v int13		Emulated drive
663
+ * @v scratch		Scratch area for single-sector reads
664
+ * @ret rc		Return status code
665
+ */
666
+static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
667
+	unsigned int guessed_heads;
668
+	unsigned int guessed_sectors;
669
+	unsigned int blocks;
670
+	unsigned int blocks_per_cyl;
671
+	int rc;
672
+
673
+	/* Don't even try when the blksize is invalid for C/H/S access */
674
+	if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
675
+		return 0;
676
+
677
+	/* Guess geometry according to drive type */
678
+	if ( int13_is_fdd ( int13 ) ) {
679
+		if ( ( rc = int13_guess_geometry_fdd ( int13, &guessed_heads,
680
+						       &guessed_sectors )) != 0)
681
+			return rc;
682
+	} else {
683
+		if ( ( rc = int13_guess_geometry_hdd ( int13, scratch,
684
+						       &guessed_heads,
685
+						       &guessed_sectors )) != 0)
686
+			return rc;
549 687
 	}
550 688
 
551 689
 	/* Apply guesses if no geometry already specified */
552 690
 	if ( ! int13->heads )
553 691
 		int13->heads = guessed_heads;
554 692
 	if ( ! int13->sectors_per_track )
555
-		int13->sectors_per_track = guessed_sectors_per_track;
693
+		int13->sectors_per_track = guessed_sectors;
556 694
 	if ( ! int13->cylinders ) {
557 695
 		/* Avoid attempting a 64-bit divide on a 32-bit system */
558 696
 		blocks = int13_capacity32 ( int13 );
@@ -569,19 +707,40 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
569 707
 /**
570 708
  * Update BIOS drive count
571 709
  */
572
-static void int13_set_num_drives ( void ) {
710
+static void int13_sync_num_drives ( void ) {
573 711
 	struct int13_drive *int13;
712
+	uint8_t *counter;
713
+	uint8_t max_drive;
714
+	uint8_t required;
574 715
 
575
-	/* Get current drive count */
716
+	/* Get current drive counts */
717
+	get_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
576 718
 	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
719
+	num_fdds = ( ( equipment_word & 0x0001 ) ?
720
+		     ( ( ( equipment_word >> 6 ) & 0x3 ) + 1 ) : 0 );
577 721
 
578 722
 	/* Ensure count is large enough to cover all of our emulated drives */
579 723
 	list_for_each_entry ( int13, &int13s, list ) {
580
-		if ( num_drives <= ( int13->drive & 0x7f ) )
581
-			num_drives = ( ( int13->drive & 0x7f ) + 1 );
724
+		counter = ( int13_is_fdd ( int13 ) ? &num_fdds : &num_drives );
725
+		max_drive = int13->drive;
726
+		if ( max_drive < int13->natural_drive )
727
+			max_drive = int13->natural_drive;
728
+		required = ( ( max_drive & 0x7f ) + 1 );
729
+		if ( *counter < required ) {
730
+			*counter = required;
731
+			DBGC ( int13, "INT13 drive %02x added to drive count: "
732
+			       "%d HDDs, %d FDDs\n",
733
+			       int13->drive, num_drives, num_fdds );
734
+		}
582 735
 	}
583 736
 
584 737
 	/* Update current drive count */
738
+	equipment_word &= ~( ( 0x3 << 6 ) | 0x0001 );
739
+	if ( num_fdds ) {
740
+		equipment_word |= ( 0x0001 |
741
+				    ( ( ( num_fdds - 1 ) & 0x3 ) << 6 ) );
742
+	}
743
+	put_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
585 744
 	put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
586 745
 }
587 746
 
@@ -589,13 +748,14 @@ static void int13_set_num_drives ( void ) {
589 748
  * Check number of drives
590 749
  */
591 750
 static void int13_check_num_drives ( void ) {
751
+	uint16_t check_equipment_word;
592 752
 	uint8_t check_num_drives;
593 753
 
754
+	get_real ( check_equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
594 755
 	get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
595
-	if ( check_num_drives != num_drives ) {
596
-		int13_set_num_drives();
597
-		DBG ( "INT13 fixing up number of drives from %d to %d\n",
598
-		      check_num_drives, num_drives );
756
+	if ( ( check_equipment_word != equipment_word ) ||
757
+	     ( check_num_drives != num_drives ) ) {
758
+		int13_sync_num_drives();
599 759
 	}
600 760
 }
601 761
 
@@ -669,14 +829,19 @@ static int int13_rw_sectors ( struct int13_drive *int13,
669 829
 		       int13->drive, int13_blksize ( int13 ) );
670 830
 		return -INT13_STATUS_INVALID;
671 831
 	}
672
-	
832
+
673 833
 	/* Calculate parameters */
674 834
 	cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
675
-	assert ( cylinder < int13->cylinders );
676 835
 	head = ix86->regs.dh;
677
-	assert ( head < int13->heads );
678 836
 	sector = ( ix86->regs.cl & 0x3f );
679
-	assert ( ( sector >= 1 ) && ( sector <= int13->sectors_per_track ) );
837
+	if ( ( cylinder >= int13->cylinders ) ||
838
+	     ( head >= int13->heads ) ||
839
+	     ( sector < 1 ) || ( sector > int13->sectors_per_track ) ) {
840
+		DBGC ( int13, "C/H/S %d/%d/%d out of range for geometry "
841
+		       "%d/%d/%d\n", cylinder, head, sector, int13->cylinders,
842
+		       int13->heads, int13->sectors_per_track );
843
+		return -INT13_STATUS_INVALID;
844
+	}
680 845
 	lba = ( ( ( ( cylinder * int13->heads ) + head )
681 846
 		  * int13->sectors_per_track ) + sector - 1 );
682 847
 	count = ix86->regs.al;
@@ -761,10 +926,19 @@ static int int13_get_parameters ( struct int13_drive *int13,
761 926
 		return -INT13_STATUS_INVALID;
762 927
 	}
763 928
 
929
+	/* Common parameters */
764 930
 	ix86->regs.ch = ( max_cylinder & 0xff );
765 931
 	ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
766 932
 	ix86->regs.dh = max_head;
767
-	get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES );
933
+	ix86->regs.dl = ( int13_is_fdd ( int13 ) ? num_fdds : num_drives );
934
+
935
+	/* Floppy-specific parameters */
936
+	if ( int13_is_fdd ( int13 ) ) {
937
+		ix86->regs.bl = INT13_FDD_TYPE_1M44;
938
+		ix86->segs.es = rm_ds;
939
+		ix86->regs.di = __from_data16 ( &int13_fdd_params );
940
+	}
941
+
768 942
 	return 0;
769 943
 }
770 944
 
@@ -781,10 +955,15 @@ static int int13_get_disk_type ( struct int13_drive *int13,
781 955
 	uint32_t blocks;
782 956
 
783 957
 	DBGC2 ( int13, "Get disk type\n" );
784
-	blocks = int13_capacity32 ( int13 );
785
-	ix86->regs.cx = ( blocks >> 16 );
786
-	ix86->regs.dx = ( blocks & 0xffff );
787
-	return INT13_DISK_TYPE_HDD;
958
+
959
+	if ( int13_is_fdd ( int13 ) ) {
960
+		return INT13_DISK_TYPE_FDD;
961
+	} else {
962
+		blocks = int13_capacity32 ( int13 );
963
+		ix86->regs.cx = ( blocks >> 16 );
964
+		ix86->regs.dx = ( blocks & 0xffff );
965
+		return INT13_DISK_TYPE_HDD;
966
+	}
788 967
 }
789 968
 
790 969
 /**
@@ -833,6 +1012,13 @@ static int int13_extended_rw ( struct int13_drive *int13,
833 1012
 	userptr_t buffer;
834 1013
 	int rc;
835 1014
 
1015
+	/* Extended reads are not allowed on floppy drives.
1016
+	 * ELTORITO.SYS seems to assume that we are really a CD-ROM if
1017
+	 * we support extended reads for a floppy drive.
1018
+	 */
1019
+	if ( int13_is_fdd ( int13 ) )
1020
+		return -INT13_STATUS_INVALID;
1021
+
836 1022
 	/* Get buffer size */
837 1023
 	get_real ( bufsize, ix86->segs.ds,
838 1024
 		   ( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
@@ -1300,26 +1486,29 @@ static void int13_hook_vector ( void ) {
1300 1486
 			     "popw 6(%%bp)\n\t"
1301 1487
 			     /* Fix up %dl:
1302 1488
 			      *
1303
-			      * INT 13,15 : do nothing
1489
+			      * INT 13,15 : do nothing if hard disk
1304 1490
 			      * INT 13,08 : load with number of drives
1305 1491
 			      * all others: restore original value
1306 1492
 			      */
1307 1493
 			     "cmpb $0x15, -1(%%bp)\n\t"
1308
-			     "je 2f\n\t"
1494
+			     "jne 2f\n\t"
1495
+			     "testb $0x80, -4(%%bp)\n\t"
1496
+			     "jnz 3f\n\t"
1497
+			     "\n2:\n\t"
1309 1498
 			     "movb -4(%%bp), %%dl\n\t"
1310 1499
 			     "cmpb $0x08, -1(%%bp)\n\t"
1311
-			     "jne 2f\n\t"
1312
-			     "pushw %%ds\n\t"
1313
-			     "pushw %1\n\t"
1314
-			     "popw %%ds\n\t"
1315
-			     "movb %c2, %%dl\n\t"
1316
-			     "popw %%ds\n\t"
1500
+			     "jne 3f\n\t"
1501
+			     "testb $0x80, %%dl\n\t"
1502
+			     "movb %%cs:%c1, %%dl\n\t"
1503
+			     "jnz 3f\n\t"
1504
+			     "movb %%cs:%c2, %%dl\n\t"
1317 1505
 			     /* Return */
1318
-			     "\n2:\n\t"
1506
+			     "\n3:\n\t"
1319 1507
 			     "movw %%bp, %%sp\n\t"
1320 1508
 			     "popw %%bp\n\t"
1321 1509
 			     "iret\n\t" )
1322
-	       : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) );
1510
+	       : : "i" ( int13 ), "i" ( __from_text16 ( &num_drives ) ),
1511
+		   "i" ( __from_text16 ( &num_fdds ) ) );
1323 1512
 
1324 1513
 	hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
1325 1514
 			      &int13_vector );
@@ -1404,14 +1593,13 @@ static void int13_free ( struct refcnt *refcnt ) {
1404 1593
  */
1405 1594
 static int int13_hook ( struct uri *uri, unsigned int drive ) {
1406 1595
 	struct int13_drive *int13;
1407
-	uint8_t num_drives;
1408 1596
 	unsigned int natural_drive;
1409 1597
 	void *scratch;
1410 1598
 	int rc;
1411 1599
 
1412 1600
 	/* Calculate natural drive number */
1413
-	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
1414
-	natural_drive = ( num_drives | 0x80 );
1601
+	int13_sync_num_drives();
1602
+	natural_drive = ( ( drive & 0x80 ) ? ( num_drives | 0x80 ) : num_fdds );
1415 1603
 
1416 1604
 	/* Check that drive number is not in use */
1417 1605
 	list_for_each_entry ( int13, &int13s, list ) {
@@ -1468,7 +1656,7 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
1468 1656
 	list_add ( &int13->list, &int13s );
1469 1657
 
1470 1658
 	/* Update BIOS drive count */
1471
-	int13_set_num_drives();
1659
+	int13_sync_num_drives();
1472 1660
 
1473 1661
 	free ( scratch );
1474 1662
 	return 0;

Загрузка…
Отмена
Сохранить