Problem with floppy driver - IRQ6 not firing

If you are new to OS Development, plan on spending some time here first before going into the other forums.

Moderator:Moderators

chibicitiberiu
Posts:22
Joined:Sat Jul 17, 2010 7:55 am
Problem with floppy driver - IRQ6 not firing

Post by chibicitiberiu » Thu Aug 05, 2010 2:39 pm

Okay so I tried to make a floppy driver based on the two tutorials about floppy and dma, and on osdev wiki. I tried to support up to two drives, and all densities for 3.5" floppies. I would love to support up to 4 drives, and also 5" floppies, but not sure how to do it.

Anyway, below is my driver. The problem I have is that IRQ6 isn't firing. What could be the problem? I checked twice the code... and I also tried a timeout and apparently it did read properly... but timeout is ugly, since the minimum timeout should be around 3 seconds...

floppy.c

Code: Select all

/***** floppy.c ******************************************************
 * (c) 2010 CTA Systems Inc. All rights reserved. Glory To God       *
 *                                                                   *
 *         Floppy Drive I/O Routines                                 *
 *         =========================                                 *
 *                                                                   *
 ************************************************************ cta os */
#include "../irq/irq.h"
#include "../dma/dma.h"
#include <system.h>
#include <conio.h>

#define i86_floppy_wait() { while (!i86_floppy_new_interrupt); i86_floppy_new_interrupt = 0; }

// Used ports:
// ***********
// Digital Output Register (DOR):         0x3f2
// Main Status Register (MSR):            0x3f4
// Data Register (FIFO):                  0x3f5
// Configuration Control Register (CTRL): 0x3f7

unsigned char floppy_drives_installed;
volatile unsigned char i86_floppy_new_interrupt;
struct {
     unsigned char type;
     unsigned char data_rate;
     unsigned char step_rate_time;
     unsigned char head_load_time;
     unsigned char head_unload_time;
     unsigned char sectors_per_track;
} fd[2];


// Initialize DMA
unsigned char i86_floppy_initialize_dma(unsigned char* buffer, unsigned length)
{
    union { unsigned char byt[4]; // Low[0], Mid[1], Hi[2]
            unsigned long l;
    } a, c;

    a.l = (unsigned) buffer;
    c.l = (unsigned) length-1;

    // Check for buffer issues
    if ((a.l >> 24) || (c.l >> 16) || (((a.l & 0xffff)+c.l) >> 16)) return 0;

    i86_dma_reset();
    i86_dma_mask_channel(2);                    // Mask channel 2
    i86_dma_reset_flipflop(1);                  // FlipFlop reset on DMA1

    i86_dma_set_address(2, a.byt[0], a.byt[1]); // Buffer address
    i86_dma_reset_flipflop(1);                  // FlipFlop reset on DMA2

    i86_dma_set_count(2, c.byt[0], c.byt[1]);   // Set count
    i86_dma_set_read(2);
    i86_dma_unmask_all();

    return 1;
}




inline void i86_floppy_disable_controller() {
    outportb (0x3F2, 0);
}

inline void i86_floppy_enable_controller() {
    outportb (0x3F2, 4 | 8);
}


inline unsigned char i86_floppy_send_command (unsigned char command)
{
    int i;
    for (i = 0; i < 750; i++)
        if (inportb(0x3F4) & 128) {
            outportb(0x3F5, command); return 1;
        }
    return 0;
}


inline unsigned char i86_floppy_read_data ()
{
    int i;
    for (i = 0; i < 750; i++)
        if (inportb(0x3F4) & 0x80)
            return inportb(0x3F5);
    return 0;
}


/*inline unsigned char i86_floppy_wait()
{
    unsigned temp = 2000000000;
    
    for (;i86_floppy_new_interrupt==0; temp--)
           if (!temp) return 0;

    i86_floppy_new_interrupt = 0;
    return 1;
}*/


inline void i86_floppy_check_int(unsigned* st0, unsigned* cyl)
{
    i86_floppy_send_command(0x8);
    *st0 = i86_floppy_read_data();
    *cyl = i86_floppy_read_data();
}

extern unsigned i86_pit_get_tick_count();
extern unsigned i86_pit_get_frequency();

void i86_floppy_motor (unsigned char drive, unsigned char on)
{
    if (drive >= floppy_drives_installed) return;

    // Read DOR register
    unsigned char dor = inportb(0x3F2);

    // Un/set selected drive motor
    if (on) dor |= drive << 4;
    else dor &= ~(drive << 4);

    // Write DOR
    outportb (0x3F2, dor);

    // Wait a fifth of a second for motor to turn on
    unsigned temp = i86_pit_get_tick_count();
    unsigned freq = i86_pit_get_frequency();
    while (temp + (freq/5) > i86_pit_get_tick_count());
}


void i86_floppy_handler(ISR_stack_regs *r)
{
    i86_floppy_new_interrupt = 1;
    printf ("[FLOPPY] [INT]\n");
}


void i86_floppy_drive_data (unsigned char drv, unsigned char dma)
{
    unsigned data = 0;
    if (drv >= floppy_drives_installed) return;

    outportb(0x3F7, fd[drv].data_rate);

    i86_floppy_send_command (0x3);

    data = ((fd[drv].step_rate_time & 0xf) << 4) | (fd[drv].head_unload_time & 0xf);
    i86_floppy_send_command (data);

    data = (fd[drv].head_load_time <<1 ) | (dma) ? 1 : 0;
    i86_floppy_send_command (data);
}


inline void i86_floppy_select(unsigned char drive)
{
      if (drive >= floppy_drives_installed) return;
      
      // Send mechanical drive data
      i86_floppy_drive_data(drive, 1);

      // Select drive in DOR register
      outportb (0x3F2, 4 | 8 | drive);

}


unsigned char i86_floppy_calibrate(unsigned drive)
{
    unsigned st0, cyl;

    if (drive >= floppy_drives_installed) return 0;

    i86_floppy_motor (drive, 1);

    int i;
    for (i = 0; i < 15; i++) {
        i86_floppy_new_interrupt = 0;
        i86_floppy_send_command(0x7);
        i86_floppy_send_command(drive);
        i86_floppy_wait();
        i86_floppy_check_int(&st0, &cyl);

        if (!cyl) {
            i86_floppy_motor(drive, 0);
            return 1;
        }
    }
    i86_floppy_motor(drive, 0);
    return 0;
}


void i86_floppy_reset()
{
    unsigned st0, cyl;

    printf ("[Floppy] [Reset] Reset routine started...\n");

    i86_floppy_new_interrupt = 0;
    i86_floppy_disable_controller();
    i86_floppy_enable_controller();
    i86_floppy_wait();
    printf ("[Floppy] [Reset] Interrupt received. Continuing...\n");
    
    int i;
    for (i = 0; i < 4; i++)
        i86_floppy_check_int(&st0, &cyl);

    unsigned char drive;
    for (drive = 0; drive < floppy_drives_installed; drive++) {
      i86_floppy_drive_data(drive, 1);
      if (i86_floppy_calibrate(drive)) printf ("Drive %u calibrated.", drive);
      else printf ("Drive %u failed to calibrate.", drive);
    }

}


void i86_floppy_read_sector_imp (unsigned* where, unsigned char drive, unsigned char head, unsigned char track, unsigned char sector)
{
    unsigned st0, cyl;

    i86_floppy_select (drive);
    i86_floppy_initialize_dma((unsigned char*) where, 512);
    i86_dma_set_read(2);

    i86_floppy_new_interrupt = 0;

    i86_floppy_send_command(0x06 | 0x80 | 0x40 );
    i86_floppy_send_command(head<<2 | drive);
    i86_floppy_send_command(track);
    i86_floppy_send_command(head);
    i86_floppy_send_command(sector);
    i86_floppy_send_command(0x02);
    i86_floppy_send_command( ((sector+1) >= fd[drive].sectors_per_track) ? fd[drive].sectors_per_track : sector+1);
    i86_floppy_send_command(0x1b);
    i86_floppy_send_command(0xff);

    i86_floppy_wait();

    int i;
    for (i = 0; i < 7; i++) i86_floppy_read_data();

    i86_floppy_check_int (&st0, &cyl);
}


unsigned char i86_floppy_seek (unsigned drive, unsigned cyl, unsigned head)
{
    unsigned st0, cyl0;

    if (drive >= floppy_drives_installed) return 0;

    i86_floppy_select (drive);

    int i;
    for (i = 0; i < 20; i++) {
        i86_floppy_new_interrupt = 0;
        i86_floppy_send_command (0xF);
        i86_floppy_send_command ( (head) << 2 | drive);
        i86_floppy_send_command (cyl);

        i86_floppy_wait();
        i86_floppy_check_int(&st0, &cyl0);

        if (cyl0 == cyl) return 1;
    }
    return 0;
}


inline void i86_floppy_lba_to_chs (int lba, unsigned char drive, unsigned char *head, unsigned char *track, unsigned char *sectors)
{
    *head = (lba % (fd[drive].sectors_per_track * 2)) / fd[drive].sectors_per_track;
    *track = lba / (fd[drive].sectors_per_track * 2);
    *sectors = lba % fd[drive].sectors_per_track + 1;
}

extern unsigned char i86_cmos_read_floppy_drives();
const char* types[] = {
      "Nonexistant", "5.25\", unsupported.", "5.25\", unsupported.",
      "3.5\", 720kb", "3.5\", 1.44mb", "3.5\", 2.88 mb"};

void i86_floppy_install()
{
    unsigned char temp = i86_cmos_read_floppy_drives();
    int i;

    printf ("[Floppy] Init started...\n");

    // Set fd0 and fd1 types
    fd[1].type = temp & 0xf;
    fd[0].type = temp >> 4;
    
    printf ("[Floppy] Drives detected: (fd0) %s, (fd1) %s\n", types[fd[0].type], types[fd[1].type]);

    // SRT = 16 - (ms * datarate / 500000);
    // HLT = ms * datarate / 1000000
    // HUT = ms * datarate / 8000000

    // Set up
    for (i = 0; i < 2; i++) {
        if (fd[i].type >= 3) floppy_drives_installed++; // 5.25" drives unsupported
        if (fd[i].type == 3) {  // 720 kb, DD
                fd[i].data_rate = 2;      // speed = 250 kbps
                fd[i].step_rate_time = 12; // 16 - (ms * 250000 / 500000), ms = 8
                fd[i].head_load_time = 7;
                fd[i].head_unload_time = 7;
                fd[i].sectors_per_track = 9;
        }
        else if (fd[i].type == 4) { // 1.44 MB, HD
                fd[i].data_rate = 0;      // speed = 500 kbps
                fd[i].step_rate_time = 8;
                fd[i].head_load_time = 15;
                fd[i].head_unload_time = 15;
                fd[i].sectors_per_track = 18;
        }
        else if (fd[i].type == 5) { // 2.88 MB, ED
                fd[i].data_rate = 3;      // speed = 1000 kbps;
                fd[i].step_rate_time = 0;
                fd[i].head_load_time = 30;
                fd[i].head_unload_time = 30;
                fd[i].sectors_per_track = 36;
        }
    }
    if (floppy_drives_installed == 0) return;       // No drives to set

    printf ("[Floppy] Set up arrays:\n");
    printf ("     (fd0) data rate = %u\n", fd[0].data_rate);
    printf ("     (fd0) step rate time = %u\n", fd[0].step_rate_time);
    printf ("     (fd0) head load time = %u\n", fd[0].head_load_time);
    printf ("     (fd0) head_unload_time = %u\n", fd[0].head_unload_time);
    printf ("     (fd0) sectors_per_track = %u\n", fd[0].head_unload_time);
    printf ("[Floppy] Set up arrays:\n");
    printf ("     (fd1) data rate = %u\n", fd[1].data_rate);
    printf ("     (fd1) step rate time = %u\n", fd[1].step_rate_time);
    printf ("     (fd1) head load time = %u\n", fd[1].head_load_time);
    printf ("     (fd1) head_unload_time = %u\n", fd[1].head_unload_time);
    printf ("     (fd1) sectors_per_track = %u\n", fd[1].head_unload_time);
    
    // Install handler
    i86_irq_install_handler(6, i86_floppy_handler);
    printf ("[Floppy] Installed IRQ6.\n");
    i86_floppy_reset();
}


unsigned char i86_floppy_driver_enabled()
{
    return (floppy_drives_installed>0);
}


unsigned* i86_read_sector (unsigned* where, unsigned char drive, int sectorLBA)
{
    if (drive >= floppy_drives_installed) return 0;
    if ((unsigned)(where) > (0xFFFF - 513)) return 0;

    // convert lba to chs
    unsigned head, track, sector;
    i86_floppy_lba_to_chs(sectorLBA, drive, (unsigned char*)&head, (unsigned char*)&track, (unsigned char*) &sector);

    // start motor
    i86_floppy_motor(drive, 1);
    if (!i86_floppy_seek(drive, track, head)) return 0;

    i86_floppy_read_sector_imp(where, drive, head, track, sector);
    i86_floppy_motor(drive, 0);

    return (unsigned*)where;
}
dma.c

Code: Select all

/***** dma.c *********************************************************
 * (c) 2010 CTA Systems Inc. All rights reserved. Glory To God       *
 *                                                                   *
 *         Direct Memory Access (DMA) Routines                       *
 *         ===================================                       *
 *                                                                   *
 ************************************************************ cta os */

#include "dma.h"
#include <system.h>

enum DMA0_IO {
    DMA0_STATUS_REG = 0x08,
    DMA0_COMMAND_REG = 0x08,
    DMA0_REQUEST_REG = 0x09,
    DMA0_CHANMASK_REG = 0x0a,
    DMA0_MODE_REG = 0x0b,
    DMA0_CLEARBYTE_FLIPFLOP_REG = 0x0c,
    DMA0_TEMP_REG = 0x0d,
    DMA0_MASTER_CLEAR_REG = 0x0d,
    DMA0_CLEAR_MASK_REG = 0x0e,
    DMA0_MASK_REG = 0x0f
};

enum DMA1_IO {
    DMA1_STATUS_REG = 0xd0,
    DMA1_COMMAND_REG = 0xd0,
    DMA1_REQUEST_REG = 0xd2,
    DMA1_CHANMASK_REG = 0xd4,
    DMA1_MODE_REG = 0xd6,
    DMA1_CLEARBYTE_FLIPFLOP_REG = 0xd8,
    DMA1_INTER_REG = 0xda,
    DMA1_UNMASK_ALL_REG = 0xdc,
    DMA1_MASK_REG = 0xde
};

void i86_dma_set_address(unsigned short channel, unsigned char low, unsigned char high)
{
    if (channel > 7) return;   // Ignore if channel > 7

    // Calculate port
    unsigned short port = (channel >= 4) ? 4*(channel - 4) + 0xc0 : 2*channel;

    // Set address
    outportb (port, low);
    outportb (port, high);
}


void i86_dma_set_count (unsigned short channel, unsigned char low, unsigned char high)
{
    if (channel > 7) return;   // Ignore if channel > 7

    // Calculate port
    unsigned short port = (channel >= 4) ?  4*(channel - 4) + 0xc2
                                         :  (2*channel) + 1;

    // Set count
    outportb (port, low);
    outportb (port, high);
}


void i86_dma_set_external_page_registers (unsigned char channel, unsigned char val)
{
    unsigned short port = 0;

    switch (channel) {
        case 1: port = 0x83; break;
        case 2: port = 0x81; break;
        case 3: port = 0x82; break;
        // <- nothing should ever write to chan 4
        case 5: port = 0x89; break;
        case 6: port = 0x87; break;
        case 7: port = 0x88; break;
        default: if (channel == 4 || channel > 14) return;
    }

    outportb(port, val);
}


void i86_dma_mask_channel (unsigned char channel)
{
    if (channel <= 4) outportb (DMA0_CHANMASK_REG, (1<< (channel -1)));
    else outportb (DMA1_CHANMASK_REG, (1<< (channel -5)));
}


void i86_dma_unmask_channel (unsigned char channel)
{
    if (channel <= 4) outportb (DMA0_CHANMASK_REG, channel);
    else outportb (DMA1_CHANMASK_REG, channel);
}


void i86_dma_unmask_all()
{
    outportb (DMA1_UNMASK_ALL_REG, 0xff);
}


void i86_dma_reset_flipflop (unsigned char dma)
{
    switch (dma) {
        case 0: outportb (DMA0_CLEARBYTE_FLIPFLOP_REG, 0xff);
        case 1: outportb (DMA1_CLEARBYTE_FLIPFLOP_REG, 0xff);
    }
}

void i86_dma_reset ()
{
    outportb (DMA0_TEMP_REG, 0xff);
}


void i86_dma_set_mode(unsigned char channel, unsigned char mode)
{
    unsigned char dma = (channel < 4) ? 0:1;
    unsigned char chan = (dma == 0) ? channel : channel-4;

    i86_dma_mask_channel (channel);
    outportb ((channel < 4) ? DMA0_MODE_REG : DMA1_MODE_REG, chan | mode);
    i86_dma_unmask_all ();
}


void i86_dma_set_read (unsigned char channel)
{
    i86_dma_set_mode (channel, DMA_MODE_READ_TRANSFER | DMA_MODE_TRANSFER_SINGLE);
}


void i86_dma_set_write (unsigned char channel)
{
    i86_dma_set_mode (channel, DMA_MODE_WRITE_TRANSFER | DMA_MODE_TRANSFER_SINGLE);
}

Jarvix
Posts:21
Joined:Mon Apr 06, 2009 6:08 am

Re: Problem with floppy driver - IRQ6 not firing

Post by Jarvix » Sat Aug 07, 2010 10:46 am

Are you sure the irq-code works? DO you have a working keyboard or PIT timer?

About the 5" floppies, i see no reason why you would want to support it, who ever has those? Nobody.

Same for 4 floppy drives, new pc's do not have ANY floppy drive, some older pc's have, maybe one or two have 2 drives, but 3 or 4? Unneeded support. More code is more chance on bugs and instability.

Good luck ;)

// Jarvix
Jinix. Kernel programming is a black art that should be avoided if at all possible.

chibicitiberiu
Posts:22
Joined:Sat Jul 17, 2010 7:55 am

Re: Problem with floppy driver - IRQ6 not firing

Post by chibicitiberiu » Sat Aug 07, 2010 10:56 am

Jarvix wrote:Are you sure the irq-code works? DO you have a working keyboard or PIT timer?

About the 5" floppies, i see no reason why you would want to support it, who ever has those? Nobody.

Same for 4 floppy drives, new pc's do not have ANY floppy drive, some older pc's have, maybe one or two have 2 drives, but 3 or 4? Unneeded support. More code is more chance on bugs and instability.

Good luck ;)

// Jarvix
Yes, I do have working clock and keyboard with IRQs.

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Problem with floppy driver - IRQ6 not firing

Post by Andyhhp » Tue Aug 10, 2010 2:21 pm

About the 5" floppies, i see no reason why you would want to support it, who ever has those?
You are right - no one has used 5" floppies.

However, what I assume you mean is 5.25" floppies from back in the day, which would make me, and quite a few other people nobody.


~Andrew
Image

chibicitiberiu
Posts:22
Joined:Sat Jul 17, 2010 7:55 am

Re: Problem with floppy driver - IRQ6 not firing

Post by chibicitiberiu » Tue Aug 10, 2010 4:16 pm

Andyhhp wrote:
About the 5" floppies, i see no reason why you would want to support it, who ever has those?
You are right - no one has used 5" floppies.

However, what I assume you mean is 5.25" floppies from back in the day, which would make me, and quite a few other people nobody.


~Andrew
Yes, about 5.25" floppies I was talking about... but let's not change subject please... What could be the problem with this driver? I confess, I didn't try very hard to debug it last week, I've been redesigning the console screen, now it's more portable and more colorful, it can even display the console in a window if using a GUI, provided you give it addresses to some basic I/O routines.

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Problem with floppy driver - IRQ6 not firing

Post by Andyhhp » Tue Aug 10, 2010 5:12 pm

I cant see anything obviously wrong.

Can you get the interrupt to fire in non DMA mode?
Image

chibicitiberiu
Posts:22
Joined:Sat Jul 17, 2010 7:55 am

Re: Problem with floppy driver - IRQ6 not firing

Post by chibicitiberiu » Wed Aug 11, 2010 9:50 am

Andyhhp wrote:I cant see anything obviously wrong.

Can you get the interrupt to fire in non DMA mode?
And how do I do that? Since the non-DMA tutorial for floppy doesn't exist, and most emulators(?) don't support non-DMA floppy. And how would I test it if it's not supported on most emulators?

halofreak1990
Posts:92
Joined:Thu May 27, 2010 8:54 pm
Location:Netherlands

Re: Problem with floppy driver - IRQ6 not firing

Post by halofreak1990 » Wed Aug 11, 2010 11:09 pm

You could test it on real hardware, if available.

Anyways, are you sure the for loop actually runs?

Code: Select all

/*inline unsigned char i86_floppy_wait()
{
    unsigned temp = 2000000000;
    for (;i86_floppy_new_interrupt==0; temp--)
           if (!temp) return 0;

    i86_floppy_new_interrupt = 0;
    return 1;
}*/
you could do this instead:

Code: Select all

inline unsigned char i86_floppy_wait()
{
    while !(i86_floppy_new_interrupt);

    i86_floppy_new_interrupt = 0;
    return 1;
}
It basicly does the same as your code, except that it's guaranteed to work.

chibicitiberiu
Posts:22
Joined:Sat Jul 17, 2010 7:55 am

Re: Problem with floppy driver - IRQ6 not firing

Post by chibicitiberiu » Thu Aug 12, 2010 4:42 am

I don't think that's the problem. And if you take a closer look, the wait function is commented, and a macro similar to your function is actually used.

Code: Select all

void i86_floppy_handler(ISR_stack_regs *r)
{
    i86_floppy_new_interrupt = 1;
    printf ("[FLOPPY] [INT]\n");
}
It should print on the screen when the interrupt is fired, and this never happens.

I tested it on real hardware as well, but same as on emulator. Weird enough, when the timer is over, (tested this only in emulators) it seems to read ok.

halofreak1990
Posts:92
Joined:Thu May 27, 2010 8:54 pm
Location:Netherlands

Re: Problem with floppy driver - IRQ6 not firing

Post by halofreak1990 » Thu Aug 12, 2010 1:04 pm

chibicitiberiu wrote:I don't think that's the problem. And if you take a closer look, the wait function is commented, and a macro similar to your function is actually used.

Code: Select all

void i86_floppy_handler(ISR_stack_regs *r)
{
    i86_floppy_new_interrupt = 1;
    printf ("[FLOPPY] [INT]\n");
}
Sorry, I must've missed that one. Anyway, this is my own interrupt handler. I'm not sure if the ASM is truly necessary, but it works, so I'm happy.

Code: Select all

void _cdecl i86_flpy_irq () {

	_asm add esp, 12
	_asm pushad
	_asm cli

	//! irq fired
	_FloppyDiskIRQ = 1;

	//! tell HAL we are done
	interruptdone( FLOPPY_IRQ );

	_asm sti
	_asm popad
	_asm iretd
}
When looking at the difference between our two handlers, I got an idea; are you informing the PIC(s) that the interrupt has been handled? If not, no other interrupt will be serviced, or intercepted by your kernel, once the first floppy interrupt has been triggered. That is, assuming the other interrupt handlers tell the PIC(s) that new interrupts can be sent.

chibicitiberiu
Posts:22
Joined:Sat Jul 17, 2010 7:55 am

Re: Problem with floppy driver - IRQ6 not firing

Post by chibicitiberiu » Thu Aug 12, 2010 7:29 pm

halofreak1990 wrote: When looking at the difference between our two handlers, I got an idea; are you informing the PIC(s) that the interrupt has been handled? If not, no other interrupt will be serviced, or intercepted by your kernel, once the first floppy interrupt has been triggered. That is, assuming the other interrupt handlers tell the PIC(s) that new interrupts can be sent.
Yes. I have really beautiful IRQ handler. They are made so that they all lead to a common function, which has stored in memory it's own IVT (which is just a 16-item list with pointers to functions). If an interrupt is not handled, it simply ignores it, but doesn't halt the system with an exception. It also sends EOI to the Master/Slave PIC, as required.


And as I said before, if it was called even that one time, I would see it on the screen.


And by the way, it isn't a very good idea to clear interrupts during the execution of the handler... for example the PIT may loose ticks and system clock would suffer, a keypress/release may be ignored... could cause trouble.

Usually an interrupt handler that has a lower number cannot be interrupted by one with a higher number. For example, the PIT (IRQ0) can interrupt the execution of any handler, but the floppy interrupt (IRQ6) can only interrupt IRQs > 6.

halofreak1990
Posts:92
Joined:Thu May 27, 2010 8:54 pm
Location:Netherlands

Re: Problem with floppy driver - IRQ6 not firing

Post by halofreak1990 » Thu Aug 12, 2010 7:42 pm

chibicitiberiu wrote:And by the way, it isn't a very good idea to clear interrupts during the execution of the handler... for example the PIT may loose ticks and system clock would suffer, a keypress/release may be ignored... could cause trouble.
Since I'm only setting a variable and execute one function, the time I have interrupts disabled will definately be shorter than the interval I set my PIT to.

chibicitiberiu wrote:Usually an interrupt handler that has a lower number cannot be interrupted by one with a higher number. For example, the PIT (IRQ0) can interrupt the execution of any handler, but the floppy interrupt (IRQ6) can only interrupt IRQs > 6.
I know this, and that is why Mike, who wrote that snippet (since it's copied from the tutorial) disabled interrupts.
You don't want an interrupt handler to be interrupted. That would lead to an unpredictable program flow, if not exceptions, and would compromise the stability of the software.

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Problem with floppy driver - IRQ6 not firing

Post by Andyhhp » Thu Aug 12, 2010 7:49 pm

I point you both at the intel developer manual which has the following snippets in:
Trap and Interrupt gates are similar, and their descriptors are structurally the same, they differ only in the type field. The difference is that for interrupt gates, interrupts are automatically disabled upon entry and reenabled upon IRET which restores the saved EFLAGS
Because IA-32 tasks are not re-entrant, an interrupt-handler task must disable interrupts between the time it completes handling the interrupt and the time it executes the IRET instruction. This action prevents another interrupt from occurring while the interrupt task's TSS is still marked busy, which would cause a general-protection (#GP) exception.
Basically, dont go messing with the interrupt flag in your interrupt routines.
Image

chibicitiberiu
Posts:22
Joined:Sat Jul 17, 2010 7:55 am

Re: Problem with floppy driver - IRQ6 not firing

Post by chibicitiberiu » Fri Aug 13, 2010 6:39 am

Andyhhp wrote:
Basically, dont go messing with the interrupt flag in your interrupt routines.
I don't get it. Should I or should I not disable interrupts during the execution of a handler?

You are saying like I shouldn't, the intel manuals from what I understand are saying like I should.

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: Problem with floppy driver - IRQ6 not firing

Post by Andyhhp » Fri Aug 13, 2010 9:13 am

The intel manual is stating that interupts should not be enabled during the execution of an interrupt routine.

As a programmer, you have 2 choices in the IDT. You can use an Interrupt Gate which will automatically disable interrupts for you, or you can use a Trap Gate which wont.

Therefore, the actual code in your interupt handler routines depends on which type of handler it is. As this tutorial uses excusivly Interrupt Gates, you should just ignore the interrupt flag and know that it is delt with automatically for you.

~Andrew
Image

Post Reply