Page 1 of 1

IDT help

Posted: Fri Jul 21, 2006 7:13 pm
by reason
I'm having troubles setting up my IDT. I have read the manuals and the pages in the faq but still have some questions:

1. What are the differences between Trap, Interrupt and Task gates? From my understanding the task gate switches the task for you. But I don't get the difference between intterupt and trap gates.

2. I understand that when you load the IDTR you must give a 16bit size, and then the 32bit memory location. What I don't understand is what is the size measured in? The number of bits of the table, bytes, or is it the number of entries?

3. For interrupt and trap gates what do I put in the two 16bit offsets? Do I put the first 16bits of the address in the first offset field and the other 16bits in the other offset field?

4. Also what would I put for the segment value? Since grub sets the segment size to 4gb I should just fill this value with 0 right?

Here is the code I have written so far regarding interrupts

Code: Select all

struct idt_entry{
   unsigned offset:16;
   unsigned segment:16; //0?
   unsigned reserved:8; //always 0
   unsigned flags:8; // 0x8E for 32bit interrupt gate
   unsigned offset2:16;
};

struct idt_pointer{
   unsigned table_size:16;
   unsigned base_location:32;
};

struct idt_entry idt[256];
struct idt_pointer idt_p;

void kernel_entry(){
   int i;
   idt_p.table_size = 16383 // (256 * 65) - 1
   idt_p.base_location = &idt;
   for(i = 0; i < 256; i ++){ //fill the table
      //put other values here
      idt[i].reserved = 0;
      idt[i].flags = 0x8E;
   }
...

Thanks

Re:IDT help

Posted: Fri Jul 21, 2006 10:15 pm
by mhaggag
reason wrote: 1. What are the differences between Trap, Interrupt and Task gates? From my understanding the task gate switches the task for you. But I don't get the difference between intterupt and trap gates.
From the Intel IA-32 Architecture Software Developer's Manual, Volume 3, 5.12.1.2:
"The only difference between an interrupt gate and a trap gate is the way the processor handles the IF flga in the EFLAGS register. When accessing an exception or interrupt-handling procesdure through an interrupt gate, the processor clears the IF flag to prevent other interrupts from interferring with the current interrupt handler. A subsequent IRET instruction restores the IF flag to its value in the saved contents of the EFLAGS register on the stack. Accessing a handler procedure through a trap gate does not affect the IF flag."
2. I understand that when you load the IDTR you must give a 16bit size, and then the 32bit memory location. What I don't understand is what is the size measured in? The number of bits of the table, bytes, or is it the number of entries?
The size is measured in bytes--it is the size of your IDT entries minus one byte. Again, Volume 3, 5.10:
"The limit value is expressed in bytes and is added to the base address to get the address of the last valid byte. [snip] the limit should always be one less than an integral multiple of eight (that is, 8N - 1)."
3. For interrupt and trap gates what do I put in the two 16bit offsets? Do I put the first 16bits of the address in the first offset field and the other 16bits in the other offset field?
Yes, something like this:

Code: Select all

void idt_t::set_entry(uint index, uint32 base, uint16 segment, bool present, byte ring)
{
   // 
   // For reference, check Intel architecture's software developer's manual, Volume 3, 5.11
   //
   ASSERT(index < NUM_IDT_ENTRIES, _T("set_entry: <index> must be less than <NUM_IDT_ENTRIES>."));
   ASSERT(ring < 4, _T("set_entry: <ring> must be less than 4."));

   idt_entry_t& entry = m_entries[index];
   
   entry.base_low = base & 0xFFFF;
   entry.base_high= base>>16;
   entry.reserved = IDT_ENTRY_RESERVED;
   entry.segment = segment;
   entry.ring = ring;
   entry.present = present;
}
4. Also what would I put for the segment value? Since grub sets the segment size to 4gb I should just fill this value with 0 right?
The value should be the segment selector for whatever code segment the handlers are to run in (typically, kernel code segment). I don't know what segments GRUB sets up--I recommend you set up your own segments. You'll have to do this sooner or later to get user and system code and data segments, as well as a TSS (Task State Segment--for task switching).
Here is the code I have written so far regarding interrupts
You'd do well to:
1. Make sure your structures are packed. I #define PACKED as follows:

Code: Select all

#define PACKED __attribute__((packed))
...
// Later
struct idt_entry_t
{
} PACKED;
2. Separate the IDT management code into a module of its own.

Re:IDT help

Posted: Sat Jul 22, 2006 12:11 pm
by reason
Thanks for the help
2. Separate the IDT management code into a module of its own.
What do you mean by this? Do you mean like put it in its own file or function?

Re:IDT help

Posted: Sat Jul 22, 2006 12:17 pm
by mhaggag
reason wrote:
2. Separate the IDT management code into a module of its own.
What do you mean by this? Do you mean like put it in its own file or function?
Well, a module. That'd be more like a file in C, or a class in C++. Basically, expose functions for adding gate descriptors to the IDT (e.g. add_trap, add_interrupt, etc). Instead of having the kernel_entry fill the table, have an idt_init() that does that...got my point?

Re:IDT help

Posted: Sat Jul 22, 2006 12:20 pm
by reason
oh, ok I understand. I thought you meant module as in the minix type of module, which seems like it would cause the chicken and the egg type problem.