Browse Source

[int13] Pairwise swap drive numbers, instead of shifting all drive numbers

Shifting all INT13 drive numbers causes problems on systems that use a
sparse drive number space (e.g. qemu BIOS, which uses 0xe0 for the CD-ROM
drive).

The strategy now is:

  Each drive is assigned a "natural" drive number, being the next
  available drive number in the system (based on the BIOS drive count).

  Each drive is accessed using its specified drive number.  If the
  specified drive number is -1, the natural drive number will be used.

  Accesses to the specified drive number will be delivered to the
  emulated drive, masking out any preexisting drive using this number.

  Accesses to the natural drive number, if different, will be remapped to
  the masked-out drive.

The overall upshot is that, for examples:

  System has no drives.  Emulated INT13 drive gets natural number 0x80
  and specified number 0x80.  Accesses to drive 0x80 go to the emulated
  drive, and there is no remapping.

  System has one drive.  Emulated INT13 drive gets natural number 0x81
  and specified number 0x80.  Accesses to drive 0x80 go to the emulated
  drive.  Accesses to drive 0x81 get remapped to the original drive 0x80.
tags/v0.9.4
Michael Brown 16 years ago
parent
commit
bb41ec385c
2 changed files with 41 additions and 22 deletions
  1. 13
    1
      src/arch/i386/include/int13.h
  2. 28
    21
      src/arch/i386/interface/pcbios/int13.c

+ 13
- 1
src/arch/i386/include/int13.h View File

69
 	/** Underlying block device */
69
 	/** Underlying block device */
70
 	struct block_device *blockdev;
70
 	struct block_device *blockdev;
71
 
71
 
72
-	/** BIOS drive number (0x80-0xff) */
72
+	/** BIOS in-use drive number (0x80-0xff) */
73
 	unsigned int drive;
73
 	unsigned int drive;
74
+	/** BIOS natural drive number (0x80-0xff)
75
+	 *
76
+	 * This is the drive number that would have been assigned by
77
+	 * 'naturally' appending the drive to the end of the BIOS
78
+	 * drive list.
79
+	 *
80
+	 * If the emulated drive replaces a preexisting drive, this is
81
+	 * the drive number that the preexisting drive gets remapped
82
+	 * to.
83
+	 */
84
+	unsigned int natural_drive;
85
+
74
 	/** Number of cylinders
86
 	/** Number of cylinders
75
 	 *
87
 	 *
76
 	 * The cylinder number field in an INT 13 call is ten bits
88
 	 * The cylinder number field in an INT 13 call is ten bits

+ 28
- 21
src/arch/i386/interface/pcbios/int13.c View File

325
 static __cdecl void int13 ( struct i386_all_regs *ix86 ) {
325
 static __cdecl void int13 ( struct i386_all_regs *ix86 ) {
326
 	int command = ix86->regs.ah;
326
 	int command = ix86->regs.ah;
327
 	unsigned int bios_drive = ix86->regs.dl;
327
 	unsigned int bios_drive = ix86->regs.dl;
328
-	unsigned int original_bios_drive = bios_drive;
329
 	struct int13_drive *drive;
328
 	struct int13_drive *drive;
330
 	int status;
329
 	int status;
331
 
330
 
332
 	list_for_each_entry ( drive, &drives, list ) {
331
 	list_for_each_entry ( drive, &drives, list ) {
333
-		if ( drive->drive > bios_drive )
334
-			continue;
335
-		if ( drive->drive < bios_drive ) {
336
-			original_bios_drive--;
332
+
333
+		if ( bios_drive != drive->drive ) {
334
+			/* Remap any accesses to this drive's natural number */
335
+			if ( bios_drive == drive->natural_drive ) {
336
+				DBG ( "INT 13,%04x (%02x) remapped to "
337
+				      "(%02x)\n", ix86->regs.ax,
338
+				      bios_drive, drive->drive );
339
+				ix86->regs.dl = drive->drive;
340
+				return;
341
+			}
337
 			continue;
342
 			continue;
338
 		}
343
 		}
339
 		
344
 		
393
 
398
 
394
 		return;
399
 		return;
395
 	}
400
 	}
396
-
397
-	/* Remap BIOS drive */
398
-	if ( bios_drive != original_bios_drive ) {
399
-		DBG ( "INT 13,%04x (%02x) remapped to (%02x)\n",
400
-		      ix86->regs.ax, bios_drive, original_bios_drive );
401
-	}
402
-	ix86->regs.dl = original_bios_drive;
403
 }
401
 }
404
 
402
 
405
 /**
403
 /**
542
 	/* Give drive a default geometry if none specified */
540
 	/* Give drive a default geometry if none specified */
543
 	guess_int13_geometry ( drive );
541
 	guess_int13_geometry ( drive );
544
 
542
 
545
-	/* Assign drive number if none specified, update BIOS drive count */
543
+	/* Assign natural drive number */
546
 	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
544
 	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
547
-	if ( ( drive->drive & 0xff ) == 0xff )
548
-		drive->drive = num_drives;
549
-	drive->drive |= 0x80;
545
+	drive->natural_drive = ( num_drives | 0x80 );
550
 	num_drives++;
546
 	num_drives++;
551
-	if ( num_drives <= ( drive->drive & 0x7f ) )
552
-		num_drives = ( ( drive->drive & 0x7f ) + 1 );
547
+
548
+	/* Assign drive number */
549
+	if ( ( drive->drive & 0xff ) == 0xff ) {
550
+		/* Drive number == -1 => use natural drive number */
551
+		drive->drive = drive->natural_drive;
552
+	} else {
553
+		/* Use specified drive number (+0x80 if necessary) */
554
+		drive->drive |= 0x80;
555
+		if ( num_drives <= ( drive->drive & 0x7f ) )
556
+			num_drives = ( ( drive->drive & 0x7f ) + 1 );
557
+	}
558
+
559
+	/* Update BIOS drive count */
553
 	put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
560
 	put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
554
 
561
 
555
-	DBG ( "Registered INT13 drive %02x with C/H/S geometry %d/%d/%d\n",
556
-	      drive->drive, drive->cylinders, drive->heads,
557
-	      drive->sectors_per_track );
562
+	DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S "
563
+	      "geometry %d/%d/%d\n", drive->drive, drive->natural_drive,
564
+	      drive->cylinders, drive->heads, drive->sectors_per_track );
558
 
565
 
559
 	/* Hook INT 13 vector if not already hooked */
566
 	/* Hook INT 13 vector if not already hooked */
560
 	if ( list_empty ( &drives ) )
567
 	if ( list_empty ( &drives ) )

Loading…
Cancel
Save