[vbox-dev] BIOS Floppy Int 13 AL = 0x17, AL = 0x18 operations

Dave Meagher stope19 at gmail.com
Wed Jan 11 00:46:23 GMT 2012


Implement BIOS Floppy Int 13 AL = 0x17, AL = 0x18 operations

The comments in the attached text file relate to changes made for the
Bochs emulator. I believe that as the BIOS code in VirtualBox appears
to
derive from this (or is at least very similar), the following change
is applicable there as well.

The patch is provided under the MIT license.

Reason for Patch

I have been looking at bochs 2.4.6 as an emulator platform for an old
OS called 'Pick R83' (version 3.1M from early 90's) - but
encountered difficulty getting it running on bochs emulator. The OS
would boot, and the request the media from which
it was to load its data files. I was using the 'Legacy BIOS', and
tried to load the OS data files from Floppy disk.

At this point the OS load 'hangs', as it appears to not accept the
users choice of meda as being 'valid'. I spent quite some time
playing with logs and settings, but nothing worked. Finally, I rebuilt
the legacy BIOS with debugging turned on. This
enabled me to see that the OS, on being told to load files from
diskette, was making INT 13 AL=17 and AL=18 calls.
It seemed to be doing this to configure the selected
media/media-devices. Looking at Ralf Brown's Interrupt List,
these interrupts are:

Int 13 AL = 17 - FLOPPY DISK - SET DISK TYPE FOR FORMAT (AT,PS)
Int 13/AH=18h - DISK - SET MEDIA TYPE FOR FORMAT (AT model 3x9,XT2,XT286,PS)

As the OS is not attempting a 'format' operation, I'm assuming these
calls are being used for media/device detection and to
configure the system for subsequent media read operations.

The problem seems to be that these calls are not supported by BIOS code.

The attached file details this, and provides code to implement these functions.

I hope this change can be considered for VirtualBox. The changes have
been implemented in the Bochs system since release 2.5

Regards,
Dave
-------------- next part --------------
Implement BIOS Floppy Int 13 AL = 0x17, AL = 0x18 operations
============================================================

The following comment relates to changes made for the Bochs emulator. I believe that as the BIOS code in VirtualBox appears to
derive from this (or is at least very similar), the following change is applicable there as well.

This patch is provided under the MIT license. 

I have been looking at bochs 2.4.6 as an emulator platform for an old OS called 'Pick R83' (version 3.1M from early 90's) - but
encountered difficulty getting it running on bochs emulator. The OS would boot, and the request the media from which
it was to load its data files. I was using the 'Legacy BIOS', and tried to load the OS data files from Floppy disk.

At this point the OS load 'hangs', as it appears to not accept the users choice of meda as being 'valid'. I spent quite some time
playing with logs and settings, but nothing worked. Finally, I rebuilt the legacy BIOS with debugging turned on. This
enabled me to see that the OS, on being told to load files from diskette, was making INT 13 AL=17 and AL=18 calls.
It seemed to be doing this to configure the selected media/media-devices. Looking at Ralf Brown's Interrupt List,
these interrupts are:

Int 13 AL = 17 - FLOPPY DISK - SET DISK TYPE FOR FORMAT (AT,PS)
Int 13/AH=18h - DISK - SET MEDIA TYPE FOR FORMAT (AT model 3x9,XT2,XT286,PS)

As the OS is not attempting a 'format' operation, I'm assuming these calls are being used for media/device detection and to
configure the system for subsequent media read operations.

The problem seems to be that these calls are not supported by the legacy ROM BIOS, as the code in 'rombios.c' looks like:

...
case 0x17: // set diskette type for format(old)
BX_DEBUG_INT13_FL("floppy f17\n");
   /* not used for 1.44M floppies */
   SET_AH(0x01); // not supported
   set_diskette_ret_status(1); /* not supported */
   SET_CF();
   return;

case 0x18: // set diskette type for format(new)
BX_DEBUG_INT13_FL("floppy f18\n");
   SET_AH(0x01); // do later
   set_diskette_ret_status(1);
   SET_CF();
   return;
...

That is, any call always fails!

In an effort to make an attempt to fix my own problem, here is the code I came up with to implement the diskette INT13 functions AL=17h and AL=18h.

File: bios/rombios.c

Within function int13_diskette_function(..)

Declare 2 new variables at top of function, before the big switch statement.

Bit8u spt;
Bit16u maxCyl;

Then replace the existing code in the switch statement for 

case 0x17: // set diskette type for format(old)
...
case 0x18: // set diskette type for format(new)
...

With new code:

............start...........................

    case 0x17: // set diskette type for format(old)
BX_DEBUG_INT13_FL("floppy f17\n");
        // NOTE: 1.44M diskette not supported by this function,
        //       should use Int13 al=0x18 instead.
        // Intr Reference: http://www.ctyme.com/intr
        //
        // ** media state byte **
        // Bitfields for diskette drive media state byte that we might
        // change in this function:
        // Bit(s)  Description (Table M0030)
        //  7-6  data rate
        //    00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
        //  5  double stepping required (e.g. 360kB in 1.2MB)
        //  4  media type established

        // Drive number (0 or 1) values allowed
        drive = GET_ELDL();

        // Drive type (AL)
        // 00 - NOT USED    
        // 01 - DISKETTE 320/360K IN 360K DRIVE    
        // 02 - DISKETTE 360K IN 1.2M DRIVE
        // 03 - DISKETTE 1.2M IN 1.2M DRIVE
        // 04 - DISKETTE 720K IN 720K DRIVE
        drive_type = GET_AL();

        if (drive > 1) {
            SET_AH(0x01); // invalid drive
            set_diskette_ret_status(1); // bad parameter
            SET_CF();
            return;
        }
    
        // see if drive exists
        if (floppy_drive_exists(drive) == 0) {
            SET_AH(0x80); // not responding/time out
            set_diskette_ret_status(0x80);
            SET_CF();
            return;
        }

        // Get current drive status into 'status'. Set 'base_address' to media status offset address
        base_address = (drive) ? 0x0091 : 0x0090;
        status = read_byte(0x0040, base_address);

        // Mask out (clear) bits 4-7 (4:media type established, 5:double stepping, 6-7:data rate),
        val8 = status & 0x0f;

        switch(drive_type) {
        case 1:
            // 320/360K media in 360K drive
            val8 |= 0x90; // 1001 0000 (media type established, data rate=250)
            break;
        case 2:
            // 360K media in 1.2M drive
            val8 |= 0x70; // 0111 0000 (media type established, double stepping, data rate=300)
            break;
        case 3:
            // 1.2M media in 1.2M drive
            val8 |= 0x10; // 0001 0000 (media type established, data rate=500)
            break;
        case 4:
            // 720K media in 720K drive
            if (((status >> 4) & 0x01) && ((status >> 1) & 0x01))
            {
                // Media type already determined, and multiple format capable, so assume a higher data rate.
                val8 |= 0x50; // 0101 0000 (media type established, data rate=300)
            }
            else
            {
                // Media type not yet determined, or not multiple format capable, assume a lower data rate.
                val8 |= 0x90; // 1001 0000 (media type established, data rate=250)
            }
            break;
        default:
            // bad parameter
            SET_AH(0x01); // invalid drive
            set_diskette_ret_status(1); // bad parameter
            SET_CF();
            return;
        }

        BX_DEBUG_INT13_FL("floppy f17 - media status set to: %02x\n", val8);

        // Update media status
        write_byte(0x0040, base_address, val8);

        // return success!
        SET_AH(0);
        set_diskette_ret_status(0);
        CLEAR_CF();
        return;

    case 0x18: // set diskette type for format(new)
BX_DEBUG_INT13_FL("floppy f18\n");
        // Set Media Type for Format verifies that the device supports a specific geometry.
        // Unlike Int13 al=0x17 entry point, this version supports higher capacity
        // drives like 1.44M and even 2.88M.
        
        // Drive number (0 or 1) values allowed
        drive = GET_ELDL();

        val8 = GET_CL();
        spt = val8 & 0x3f; // sectors per track
        maxCyl = ((val8 >> 6) << 8) + GET_CH();  // max cylinder number (max cylinders - 1)

        BX_DEBUG_INT13_FL("floppy f18 - drive: %d, max cylinder number: %d, sectors-per-tracks: %d\n", drive, maxCyl, spt);

        if (drive > 1) {
            SET_AH(0x01); // invalid drive
            set_diskette_ret_status(1); // bad parameter
            SET_CF();
            return;
        }

        // see if drive exists
        if (floppy_drive_exists(drive) == 0) {
            SET_AH(0x80); // not responding/time out
            set_diskette_ret_status(0x80);
            SET_CF();
            return;
        }

        // see if media in drive, and type is known
        if (floppy_media_known(drive) == 0) {
            if (floppy_media_sense(drive) == 0) {
                SET_AH(0x0C); // drive type unknown
                set_diskette_ret_status(0x0C);
                SET_CF(); 
                return;
            }
        }

        // get current drive type
        drive_type = inb_cmos(0x10);
        if (drive == 0)
            drive_type >>= 4;
        else
            drive_type &= 0x0f;

        // Get current drive status into 'status'. Set 'base_address' to media status offset address
        base_address = (drive) ? 0x0091 : 0x0090;
        status = read_byte(0x0040, base_address);

        // Mask out (clear) bits 4-7 (4:media type established, 5:double stepping, 6-7:data rate),
        val8 = status & 0x0f;

        SET_AH(0x0C); // Assume error - unsupported combination of drive-type/max-cylinders/sectors-per-track
        switch (drive_type) {
        case 0: // none
            break;

        case 1: // 360KB, 5.25"
        case 6: // 160k, 5.25" 
        case 7: // 180k, 5.25"
        case 8: // 320k, 5.25"
            if (maxCyl == 39 && (spt == 8 || spt == 9))
            {
                val8 |= 0x90; // 1001 0000 (media type established, data rate=250)
                SET_AH(0);
            }
            break;

        case 2: // 1.2MB, 5.25"
            if (maxCyl == 39 && (spt == 8 || spt == 9))
            {
                // 320K/360K disk in 1.2M drive
                val8 |= 0x70; // 0111 0000 (media type established, double stepping, data rate=300)
                SET_AH(0);
            }
            else if (maxCyl == 79 && spt == 15)
            {
                // 1.2M disk in 1.2M drive
                val8 |= 0x10; // 0001 0000 (media type established, data rate=500)
                SET_AH(0);
            }
            break;

        case 3: // 720KB, 3.5"
            if (maxCyl == 79 && spt == 9)
            {
                val8 |= 0x90; // 1001 0000 (media type established, data rate=250)
                SET_AH(0);
            }
            break;

        case 4: // 1.44MB, 3.5"
            if (maxCyl == 79)
            {
                if (spt == 9)
                {
                    // 720K disk in 1.44M drive
                    val8 |= 0x90; // 1001 0000 (media type established, data rate=250)
                    SET_AH(0);
                }
                else if (spt == 18)
                {
                    // 1.44M disk in 1.44M drive
                    val8 |= 0x10; // 0001 0000 (media type established, data rate=500)
                    SET_AH(0);
                }
            } 
            break;

        case 5: // 2.88MB, 3.5"
            if (maxCyl == 79)
            {
                if (spt == 9)
                {
                    // 720K disk in 2.88M drive
                    val8 |= 0x90; // 1001 0000 (media type established, data rate=250)
                    SET_AH(0);
                }
                else if (spt == 18)
                {
                    // 1.44M disk in 2.88M drive
                    val8 |= 0x10; // 0001 0000 (media type established, data rate=500)
                    SET_AH(0);
                }
                else if (spt == 36)
                {
                    // 2.88M disk in 2.88M drive
                    val8 |= 0xD0; // 1101 0000 (media type established, data rate=1mb/s)
                    SET_AH(0);
                }
            }
            break;

        default:
            break;
        }

        if (0 != GET_AH())
        {
            // Error - assume requested max-cylinder/sectors-per-track not supported
            // for current drive type - or drive type is unknown!
            set_diskette_ret_status(GET_AH());
            SET_CF(); 
            return;
        }

        BX_DEBUG_INT13_FL("floppy f18 - media status set to: %02x\n", val8);

        // Update media status
        write_byte(0x0040, base_address, val8);

        // set es & di to point to 11 byte diskette param table in ROM 
        // Note that we do not update the table, as I don't see it being used anywhere...
ASM_START
        push bp
        mov  bp, sp
        mov ax, #diskette_param_table2
        mov _int13_diskette_function.DI+2[bp], ax
        mov _int13_diskette_function.ES+2[bp], cs
        pop  bp
ASM_END

        // return success!
        set_diskette_ret_status(0);
        CLEAR_CF();
        return;

............end.............................


More information about the vbox-dev mailing list