Incorrect Stack on IRET in IRQ0 Handler

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
User avatar
jon002
Posts: 2
Joined: Tue Aug 09, 2016 7:53 pm
Libera.chat IRC: Jon002

Incorrect Stack on IRET in IRQ0 Handler

Post by jon002 »

So I am currently trying to re-enable interrupts in 32-bit mode, and I have run into a weird error that should be easily fixed.

I have currently set up my GDT and IDT in 32-bit mode, mapped IRQs 0-15 to IVT entries 32-47, and enabled both the 8259A PIC and 8253 PIT, enabling interrupts with "sti" afterwards.

However, upon the PIT firing IRQ0, the OS generates a General Protection Fault (IR 13). I have been debugging with both GDB and Bochs and I believe the issue is related to an incorrect stack, which should be easily solvable. When an IRQ that does not generate an error code is fired (such as IRQ0) EFLAGS, CS, then EIP is pushed to the stack. If an error code is fired, EFLAGS, CS, EIP, and the 32-bit error code is pushed.

In C, I have been using the following method to update ESP and to read the values from the stack before calling IRET:

Code: Select all

asm("addl $12, %esp);

// ... Handle interrupt here

int eip;
int cs;
int eflags;

asm("movl (%%esp), %0" : "=r"(eip));
asm("movl 4(%%esp), %0" : "=r"(cs));
asm("movl 8(%%esp), %0" : "=r"(eflags));

// ... Print integers here

asm("iretl");
(If an error code is generated, I also get that with movl 16(%%esp)).

I have checked the stack with bochs debugger (I can put a "for (;;) { asm("hlt"); } to halt the system) and I have found that it is not set up correctly.

Because I am still in Ring 0, the processor should use the current stack. But I have found 0x00000008 (my CS value, or at least what I think it is) to be offset 20-42 bytes from ESP instead of 4 bytes when handling an interrupt, and the location of different values in the stack also change frequently. I have looked through my code, and I am unable to figure out why in the world this is happening. It happens in QEMU, Bochs, and VirtualBox.

My GDT is set up correctly (Triple-checked it). IDT is also set up correctly and IRQs 0-15 are correctly mapped to 32-47 IRs. PIT and PIC are initialized correctly. Assembly code should be great for what I want it to do. I have researched the stack, even widely switch the values (from "movl 4(%%esp)" to "movl -4(%%esp)"), or adjusted ESP, but nothing seems to work. I have googled all over this site and the internet (looked as OSDev.org, BrokenThorn.com, even articles from .edu sites) but I cannot make heads or tails out of the problem. If there's a problem with the code, or it's clear for some reason that I don't fully understand the stack, please let me know. Any help possible would be greatly appreciated!

My source code can be found on GitHub here: https://github.com/jaller200/DarkOS. Thanks in advance for any guidance or help!
"What light is to the eyes - what air is to lungs - what love is to the heart - liberty is to the soul of man" ~Robert Ingersoll
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Incorrect Stack on IRET in IRQ0 Handler

Post by BrightLight »

Very common mistake: the IRQ handler wrapper/dispatcher (whatever you want to call it) must be written in assembly.
Something like this, for example (Intel syntax, I can't do much in gas):

Code: Select all

irq0_dispatcher:
	pusha
	extern irq_c_handler
	call irq0_c_handler    ; your code written in C
	popa
	iret
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
jon002
Posts: 2
Joined: Tue Aug 09, 2016 7:53 pm
Libera.chat IRC: Jon002

Re: Incorrect Stack on IRET in IRQ0 Handler

Post by jon002 »

omarrx024 wrote:Very common mistake: the IRQ handler wrapper/dispatcher (whatever you want to call it) must be written in assembly.
Something like this, for example (Intel syntax, I can't do much in gas):

Code: Select all

irq0_dispatcher:
	pusha
	extern irq_c_handler
	call irq0_c_handler    ; your code written in C
	popa
	iret
Thanks so much! IRQs are working perfectly now. Rookie mistake - won't happen again.

Also, after you told me that and I fixed the problem, I found this as I knew what I was looking for: http://wiki.osdev.org/Interrupt_Service_Routines. #-o
"What light is to the eyes - what air is to lungs - what love is to the heart - liberty is to the soul of man" ~Robert Ingersoll
Post Reply