Page 1 of 2

ISR not catching divide by 0 error*FIXED*

Posted: Sun Jul 12, 2009 8:37 pm
by brentS
For my kernel I am at currently testing the Interrupt Service Routines but whenever I divide by 0 the machine resets instead of being caught by isr0. Here is the important snippets of my code. The idt_install is called in my main D method.

Code: Select all

void idt_install()
{
	idtp.limit = (8 * 256) - 1;
	idtp.base = cast(uint)&idt;
	memorySet(&idt,0,8 * 256);

	isrs_install();	

	idtFlush(cast(uint)&idtp);		

	console_print("idt installed");
}

Code: Select all

void isrs_install()
{
	idt_setGate(0,cast(ulong)&isr0, 0x08, 0x8E);
/*	idt_setGate(1,cast(ulong)&isr1, 0x08, 0x8E);
	idt_setGate(2,cast(ulong)&isr2, 0x08, 0x8E);
	idt_setGate(3,cast(ulong)&isr3, 0x08, 0x8E);
	idt_setGate(4,cast(ulong)&isr4, 0x08, 0x8E);
	idt_setGate(5,cast(ulong)&isr5, 0x08, 0x8E);
	idt_setGate(6,cast(ulong)&isr6, 0x08, 0x8E);
	idt_setGate(7,cast(ulong)&isr7, 0x08, 0x8E);

	idt_setGate(8,cast(uint)&isr8, 0x08, 0x8E);
	idt_setGate(9,cast(uint)&isr9, 0x08, 0x8E);
	idt_setGate(10,cast(uint)&isr10, 0x08, 0x8E);
	idt_setGate(11,cast(uint)&isr11, 0x08, 0x8E);
	idt_setGate(12,cast(uint)&isr12, 0x08, 0x8E);
	idt_setGate(13,cast(uint)&isr13, 0x08, 0x8E);
	idt_setGate(14,cast(uint)&isr14, 0x08, 0x8E);
	idt_setGate(15,cast(uint)&isr15, 0x08, 0x8E);

	idt_setGate(16,cast(uint)&isr16, 0x08, 0x8E);
	idt_setGate(17,cast(uint)&isr17, 0x08, 0x8E);
	idt_setGate(18,cast(uint)&isr18, 0x08, 0x8E);
	idt_setGate(19,cast(uint)&isr19, 0x08, 0x8E);
	idt_setGate(20,cast(uint)&isr20, 0x08, 0x8E);
	idt_setGate(21,cast(uint)&isr21, 0x08, 0x8E);
	idt_setGate(22,cast(uint)&isr22, 0x08, 0x8E);
	idt_setGate(23,cast(uint)&isr23, 0x08, 0x8E);

	idt_setGate(24,cast(uint)&isr24, 0x08, 0x8E);
	idt_setGate(25,cast(uint)&isr25, 0x08, 0x8E);
	idt_setGate(26,cast(uint)&isr26, 0x08, 0x8E);
	idt_setGate(27,cast(uint)&isr27, 0x08, 0x8E);
    	idt_setGate(28,cast(uint)&isr28, 0x08, 0x8E);
	idt_setGate(29,cast(uint)&isr29, 0x08, 0x8E);
	idt_setGate(30,cast(uint)&isr30, 0x08, 0x8E);
	idt_setGate(31,cast(uint)&isr31, 0x08, 0x8E);
*/
	console_print("isrs installed");
}

Code: Select all

void isr0()
{
	console_print("irs0 called");
	asm
	{
    		cli;
    		push 0;
		push 0;
	}
    	
	isr_common();
}

Code: Select all

isr_common:
   pusha  

   mov ax, ds              
   push eax                 

   mov ax, 0x10  
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   call faultHandler

   pop eax   
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   popa                   
   add esp, 8 
   sti
   iret     

Code: Select all

extern(C) void faultHandler(registers r)
{
    //if ((*r).int_no < 32)
    //{
        console_print(exception_messages[r.int_no]);
        console_print(" Exception. System Halted!");
        while(true){}
    //}
}
I have been looking at this issue for several days and have no clue what the problem may be. Bochs is saying this "00085352371e[CPU ] interrupt(): vector must be within IDT table limits, IDT.limit = 0x0" but I could find no info on the message.

Re: ISR not catching divide by 0 error

Posted: Sun Jul 12, 2009 8:56 pm
by frank
Is your IDT pointer structure packed correctly? Try adding __attribute__ ((packed)) to your structure.

Re: ISR not catching divide by 0 error

Posted: Sun Jul 12, 2009 9:00 pm
by brentS
Since I am using D align(1) is the equivalent. Here are my structs

Code: Select all

align(1)struct idt_entry
{
	ushort base_lo;
	ushort sel;
	ubyte always0;      
	ubyte flags;
	ushort base_hi;
}

align(1)struct idt_ptr
{
    ushort limit;
    uint base;
}

Re: ISR not catching divide by 0 error

Posted: Sun Jul 12, 2009 9:08 pm
by Gman
I had a problem like this too. I don't know much about D, but make sure you're calling idt_install() from your main() function (again, I don't know any D). I forgot to do that, and got the same problem.

Re: ISR not catching divide by 0 error

Posted: Sun Jul 12, 2009 9:15 pm
by brentS
[-X lol but could it possibly be a problem with my gdt ... or is that a whole separate realm.

Re: ISR not catching divide by 0 error

Posted: Sun Jul 12, 2009 9:24 pm
by Brendan
Hi,
brentS wrote:[-X lol but could it possibly be a problem with my gdt ... or is that a whole separate realm.
If Bochs says that your IDT limit is zero, then I'd guess that your IDT limit is zero. Maybe the IDT base is also zero, maybe it's being overwritten, and maybe you forgot to do "lidt"...


Cheers,

Brendan

Re: ISR not catching divide by 0 error

Posted: Sun Jul 12, 2009 9:42 pm
by brentS
I definately am calling lidt.

Code: Select all

idtFlush(cast(uint)&idtp);

Code: Select all

idtFlush:
	mov eax, [esp+4]
	lidt [eax]
	ret
*This code you can say was grabbed from here http://www.jamesmolloy.co.uk/tutorial_h ... 20IDT.html*

Nothing is being written after I install the IDT except some keyboard tests but that should not matter. What would the limit and base being 0 mean? that it sees my table as 0 of size?

Re: ISR not catching divide by 0 error

Posted: Mon Jul 13, 2009 7:59 am
by Zenith
I'm wondering... can you verify using the Bochs debugger whether anything is actually being written to the IDT location? Also, is it right for us to presume that idt is idt_entry[256] idt?

Try replacing the call to idtFlush with some D inline ASM and see what happens:

Code: Select all

// Should work in GDC/LDC
auto ptr_idtp = &idtp;
asm {
	lidt ptr_idtp;
	sti;
}

Re: ISR not catching divide by 0 error

Posted: Mon Jul 13, 2009 8:22 am
by yemista
Are you using a virtual offset for your kernel? idt may be linked with a physical address that you are supplying for lidt, but maybe it should be at a virtual address

Re: ISR not catching divide by 0 error

Posted: Fri Jul 17, 2009 11:25 am
by brentS
Zenith I tried that and still not luck unfortunately. Yemista I am still new to kernel development so I do not understand exactely how to look for that. This is my linker script if it helps.

Code: Select all

ENTRY(load)
SECTIONS
{
  .text 0x100000 :
  {
    code = .; _code = .; __code = .;
    *(.text)
    . = ALIGN(4096);
  }

  .data :
  {
     data = .; _data = .; __data = .;
     *(.data)
     *(.rodata)
     . = ALIGN(4096);
  }

  .bss :
  {
    bss = .; _bss = .; __bss = .;
    *(.bss)
    . = ALIGN(4096);
  }

  end = .; _end = .; __end = .;
} 

Re: ISR not catching divide by 0 error

Posted: Fri Jul 17, 2009 11:59 am
by Troy Martin
Nope, that's pretty much my linker script, so it should be in working order :)

Could you pastebin or slexy your main() function? I'd like to take a look at that.

Re: ISR not catching divide by 0 error

Posted: Fri Jul 17, 2009 12:07 pm
by raghuk
Do you have a higher half kernel? Do you load it at a virtual offset 0xc0100000 or something? If you run objdump -d <kernel binary> and look for lidt what address is it trying to load? It should be the linear address of idtp.

Re: ISR not catching divide by 0 error

Posted: Fri Jul 17, 2009 1:31 pm
by brentS
The addresses match but there is one thing is just wondered. In my makefile I use

Code: Select all

@cat $(BOCHSDIR)stage1 $(BOCHSDIR)stage2 $(BOCHSDIR)pad $(BINDIR)kernel.bin > $(BOCHSDIR)kernel.img
to run it in bochs. Would this affect anything?

My main

Code: Select all

extern(C) void main(uint magic, uint addr)
{
	
	console_setAttributes(ConsoleColors.BLUE,ConsoleColors.GREEN);
	console_clear();
	console_print("\t\t\t\t\t\t\tWelcome to the Kernel\n");
	gdt_install();
	idt_install();
	//isrs_install();
		
	int c=0;
	console_print("before /0 \n");	
	int b= 1/c;
	console_print("after /0 \n");
}

Re: ISR not catching divide by 0 error

Posted: Sat Jul 18, 2009 6:58 am
by brentS
I am officially being driven crazy over this issue. I now have new bochs output that might help the cause.

Code: Select all

interrupt(): gate descriptor is not valid sys seg (vector=0x00)

Re: ISR not catching divide by 0 error

Posted: Sat Jul 18, 2009 2:32 pm
by Creature
I'm not sure you're supposed to be defining the 'ISR0' function in D. As JamesM says in his tutorials, you should be defining them in Assembly, then passing the address of the assembly function as IDT function address.

For example, ISR0 should be something like this:

Code: Select all

[GLOBAL ISR0]

ISR0:
   cli ; Disable interrupts, your IsrHandler should iret to turn them on again.

   push byte 0 ; Push the number of this interrupt (in this case, 0 indicating a division-by-zero-exception).
   jmp YourIsrHandlerThatPossiblyCallsFaultHandler ; Go to your ISR handler that pops and pushes some things and calls 'FaultHandler'.
So it works like this:

You do

Code: Select all

SetIDTGate(0, cast(ulong) &ISR0, 0x08, 0x8E);
Where 'ISR0' is a function defined in assembly, like the one above. This function does what the above code does, moves to the ISR handler (isr_common for example), this function pushes and pops some things, calls your 'faultHandler', which can call a specific function based on what interrupts number was sent (like call a function called "DivideByZeroExc(registers r)" when the interrupt number for the ISR is 0). When you return from your faultHandler, assembly will pop some things off the stack and do some more things to finally 'iret', turning interrupts on again.