bochs-emu / Bochs

Bochs - Cross Platform x86 Emulator Project
https://bochs.sourceforge.io/
GNU Lesser General Public License v2.1
875 stars 102 forks source link

IRQs produced by the secondary PIC, and lowered before IRQ#2 is raised, become spurius IRQs#15 #11

Closed JuantAldea closed 2 years ago

JuantAldea commented 2 years ago

Hello Bochs team,

I believe I have stumbled upon a bug while developing an ATA PIO driver for my toy operating system. My driver was polling the status register of the primary ATA device, and thus, clearing the interrupt, as I wasn't reading from the secondary.

My IRQs, as usual, are remapped from 0x20 for the Master PIC and from 0x28 for the Slave.

The following log shows a trace of the emulation of the operating system I'm developing. There are some additions and modifications to the log messages.

01759425355i[HD    ] ASDF HARDDRV: raising interrupt 14 {DISK}   
01759425355d[IOAPIC] set_irq_level(): INTIN14: level=1           
01759425355i[PIC   ] ASDF SLAVE IRQ line 14 now high             <------- [1]
01759425355i[PIC   ] ASDF slave irr: 40
01759425355i[PIC   ] ASDF Interrupt requests: 40
01759425355i[PIC   ] ASDF Interrupt mask: 0
01759425355i[PIC   ] ASDF Unmasked Interrupts: 40
01759425355i[PIC   ] ASDF signalling IRQ #14
01759425355i[PIC   ] ASDF MASTER IRQ line 2 now high
01759425355i[PIC   ] ASDF Interrupt requests: 5
01759425355i[PIC   ] ASDF Interrupt mask: 0
01759425355i[PIC   ] ASDF Unmasked Interrupts: 5
01759425489d[IOAPIC] set_irq_level(): INTIN14: level=0
01759425489i[PIC   ] ASDF IRQ line 14 now low                    <------- [2]
01759479170i[CPU0  ] ASDF interrupt(): vector = 20, TYPE = 4, EXT = 0
01759479170d[CPU0  ] interrupt(): INTERRUPT TO SAME PRIVILEGE
01759482224i[PIC   ] ASDF Interrupt requests: 5
01759482224i[PIC   ] ASDF Interrupt mask: 0
01759482224i[PIC   ] ASDF Unmasked Interrupts: 5
01759484885d[CPU0  ] inhibit interrupts mask = 1
01759484886d[CPU0  ] INTERRUPT RETURN TO SAME PRIVILEGE LEVEL
01759484894d[CPU0  ] inhibit interrupts mask = 1
01759484896i[CPU0  ] ASDF InterruptAcknowledge vector: 20
01759484896i[CPU0  ] ASDF interrupt(): vector = 20, TYPE = 0, EXT = 1
01759484896d[CPU0  ] interrupt(): INTERRUPT TO SAME PRIVILEGE
01759487949i[PIC   ] ASDF Interrupt requests: 4
01759487949i[PIC   ] ASDF Interrupt mask: 0
01759487949i[PIC   ] ASDF Unmasked Interrupts: 4
01759487949i[PIC   ] ASDF signalling IRQ #2                   <------ [3]
01759490610d[CPU0  ] inhibit interrupts mask = 1
01759490611d[CPU0  ] INTERRUPT RETURN TO SAME PRIVILEGE LEVEL
01759490612i[PIC   ] ASDF IAC SLAVE_IRQ: 6, SLAVE_OFFSET: 28, VECTOR: 2e (IRR: 0) <------ [4]
01759490612i[PIC   ] ASDF IAC: SLAVE PIC SPURIUS!      
01759490612i[CPU0  ] ASDF InterruptAcknowledge vector: 2f
01759490612p[CPU0  ] >>PANIC<< ASDF interrupt(): 2f
01759490612i[CPU0  ] ASDF interrupt(): vector = 2f, TYPE = 0, EXT = 1            <------- [5]

Has can be deduced from the log, if the IRQ#14 [1] goes low [2] before IRQ#2 is raised [3], Bochs will morph the lowered IRQ#14 interrupt into [4] an spurious IRQ#15 [5].

The aforementioned behavior is produced by line, which will morph any slave interrupt lowered, into an IRQ#15.

    if ((BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr) == 0) {
      return (BX_PIC_THIS s.slave_pic.interrupt_offset + 7);
    }

I don't know if the behavior I'm describing is intended, but it feels smelly to me, although this has to be well-exercised code path. I'd also like to add that it has been driving me crazy because QEMU treated the interrupt as an IRQ#14.

The logging modifications I've made are available here

Best regards.

JuantAldea commented 2 years ago

After studying a bit more this is exactly how it is supposed to work. Sorry for the inconveniences.