views:

625

answers:

6

In the Intel software developers manual it says that interrupt vectors 32-255 are usually user defined for external IO devices. In my systems programming class I must develop a simple device driver. My question is how can I define a specific interrupt vector to be used for a specific device? Is this done with the BIOS?

Note: we are developing a simple operating system so my situation is quite specific, however, in the end I need to understand how this all happens on an x86 system. Currently our system is set up so that a few interrupt vectors above 32 are assigned to devices like a serial port and keyboard. In reading the datasheet for the Intel 82801EB ICH5 IO controller, specifically the section concerning the 8259 PICs, it says that IRQ15 is the secondary IDE channel. How would that eventually be put on the stack as a interrupt vector?

I may just be so confused that this question didn't make sense, so I apologize in advance.

EDIT: So our systems programming class has a very simple OS, which has kernel routines for installing ISRs to handle specific interrupts given the vector number. In our class last quarter the professor gave us a header file that defined the keyboard as vector number 0x2c or something similar. I am trying to find out how to map the primary and/or secondary IDE channel interrupts to various ISRs using our kernel routines. For now, all of the unused interrupt vectors have a default handler that would print messages if an interrupt occurred, so IDE interrupts aren't even on at the moment, however that is another question.

A: 

As I recall there is a vector table in the beginning of memory space that points to the routine to call when a specific interrupt occurs. I may be hitting at too low a level here (old x86 Assembly programmer) but at the base level you get your vector installed in that table then your routine is called. I've not got any of my old reference material with me so can't give you the actual calls but I'd be surprised if the official method operated outside of the BIOS.

In these days of GUIs I'm sure there are other, more appropriate methods, that allow interrupt sharing and all that good stuff.

EDIT: Ignore much of that, I've just seen that you are looking at interrupt 16 and above which are outside of the hardware interrupts. I moved away from that level of programming before there were any interesting bits of hardware in that space so I only ever dealt with the first 15 IRQs (the 16th being the cascade between controllers). I'm leaving it just in case it's of interest to anyone else :)

Lazarus
+1  A: 

It's been a while since I've dealt with this stuff so this may be off: I recall that the PC interrupt controller has 15 IRQ lines. These map to specific adjacent x86 interrupt vectors. So when a peripheral triggers an IRQ line, the PIC interrupts the CPU and tells which vector to jump to, as if the corresponding INT instruction was executed. Some IRQ are hardcoded to certain peripherals, but I believe that PCI devices negotiate with the OS for IRQs and some other resources (as do the legacy ISA PnP devices).

I do not understand what you mean by 'How would that eventually be put on the stack as a interrupt vector?'

TrayMan
What I meant was, how would I identify that an interrupt vector given to the kernel is say a primary IDE channel? As you said, if an IDE channel triggers its respective IRQ line, then how will I know which vector number to associate with the IDE channel that was the source?
TURBOxSPOOL
+1  A: 

You can program the PIC's (programmable interrupt controller) to map certain device IRQ's.

On x86, there are two PIC's which are daisy-chained giving IRQ0-IRQ17. IRQ0-7 is managed by the 8259 and IRQ8-15 by a second 8259. The first signals the CPU and is the master, with the second (the slave) signaling the first.

The IDT (interrupt descriptor table) maps the interrupts to the addresses of ISR (interrupt service routines). Interrupts can be directly raised with the INT instruction (software traps).

For example, to raise interrupt 0x80, execute INT 0x80.

To handle 0x80, mov [0x80*4], int_80_handler. Assuming a 32-bit architecture, the address of the int_80_handler function is now stored at the 0x80'th location in the IDT.

You will find these helpful:
http://en.wikipedia.org/wiki/Intel_8259
http://en.wikipedia.org/wiki/Interrupt_Handler
http://en.wikipedia.org/wiki/Interrupt
http://en.wikipedia.org/wiki/Interrupt_descriptor_table

Andy
I think I am following you, however, my question is how would I map an interrupt, say 0x3c to the primary IDE channel interrupt on the PIC? Like in your example you used int 0x80. My professor some how has done this, but I haven't had a chance to pick his brain.
TURBOxSPOOL
+1  A: 

There are two possible ways for a device to get an interrupt:

  1. Use the Plug and Play or Pci mechanism. If you do so the BIOS will call your peripherical device and ask for the resource requirements. Afterwards your driver can enumerate the plug-and-play devices, search for the supported device and get the hardware interrupt from the device.

  2. How it has been done in the early days: Just use one interrupt. Add a dip-switch to the device that allows the user to select between different interrupts. The resource allocation is at the hand of the users now. The user will also pass the interrupt number to the driver at load time somehow.

Now how to hook the interrupt: That depends on the OS and the mode the x86 is running in. For a naked, bare bone system you can query the IDT (Interrupt Descriptor Table) via a special instruction. Once you have that IDT you can get the address and poke the address of the IRQ handler into the correct slot. For real mode I don't know how it's done anymore.

If you have at least a little realtime OS or something OS-like running, it's likely that there is already a kernel function that does the hard work for you.

Nils Pipenbrinck
A: 
TURBOxSPOOL
A: 

INT 21h / AH=25h - set interrupt vector; input: AL = interrupt number. DS:DX -> new interrupt handler.

adrian