Page 1 of 1

changing idt

Posted: Mon Jul 28, 2003 11:49 am
by Amet
Is there any special thing that I forget while changing idt in pmode. Ill be happy if someone say where am I doing wrong.
I want to change idt table. I disable all irqs. and here is my structures and codes. But when I execute an interrupt, I get int13 error.

My interrupt descriptor and register structures:

Code: Select all

typedef struct {
   word offset_l;
   word selector;
   byte param_cnt;
   byte access;
   word offset_h;
} InterruptDescriptor;

typedef struct {
   word limit;
   dword base;
} IDTR;
My main code:

Code: Select all

extern void isr_00_wrapper();

void SetIDTEntry (InterruptDescriptor *item, word selector, dword offset, byte access, byte param_cnt) {

   item->selector = selector;
   item->offset_l = offset & 0xFFFF;
   item->offset_h = (offset >> 16) & 0xFFFF;
   item->access = access;
   item->param_cnt = param_cnt;
}

void intoc()
{
   OutTextXY(10, 10, "Interrupt occured...");
   for(;;); //print and hang here..
}

int main(void)
{
   InterruptDescriptor idt[256];
   IDTR idtr;
   int a;
   disable();

   InitPIC(0x20, 0x28);


   for(a=0; a<256;a++)
       SetIDTEntry (&idt[a], 0x08, (word)&isr_00_wrapper, ACS_INT, 0);

     idtr.base = (word)&idt;
     idtr.limit = sizeof(idt)-1;
     lidt (&idtr);

   enable();

   CallInt(0x15);

   for(;;);
   return -1;
}
And my isr_00_wrapper and asm functions:

Code: Select all

_lidt:
   lidt [esp+4]
   ret


_isr_00_wrapper:
   push ds
   push es                      ; saving segment registers and
   pusha                        ; other regs because it's an ISR
   mov ax, 10h
   mov ds, ax
   mov es, ax                  ; load ds and es with valid selector
   call _intoc                 ; call actual ISR code
   popa                        ; restoring the regs
   pop es
   pop ds
   ret
I think my idtr.base is wrong. But Im not sure. Ill be happy if someone see where am I wrong and give an idea how to solve.

Re:changing idt

Posted: Mon Jul 28, 2003 12:43 pm
by mystran
IIRC there is a special alignment need for idtr. In gcc syntax that would be:

Code: Select all

typedef struct __idtr {
    word dummy __attribute__((aligned(4))); /* to fix alignment */
    word limit;
    dword base;
} IDTR;
For other compilers, it's something else =)

What is that param_cnt btw? AFAIK it should always be 0 so why it is a parameter? And double check that ACT_INT is right. Then fix the _isr_00_wrapper to return with "IRET" not "RET" :)

Re:changing idt

Posted: Mon Jul 28, 2003 2:00 pm
by Amet
Nope... I use that struct but that doesnt work. Yes, ret instruction must be iret, but the problem can not be there because the code never comes there, enters an infinite loop in c function(for debugging of course).

I think my problem is base address of my idt. Base parameter of my idtr is type of dword. And Im filling it with my idt address but converted to word. I think upper word of my base parameter must be filled something else. for instance in Alexei A. Frounze's pmode examples, he put ds into upper word like this:

idtr.base = ((dword)_DS)<<4;
idtr.base += (word)&idt;
idtr.limit = sizeof(idt)-1;
lidt (&idtr);

is it really necessary? (By the way how can I get ds reg value in gcc, may I have to write a getds() function?)My ds is filled with 0x10(gdt selector). I tried like this:

idtr.base = ((dword)0x10)<<4;
...

but not worked. Where am I doing wrong?

Re:changing idt

Posted: Mon Jul 28, 2003 6:01 pm
by Peter_Vigren
Amet wrote: I think my problem is base address of my idt. Base parameter of my idtr is type of dword. And Im filling it with my idt address but converted to word. I think upper word of my base parameter must be filled something else. for instance in Alexei A. Frounze's pmode examples, he put ds into upper word like this:

idtr.base = ((dword)_DS)<<4;
idtr.base += (word)&idt;
idtr.limit = sizeof(idt)-1;
lidt (&idtr);

is it really necessary? (By the way how can I get ds reg value in gcc, may I have to write a getds() function?)My ds is filled with 0x10(gdt selector). I tried like this:

idtr.base = ((dword)0x10)<<4;
...

but not worked. Where am I doing wrong?
The base should be the start address of the IDT in 32-bit, linear (real) address that is.

The value in Ds is shifted to the left 4 times, which is the same as multiplying with 16 because every segment is 16 bytes wide (Pype can explain it better... in fact he has done it somewhere here...)... Then the value of the pointer within the segment is added...

But shouldn't it be possible to use the 32-bit address directly?

Re:changing idt

Posted: Tue Jul 29, 2003 7:21 am
by Amet
I change my loading new idt code as below:

Code: Select all

__inline__ void lidt(IDTR *idtr)
{
   __asm__ __volatile__("lidt %0" : : "m" (idtr->limit));
}

__inline__ void SetIDTEntry(InterruptDescriptor *item,word selector, dword offset, byte access) {

  item->selector = selector;
  item->offset_l = offset & 0xFFFF;
  item->offset_h = offset >> 16;
  item->access = access;
  item->param_cnt = 0;
}

int main(void)
{
   InterruptDescriptor idt[256];
   IDTR idtr;
   int Cntr=0;

   disable();

   for(;Cntr < 256;Cntr++)
      SetIDTEntry(&idt[Cntr], 0x08, (long)&IsrWrapper, ACS_INT);

   idtr.base = ((dword)GetDS())<<4;
   idtr.base += (word)&idt;
   idtr.limit = sizeof(idt)-1;
   lidt (&idtr);

   enable();

   for(;;);
   return -1;
}
and asm part:

Code: Select all

_IsrWrapper:
   mov word [0B8000h],9F44h
   jmp $
   iret

_GetDS:
   mov ax, ds
   ret
when I tried this code in bochs, I got error:

>>PANIC<< exception(): 3rd (13) exception with no resolution

What am I doing wrong? Please someone help me changing my idt table. I stucked in here... :'(

Re:changing idt

Posted: Tue Jul 29, 2003 7:26 am
by mystran
Wheck the register strace, check at least EIP, then find that address from your kernel, and it should tell you which instruction it fails on.

Also, enable CPU debug messages in bochs and it will print the exceptions, so you know which exception caused the tripple fault.

Re:changing idt

Posted: Tue Jul 29, 2003 7:37 am
by Pype.Clicker
first, i would say that it's a rather bad idea to have IDTR and the IDT itself as main() local variables.

Code: Select all

 idtr.base = ((dword)GetDS())<<4;
   idtr.base += (word)&idt;
then, what the heck is this ? what kind of info do getDS() return ? if it's the selector's value, then you're messing real and protected mode up. If it's the current segment base, why the hell do you multiply it by 16.

and finally, if it's the real-mode DS value where you loaded your kernel, you should give it a more explicit name, or make it a macro like "logical_2_absolute" ...

Code: Select all

_inline__ void lidt(IDTR *idtr)
{
   __asm__ __volatile__("lidt %0" : : "m" (idtr->limit));
}
sounds better than

Code: Select all

_lidt:
   lidt [esp+4]
   ret
, but you should disassemble the function and make sure the value transmitted to lidt is the proper one. Actually, your IDTR is located at &(idtr->limit) ... but i'm unsure whether gcc will require the & or not for lidt (as i programmed the idt in the core ASM module of Clicker :)

Note that the tutorial of A. Frounze works in 16 bits protected mode and is (imho) not a clean starting base as there will be many things that will differ between code produced by TurboC and GCC ...

if the base of your Data Segment is 0, you don't even have to worry about having "idtr.base+=(some sort of DS-based manipulation)": just use

Code: Select all

idtr.base=&idt;

Re:changing idt

Posted: Tue Jul 29, 2003 9:45 am
by Amet
Yes Pype, you are right. It is better to put idt and idtr somewhere else but this is just a try, whenever it worked Ill code it better but I still not managed to make this code worked. And I think Alexei's examples make my mind mixed. I tried lots of things but can not managed. Im attaching my code, perhaps someone can help me. Ill be very glad if someone helps...thanks..

[attachment deleted by admin]

Re:changing idt

Posted: Tue Jul 29, 2003 10:24 am
by Pype.Clicker
according to your getDS() function and PBOOT.ASM,

Code: Select all

 idtr.base = ((dword)GetDS())<<4;
  idtr.base += (word)&idt;
should be replaced by

Code: Select all

idtr.base=&idt;

Re:changing idt

Posted: Tue Jul 29, 2003 11:10 am
by Amet
I have tried it before, but it still not worked. Is it true the way Im taking the address of the isr_wrapper function? And is it necessary for isr function to be written in asm? I mean, why cant I use a c function for isr_wrapper? Most of the codes I examine writes a asm function and then calls c functions.. By the way, the code still not works.. :-\

Re:changing idt

Posted: Tue Jul 29, 2003 11:31 am
by Pype.Clicker
the asm wrapper (also called a STUB) *is* mandatory because interrupt calling conventions and C calling convention do not match! for instance, an interrupt handler must save and restore *every* register, while a C function don't save the content of registers that are used to return values like eax and edx.

Moreover, a C function is ended by "RET" while an interrupt ends with "IRET". Moreover, the automatically-generated prologue code for C function isn't compatible with "asm("iretd") ... so, you have no choice but using an ASM wrapper ...

Re:changing idt

Posted: Tue Jul 29, 2003 11:35 am
by Pype.Clicker
btw, could you give us the exact error message you get from BOCHS ?
and if you have the internal bochs debugger built in, i recommend you to enable the call trace so that you can see what exactly is happening ...
(i.e. which instruction causes the problem, and possibly why ...)

Re:changing idt

Posted: Tue Jul 29, 2003 1:39 pm
by Amet
Ok Pype,
Here is what bochs says:

Code: Select all

00002580000p[CPU  ] >>PANIC<< exception(): 3rd (13) exception with no resolution
00002580000i[SYS  ] Last time is 1059507118
00002580000i[CPU  ] protected mode
00002580000i[CPU  ] CS.d_b = 32 bit
00002580000i[CPU  ] SS.d_b = 32 bit
00002580000i[CPU  ] | EAX=000000ff  EBX=00001000  ECX=00160001  EDX=000000a1
00002580000i[CPU  ] | ESP=0000fff0  EBP=0000fffb  ESI=00007c20  EDI=00000517
00002580000i[CPU  ] | IOPL=0 NV UP EI PL NZ NA PE NC
00002580000i[CPU  ] | SEG selector     base    limit G D
00002580000i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00002580000i[CPU  ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00002580000i[CPU  ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00002580000i[CPU  ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00002580000i[CPU  ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00002580000i[CPU  ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00002580000i[CPU  ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00002580000i[CPU  ] | EIP=000010e6 (000010e6)
00002580000i[CPU  ] | CR0=0x60000011 CR1=0x00000000 CR2=0x00000000
00002580000i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00002580000i[CPU  ] >> eb
00002580000i[CPU  ] >> fe
00002580000i[CPU  ] >> : jmp 000011e6
00002580000i[CTRL ] quit_sim called with exit code 1
Let me state my situation. As you advice I changed my code as this:

Code: Select all

   for(Cntr=0; Cntr < 250; Cntr++)
      SetIDTEntry(&idt[Cntr], 0x08, (word)&IsrWrapper, ACS_INT);

   idtr.base = (dword)&idt;
   idtr.limit = sizeof(idt)-1;
   lidt (&idtr);

   InitPIC(0x20, 0x28);

   enable();
   EnableIRQ(1); //keyboard

   for(;;);
Now, the bochs works fine until a key is pressed. Whenever I pressed a key bochs gives error as above. I think the isr_wrapper address is wrong.

And everyone suggests I want to use bochs debugger but dont know how to use it. How can I enable call trace? I execute bochsdbg.exe and then press c.

Re:changing idt

Posted: Tue Jul 29, 2003 2:17 pm
by Pype.Clicker
i suggest you to try "help" instead of "c".
the trace feature can be enabled with trace-on and disabled with trace-off
i also recommend the use of "dump_cpu" just after setting the IDT to check it was loaded properly.