Really needs help - IRQs

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Derek

Really needs help - IRQs

Post by Derek »

Ive started writing an OS and Im done with the boot loader, Protected Mode, and a very small kernel (printf functions and all that) I guess the next step is to get interrupts/exceptions working.. but how to do this? Ive read lots about it but I dont really understand it.. Is this totally wrong?:
>>Disable interrupts
>>Remap the PIC
>>Load IDT and all that
>>Unmask the IRQs I wanna catch.. and so on..
Cause I know that I gotta do this, but I dont know Why I have to remap the pic or how to do all this? Anyone who could explain all these steps shortly or give me a link to a tutorial? Would be very appreciated, been stuck for over a week now
hartyl

RE:Really needs help - IRQs

Post by hartyl »

everything is just logic:
>>Disable interrupts
while configuring the interrupt-thingys there sould no interrupt occour, so we disable them.

>>Remap the PIC
you do this to get the interrupts. this is done that the PIC can cause an interrupt in the program-execution. after this, the interrupts from the periphal devices can be handeled just like the NMIs or software-interrupts (the int-instruction)

>>Load IDT and all that
this step tells the cpu what to do, when an interrupt occours: what address should it jump to, what priority level to use, what segment-registers to use.

>>Unmask the IRQs I wanna catch.. and so on..
it is possible to mask some interrupts, so that interrupts from some devices are just ignored

greets, hartyl
Derek

RE:Really needs help - IRQs

Post by Derek »

But software interrupts and that.. what are they for? I mean I do want an interrupt to occur when someone hits a key or something, but what can I use software interrupts for? (the kbd-hit is a hardware-interrupt?) and I read that you need to remap the PIC cause of a "collision" with exceptions? I mean, of course I need to disable the interrupts..and I also need to tell the computer which code to execute when an interrupt occurs (the IDT) but I dont really get what I need to do with the PIC.
hartyl

RE:Really needs help - IRQs

Post by hartyl »

software-interrupts for example are used in linux for the systemcalls - just like in good old DOS:

mov eax,<functionnumber>
mov ebx,<param0>
mov ecx,<param1>
int 0x80

that int-instruction does the software-interrupt then.

>I read that you need to remap the PIC cause of a "collision" with exceptions?
yep; keyboard is int 1, i think. if the PIC just calls int 1 from the cpu, it "collidates" with the NMIs (the processor-internal exceptions). for example, the timer interrupt is int 0, but DIV0 (division by zero-exeption) is int 0 as well. so you have to remap the hardware-interrupts somewhere above 0x1F (this is where the reserved interruptnumbers end)
hope you got the idea :)

greets, hartyl
carbonBased

RE:Really needs help - IRQs

Post by carbonBased »

You don't *need* to remap the PIC, but it's in your own best interest.  Otherwise, hardware interrupts (IRQs), and exceptions will occur on the same interrupt.  For example: IRQ 1 (keyboard) is the same interrupt as the "coprocessor segment overrun" exception.

This would result in the *collision* you speak of.  It is entirely possible to dissern wether a interrupt was caused by a hardware int, or an exception... but why? :)  It's quicker, easier, and safer to remap hardware interrupts, such that they don't "collide".  As such, it's typical to map them to above 0x20 (32) as there are only 32 hardware exceptions that are defined.

Remapping is a fairly simple process:
  outportb (M_PIC, 0x11);                  /* start 8259 initialization */
  outportb (S_PIC, 0x11);
  outportb (M_PIC+1, M_VEC);       /* master base interrupt vector */
  outportb (S_PIC+1, S_VEC);        /* slave base interrupt vector */
  outportb (M_PIC+1, 1<<2);                /* bitmask for cascade on IRQ2 */
  outportb (S_PIC+1, 2);                   /* cascade on IRQ2 */
  outportb (M_PIC+1, 1);                   /* finish 8259 initialization */
  outportb (S_PIC+1, 1);

  outportb(M_IMR, 0xff);                /* Mask all interrupts */
  outportb(S_IMR, 0xff);

Where:
#define M_PIC  0x20     /* I/O for master PIC              */
#define M_IMR  0x21     /* I/O for master IMR              */
#define S_PIC  0xA0     /* I/O for slave PIC               */
#define S_IMR  0xA1     /* I/O for slace IMR               */

and:
#define M_VEC  32       /* Vector for master               */
#define S_VEC  40       /* Vector for slave                */

The above two are essential in the remapping, and define the base interrupt vector for the master and slave PIC.  You'll probably want to keep these values, as they'll place them just above the hardware exceptions, and contiguous.

Cheers,
Jeff
Derek

One thing I dont understand

Post by Derek »

thanks you :)
I dont get this with the software interrupts either.. cause I have to write an ISR for my software interrupts..so using INT xxx will only call a ISR..why dont call this method straight off, without using interrupts? Supoose I have an ISR called my_isr().. so instead of writing
INT ..
I just write
my_isr();
why use interrupts that´ll just call a function you´ve been writing by your own?
carbonBased

RE:One thing I dont understand

Post by carbonBased »

Interrupts provide two things that makes them ideal for use:
- protection
- common entry point

The first point relates to the mechanisms employed by the protected mode IDT.  Not only can you specify which privileged tasks can access each interrupt, but you can also configure the interrupt to actually perform a task switch, as well (task gate).

The second point refers to making your API nice and simple.  If you intend on all apps calling my_isr() you'll have to publish this functions address to each app, and perform runtime relocation for every simple used in this way.  Whenever you change your kernel in any way, this function address changes.  An interrupt vector is common, and will not change through kernel development (unless you explicitly change it, of course).

Also, with a global function pointer you risk your entire kernel to dangerous apps.  In order to have apps call this function, the code must actually be mapped into each application's memory space, which isn't exactly ideal.

Cheers,
Jeff
Derek

RE:One last thing

Post by Derek »

thank you, starting to understand this now :)
one thing about the remapping of the PIC.. when an exception occurs or and IRQ, the pic will send some signal to the CPU and tell it what happened.. and I guess that some IRQs and exceptions use the same "code" so the CPU wont know which one that occurs? So when I remap the PIC, I tell itwhich interrupts to send to the CPU, so it wont send the same signals as an exception would?
carbonBased

RE:One last thing

Post by carbonBased »

Somewhat, yes.

Think of it this way; when the processor encounters an exception, it raises an interrupt.  It raises the same one every time.  A coprocessor segment overrun will *always* raise interrupt 9.

It just so happens that, by default, the keyboard interface will also call interrupt 9.

There are ways to determine (in your interrupt handler) if the interrupt occured because of a keyboard event, or because of a coprocessor segment overrun... but it's much easier (and faster) to remap the hardware interrupts to occur above these exceptions.

Perhaps a better explaination:
When the PC was developed, there were only 8 exceptions.
As such, the hardware interrupts were configured with a base vector of 8, such that they wouldn't overlap.

Now-a-days, we have 16 exceptions.  However, for backwards compatibility, the hardware interrupts (IRQs) are still mapped with a base vector of 8 by default.  Because of this, hardware interrupts 8-15 overlap with these new exceptions.

The pic works, however, by adding all hardware interrupts (or rather, IRQs) to a base vector before calling the interrupt.

In our example, the keyboard is IRQ 1, and so by default (with the PIC mapped to base vector 8), when a keyboard event occurs, the PIC adds IRQ + BASE == 1 + 8 == 9, and calls interrupt 9.

We simply map hardware interrupts to 32 to avoid overlap.
Now when we receive a keyboard event, the PIC adds IRQ + BASE == 1 + 32 == 33, and calls interrupt 33.  No overlap.

Hope that all makes sense!

Cheers,
Jeff
Post Reply