How do I know if an IRQ or Exception is firing?

When the PC boots up, the PIC IRQ's are mapped to interrupts 8 to 15 and 70 to 77.

So when your kernel boots up and you switch into protected mode, the PIC's remain unchanged, and the low 8 IRQ's end up corresponding to the same interrupt as CPU exceptions 8 to 15.

If one of these fire off, you can test if its an CPU exception or IRQ by testing some bits in the PIC status register but there is a much easier way, remap the PIC to use different interrupts than the CPU exceptions!

 

What is the PIC?

The PIC is a "Programmable Interrupt Controler" and is one of THE important chips, without it, x86 would not be an interrupt driven architecture.

There needs to be a way for perhiperals and other devices external of the CPU to tell the system than an event has happened or needs to happen. exampels of this; hard disk IO, modem/serial ports, keyboard.

Without the PIC interface, you would have to poll all the devices in the system to see if they want to do anything (signal an event), but with the PIC, your system can run along nicely until such time that a device wants to signal an event, which means you dont waste time going to the devices, you let the devices come to you when they are ready.

In the begining, the age of the IBM XT, we had only 1 PIC chip giving us 8 hardware interrupt lines, but the 8259A PIC chip has a neat abality, it can cascade!

Cascading means you can daisy chain PIC chips together. This is what happened with the introduction of the IBM AT, we had a second PIC chip cascaded onto the first, giving us a total of 15 hardware lines... Why 15 and not 16? Thats because when you cascade chips, the PIC needs to use one of the int lines to signal to the other chip.

Thus, in an AT, IRQ line 2 is used to signal the second chip... But to confuse things more, IRQ 9 is redirectd to IRQ 2. So when you get an IRQ 9, the signal is redirected to IRQ 2.

 

So can I remap the PIC?

The PIC has the ability to be re-programmed to use a different set of interrupt values than the default ones. The default PIC values are;
PIC IRQ INT
008
019
02A
03B
04C
05D
06E
07F
1870
1971
1A72
1B73
1C74
1D75
1E76
1F77

The PIC is programmable, and can be remapped quite easily, but each PIC vector must be divisable by 8, as the 8259A discards the lower 3 bits.

In x86 protected mode, it is good to remap the PICs beyond 32 as Intel have designated the first 32 interrupts as "reserved" for cpu exceptions. eg:

remap_pics(0x20, 0x28);
will remap the pics using 16 linear interrupts from 32 to 48 (0x20-0x2F).

/* remap the PIC controller interrupts to our vectors
   rather than the 8 + 70 as mapped by default */

#define	PIC1		0x20
#define	PIC2		0xA0
#define	PIC1_COMMAND	PIC1
#define	PIC1_DATA	(PIC1+1)
#define	PIC2_COMMAND	PIC2
#define	PIC2_DATA	(PIC2+1)
#define	PIC_EOI		0x20

#define	ICW1_ICW4	0x01		/* ICW4 (not) needed */
#define	ICW1_SINGLE	0x02		/* Single (cascade) mode */
#define	ICW1_INTERVAL4	0x04		/* Call address interval 4 (8) */
#define	ICW1_LEVEL	0x08		/* Level triggered (edge) mode */
#define	ICW1_INIT	0x10		/* Initialization - required! */

#define	ICW4_8086	0x01		/* 8086/88 (MCS-80/85) mode */
#define	ICW4_AUTO	0x02		/* Auto (normal) EOI */
#define	ICW4_BUF_SLAVE	0x08		/* Buffered mode/slave */
#define	ICW4_BUF_MASTER	0x0C		/* Buffered mode/master */
#define	ICW4_SFNM	0x10		/* Special fully nested (not) */

void remap_pics(int pic1, int pic2)
{
	UCHAR	a1, a2;

	a1=inb(PIC1_DATA);
	a2=inb(PIC2_DATA);

	outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4);
	io_wait();
	outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
	io_wait();
	outb(PIC1_DATA, pic1);
	io_wait();
	outb(PIC2_DATA, pic2);
	io_wait();
	outb(PIC1_DATA, 4);
	io_wait();
	outb(PIC2_DATA, 2);
	io_wait();

	outb(PIC1_DATA, ICW4_8086);
	io_wait();
	outb(PIC2_DATA, ICW4_8086);
	io_wait();

	outb(PIC1_DATA, a1);
	outb(PIC2_DATA, a2);
}
		

 

So whats this NMI then?

The NMI (&qout;Non Maskable Interrupt") is a hardware driven interrupt much like the PIC interrupts but the NMI goes diretcly the cpu, and not via the PIC controller.

Luckily you CAN have control over the NMI, otherwise you could be in deep trouble.

The NMI is turned "on"e; (set high) by the memory module when a memory parity error occurs.

You have to be carefull about disabling the NMI and the PIC for extended periods of time, your system will hang unless it has a failsafe timer! (Which you do have.. just down kill the PIT timer :)

/* enable the NMI */
void NMI_enable(void)
{
	outb(0x70, inb(0x70)&0x7F);
}

/* disable the NMI */
void NMI_disable(void)
{
	outb(0x70, inb(0x70)|=0x80);
}

		

 

APIC? Advanced Programmable Interrupt Controller

APIC is the Intel standard for the "new" PIC. Its used in multiprocessor systems.

I have no more info at this time.

 

OPIC? Open Programmable Interrupt Controller

I have no info on OPIC currently... Other than its a non-intel standard.