Loading IDT

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.
tm-

Loading IDT

Post by tm- »

Ok, now it's the time for loading IDT and setting up interrupts. I have read those tutorials about this subject on BonaFide, and I think I got the idea, but I have some questions.

1) Should I remap the PIC first and after that load the IDT?
2) Loading the IDT seems to be done in assembly everywhere.. Do I have to load it then in the file that calls the kernel? Because my kernel is in C.

I couldn't find any example kernel (simple and small), which would have done that..
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Loading IDT

Post by Pype.Clicker »

(1) the order between PIC and IDT is irrelevant provided that you do both before you re-enable interrupts.

(2) you'll have to have assembler bits for interrupt handlers (the so-called interrupt wrappers). That remains the only clean way to do it. (see the FAQ)

setting the IDTR at least is easier in asm though it can be done in C aswell (with proper care taken while accessing IDTR). You can perfectly fill the descriptor table from C.

That being said, my favourite approach remains to have a 'generic handler' called by the wrapper that will use the interrupt number to access a "list of actions" to be taken when the interrupt arises ;)
tm-

Re:Loading IDT

Post by tm- »

Hmm.. I didn't really get the point of your answer.. Where should I put that IDT loader? Kernel c-code or to the file that loads the kernel(which is in asm)?

Let's take an example:

Calls main() (kernel loader)

Code: Select all

[BITS 32]
[global start]
[extern _main]

start: 
  call _main

  cli
  hlt
And the kernel

Code: Select all

void main(void)
{
  char *str = "Welcome";
  printf(str);
  while(1);
}
Where do I load the IDT in these files? First I remap PIC in kernel main and what then?? It would help if one could use these code examples and show how its done.
AR

Re:Loading IDT

Post by AR »

I determined the order of the inits by the dependencies, everything needs the screen, everything except the screen needs the physical manager, everything except the physical manager and Screen needs the Virtual Manager and so forth. ie. Screen, Physical Manager, Virtual Manager, Kernel Heap, GDT, PIC, IDT, ...
(All these are from int main(), my bootloader between GRUB and the Kernel does nothing besides activate paging and convert GRUBs multiboot data into something more useful)

Mapping the PIC in and of itself does absolutely nothing. Just like reprogramming the IDT in and of itself does absolutely nothing as well. Once both are done however and you enable interrupts then something happens, the order of the 2 is irrelevant as long as the third event (Enable interrupts) does not occur before the other 2.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Loading IDT

Post by Pype.Clicker »

You could for instance have something like this:

Code: Select all

[BITS 32]
[global start]
[extern _main]
[global _idt_start]

; you may like to have it in BSS section
_idt_start:
   resb 8*HOW_MANY_IDT_ENTRIES

idtr:
   dw _idt_end - _idt_start
   dd _idt_start

start:
  lidt [idtr]
  call _main
  
  cli
  hlt

Code: Select all

extern struct IDTDescr _idt_start[HOW_MANY_IDT_ENTRIES];

void main(void)
{
  char *str = "Welcome";

  setup_pic(0x20,0x28)
  setup_timer(_idt_start+0x20);

  printf(str);
  while(1);
}
tm-

Re:Loading IDT

Post by tm- »

Thanks, now I got it.. Now just need to go and try to get it working :)
DruG5t0r3

Re:Loading IDT

Post by DruG5t0r3 »

Just setting up an IDT isn't enough to do a "sti" you need to setup some at least dummy fault and irq handlers.
AR

Re:Loading IDT

Post by AR »

DruG5t0r3 wrote: Just setting up an IDT isn't enough to do a "sti" you need to setup some at least dummy fault and irq handlers.
eh? What's the point of loading an empty IDT to begin with?
DruG5t0r3

Re:Loading IDT

Post by DruG5t0r3 »

AR wrote:
DruG5t0r3 wrote: Just setting up an IDT isn't enough to do a "sti" you need to setup some at least dummy fault and irq handlers.
eh? What's the point of loading an empty IDT to begin with?
Well thats my point...an empty IDT = you will eventually crash your kernel.
tm-

Re:Loading IDT

Post by tm- »

What should I put to the offset of the idt-descriptor, which should determine the address of the ISR? Yes I know, the address where the ISR is, but if the ISR is in the kernel in C, how can I find out the address of it? It would be easy to do in asm but I want to put the ISR in the kernel.
AR

Re:Loading IDT

Post by AR »

The IDT is on top of segments which are on top of paging, if you're using flat segments then the IDT address is whatever page the IDT is mapped on.

Creating the IDT Entry in C is easy:

Code: Select all

void CreateIDTEntry(void (*ISR)(), unsigned char intnum)
{
   IDTEntry idte;
   idte.ISRLow = (unsigned int)ISR & 0xFFFF;
   idte.ISRHigh = (unsigned int)ISR & 0xFFFF0000 >> 16;
   //Rest of entry
   AddEntryToIDT(&idte, intnum);
}
You would operate this code something like:

Code: Select all

extern void AssemblyISRStub1();
CreateIDTEntry(AssemblyISRStub1, 1);
The ISR Stub has to be assembly, you can't enter the C code directly.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Loading IDT

Post by Pype.Clicker »

You should read the FAQ about it, really.
tm-

Re:Loading IDT

Post by tm- »

I have read all the tutos in BonaFide and osfaq about the subject. But I can't see where's told about putting ISR's address to the offset in the descriptor? Or do I have to put the ISR to some location in memory and then put the memory address to the offset?

The way I do it:

Code: Select all

isr1:
  pusha
  push gs
  push fs
  push ds
  push es

  extern _keyboard_interrupt
  call _keyboard_interrupt
  
  pop es
  pop ds
  pop fs
  pop gs
  popa
  iret
And the interrupt descriptor for keyboard IRQ:

Code: Select all

  dw 0x0000
  dw 0x08
  dw 0x8E00
  dw isr1
Both codes are in the file that loads the kernel, and what do I have to put to that offset so the isr1 gets called?

And thanks for help :)
AR

Re:Loading IDT

Post by AR »

The pointer is 32bits but is unfortunately split in 2 parts:

Code: Select all

 dw isr1 & 0xFFFF
dw 0x08
dw 0x8E00
dw (isr1 >> 16) & 0xFFFF
Whether or not this builds, I wouldn't know. I usually generate the ISRs in C/C++
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Loading IDT

Post by Pype.Clicker »

it will/won't compile depending on your assembler (nasm may require [tt](isr1 - $$)[/tt]) and depending on whether the IDT and ISRx are in the same file or not.
and it will/won't work depending on the offset of that specific file in your image (if you have it with ORG0, everything is fine ... otherwise, beware).

So you're _much_ better to fill your IDT at runtime with

Code: Select all

mov eax, isr1
mov [idt+<intnum>*8+OFFSET_LO],ax
shr eax,16
mov [idt+<intnum>*8+OFFSET_HI],ax
Post Reply