TO me the problem was kind of obvious.
It is failing with the iret immediately because gcc pushed the old ebp value to the stack.
It fails without the iret because slowly by slowly, you're stack pointer keeps on decreasing, overwrites something else and finally either comes a an unmapped region(if you're using paging) or overwrites your code with garbage which then gives you some sort of error.
The solution is to scrap the inline assembly and use pure assembly to enter and exit the interrupt.
For example a good way to do irqs is the following
Code: Select all
irq_handler_stub:
pusha
push %ds
push %es
push %fs
push %gs
push %ss
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
mov %esp, %eax
push %eax
call <any-function>
pop %eax
pop %ss
pop %gs
pop %fs
pop %es
pop %ds
popa
iret
Note that the above code pushes a structure onto the stack that you can either ignore or use as the first argument to your function.
The structure is as follows:
Code: Select all
typedef struct regs_t
{
unsigned int r_ss, gs, fs, es, ds; /* pushed the segs last */
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */
unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */
unsigned int eip, cs, eflags, useresp, ss; /* pushed by the processor automatically */
unsigned int vm_es, vm_ds, vm_fs, vm_gs;
} regs;
The vm_* fields are used in vm8086 mode and refer to the segment selectors pushed by the processor in that mode. These fields are invalid in any other mode. Also, the useresp and ss fields are invalid in interrupts received in kernel mode.
Hope that helps.[/code][/i]