(Solved...mostly) Divide by Zero Exception during hlt loop

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
Cyber
Posts: 10
Joined: Wed Jun 22, 2016 8:58 pm
Libera.chat IRC: cyber_

(Solved...mostly) Divide by Zero Exception during hlt loop

Post by Cyber »

I have been working on my OS using resources from osdev and bran's kernel tutorial and I was trying to enable the PIT interrupt for a simple timer. In my kernel I added

Code: Select all

	for(;;)
	{
		__asm__ ("hlt");
	}
so the main method didn't exit.
This all works fine except that it throws a divide by zero exception, as well as the timer handler not firing. The exception is thrown after the EOI is sent to the master (and slave if the irq was not irq 0-7)I have spent hours rereading the code and even ended up trying to flat out copy code to see if replacing a certain methods would fix everything. I have also been using inline asm instead of external methods if that makes too much of a difference.
Here's the code for the IRQ stub:

Code: Select all

void irq_common_stub()
{
	printf("An IRQ Somewhere just executed the stub.");
	__asm__ __volatile__ (
			"pusha;"
			"pushw %%ds;"
			"pushw %%es;"
			"pushw %%fs;"
			"pushw %%gs;"
			"movw $0x10, %%ax;"
			"movw %%ax, %%ds;"
			"movw %%ax, %%es;"
			"movw %%ax, %%fs;"
			"movw %%ax, %%gs;"
			"movl %%esp, %%eax;"
			"pushl %%eax;"
			"call irq_handler;"
			"popl %%eax;"
			"popw %%gs;"
			"popw %%fs;"
			"popw %%es;"
			"popw %%ds;"
			"popa;"
			"addl $8, %%esp;"
			"iret;"
			:
			:
			:"memory"
	);
}
Basically the code for all the irqs (and isrs but very very slight difference just with what gets called)

Code: Select all

void irq0()
{
	printf("irq0 activated\n"); //temporary debug text
	__asm__ __volatile__ (
			"cli;"
			"pushl $0;"
			"pushl $32;"
			"call irq_common_stub"
			: : :"memory"
	);
}
fault&irq handlers code I just ended up copying over to see if it made any difference

Code: Select all

void fault_handler(struct regs *r)
{
	//printf("fault handler activated");
    /* Is this a fault whose number is from 0 to 31? */
    if (r->int_no < 32)
    {
        /* Display the description for the Exception that occurred.
        *  In this tutorial, we will simply halt the system using an
        *  infinite loop */
        printf(exception_messages[r->int_no]);
        printf(" Exception.  System halted.");
        for (;;);
    }
    else
    {
    	irq_handler(r);
    }
}

void irq_handler(struct regs *r)
{
	int i = r->int_no;
	if(i > 31)
	{
		printf("An IRQ Somewhere just activated the handler.\n");
		/* This is a blank function pointer */
		puts(" - handler: created blank pointer");
		void (*handler)(struct regs *r);
		puts(" - done");
		/* Find out if we have a custom handler to run for this
		*  IRQ, and then finally, run it */
		puts(" - handler: get IRQ routine.");
		handler = irq_routines[i + 32];
		puts(" - done");

		if (handler)
		{
			puts(" - handler: activating the handler...");
			handler(r);
			puts(" - done");
		}

		/* If the IDT entry that was invoked was greater than 40
		*  (meaning IRQ8 - 15), then we need to send an EOI to
		*  the slave controller */
		if (i >= 40)
		{
			puts(" - handler: sending to slave...");
			outportb(0xA0, 0x20);
			puts(" - done");
		}

		/* In either case, we need to send an EOI to the master
		*  interrupt controller too */
		puts(" - handler: sending to master...");
		outportb(0x20, 0x20);
		puts(" - done");
	}
}
If you need to see any other parts of the source just ask and I'll add them, thank you for your time.
Last edited by Cyber on Thu Jun 23, 2016 6:52 pm, edited 1 time in total.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: Divide by Zero Exception during hlt loop

Post by Octocontrabass »

In order to use C in an IRQ handler, you must have a wrapper written in bare assembly to save the CPU state so the code generated by the C compiler won't destroy the CPU state and make it impossible to return.

You've wrapped that assembly in C, which means the C compiler is generating code that destroys the CPU state and makes it impossible to return.
Cyber
Posts: 10
Joined: Wed Jun 22, 2016 8:58 pm
Libera.chat IRC: cyber_

Re: Divide by Zero Exception during hlt loop

Post by Cyber »

Thanks for the suggestion i'll try it today. Do i just need to do it for irqs (since the isrs halt the system and dont need to return) or both or what i would assume just do both anyway
User avatar
michaellangford
Posts: 21
Joined: Tue Jun 21, 2016 6:41 am
Libera.chat IRC: quad4

Re: Divide by Zero Exception during hlt loop

Post by michaellangford »

Definitely do a wrapper for both isrs and irqs. If you don't it gets very compiler specific, and you as the programmer are not in control of what is going on inside.
"Out of memory: Please memorize the following numbers and type them back in when asked for page number 42". - linguofreak

"Quote me in your forum signature" - Sortie (Check!)
Cyber
Posts: 10
Joined: Wed Jun 22, 2016 8:58 pm
Libera.chat IRC: cyber_

Re: Divide by Zero Exception during hlt loop

Post by Cyber »

I did what was done in bran's tutorials and put all the asm code in asm files instead of inline. Now I face the problem that when an IRQ fires, a page fault exception occurs. I have narrowed it down all the way to the iret call, and I believe the problem is like before: that it can't return to the state it was in before. I can't figure out what is causing this since it is all written in bare assembly like it should be now.

Code: Select all

.global isr0
#******OTHERS ARE HERE******#
.global isr31

.type isr0, @function
isr0:
	cli
	push $0
	push $0
	jmp isr_common_stub

#******OTHERS ARE HERE******#

.type isr31, @function
isr31:
	cli
	push $0
	push $31
	jmp isr_common_stub

#extern fault_handler

isr_common_stub:
	pusha
	push %ds
	push %es
	push %fs
	push %gs
	movw $0x10, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movl %esp, %eax
	push %eax
	call fault_handler
	pop %eax
	pop %gs
	pop %fs
	pop %es
	pop %ds
	popa
	add $8, %esp
	iret

.global irq0
#******OTHERS ARE HERE******#
.global irq15

.type irq0, @function
irq0:
	cli
	push $0
	push $32
	jmp irq_common_stub

#******OTHERS ARE HERE******#

.type irq15, @function
irq15:
	cli
	push $0
	push $47
	jmp irq_common_stub

irq_common_stub:
	pusha
	push %ds
	push %es
	push %fs
	push %gs
	movw $0x10, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movl %esp, %eax
	push %eax
	call irq_handler
	pop %eax
	pop %gs
	pop %fs
	pop %es
	pop %ds
	popa
	add $8, %esp
	call debug_donehandling
	iret
C code:

Code: Select all

void fault_handler(struct regs *r)
{
	//printf("fault handler activated");
    /* Is this a fault whose number is from 0 to 31? */
    if (r->int_no < 32)
    {
        /* Display the description for the Exception that occurred.
        *  In this tutorial, we will simply halt the system using an
        *  infinite loop */
        printf(exception_messages[r->int_no]);
        printf(" Exception.  System halted.");
        for (;;);
    }
    else
    {
    	irq_handler(r);
    }
}

void irq_handler(struct regs *r)
{
	if(r->int_no == 32)
	{
		printf("-h: timer!\n");
	}
    /* This is a blank function pointer */
    void (*handler)(struct regs *r);

    /* Find out if we have a custom handler to run for this
    *  IRQ, and then finally, run it */
    handler = irq_routines[r->int_no - 32];
    if (handler)
    {
    	printf("-h: handler!\n");
        handler(r);
    }

    /* If the IDT entry that was invoked was greater than 40
    *  (meaning IRQ8 - 15), then we need to send an EOI to
    *  the slave controller */
    if (r->int_no >= 40)
    {
    	printf("-h: EOI Slave!\n");
        outportb(0xA0, 0x20);
    }

    /* In either case, we need to send an EOI to the master
    *  interrupt controller too */
    printf("-h: EOI Master!\n");
    outportb(0x20, 0x20);
}
EDIT: Removed repetitive code to save space
Cyber
Posts: 10
Joined: Wed Jun 22, 2016 8:58 pm
Libera.chat IRC: cyber_

Re: Divide by Zero Exception during hlt loop

Post by Cyber »

Here i'll just make a new thread since it isn't related too much to the original topic anymore since it's an entirely different exception for an entirely different reason.
Post Reply