Page 1 of 1
ISR Problem
Posted: Sun Feb 24, 2008 6:42 pm
by lexter
Hi!
I have a problem with my ISR code. I'm trying to write a simple code for TIMER interrupt, which will just put "T" on the screen (for testing).
However, it does put some number of "T"'s then couple of other symbols and then resets bochs, if I avoid using "iret" instruction
when I use IRET is simply resets bochs after putting one "T".
what could be the reason for that?
Posted: Sun Feb 24, 2008 8:18 pm
by neon
It sounds like something is wrong with your code (I dont think your timer, though.) Its hard to tell without code...
When Bochs resets (triple faults), can you also post the log output from Bochs?
Also the code for your interrupt routine might be helpful.
Posted: Sun Feb 24, 2008 8:29 pm
by 01000101
Your code would indeed be helpful.
do you push all core registers before executing your ISR and then restore them after?
Posted: Mon Feb 25, 2008 4:36 am
by lexter
Oh, yeps ... Sorry, I've forgotttten the code part ...
Code: Select all
#define PIC1 0x20
#define PIC2 0xA0
#define PIC_EOI 0x20
inline void irq_timer(void){
asm ("pusha");
asm ("mov %ds, %ax");
asm ("push %eax");
asm ("mov $0x8, %ax");
asm ("mov %ax, %ds");
asm ("mov %ax, %fs");
asm ("mov %ax, %gs");
puts ("T");
//outportb (PIC1, PIC_EOI);
asm ("pop %eax");
asm ("mov %ax, %ds");
asm ("mov %ax, %es");
asm ("mov %ax, %fs");
asm ("mov %ax, %gs");
asm ("popa");
asm ("add $0x8, %esp");
asm ("sti");
asm ("iret");
}
The bochs log:
http://users.evtek.fi/~aleksanc/osdev/bochsout.txt
Also the rest of the src files ... just in case:
http://users.evtek.fi/~aleksanc/osdev/src/
In case this is relevant, my dev-environment is:
Win Vista (
)
Bochs x86 Emulator 2.3.6
GCC (4.2.2) [DJGPP]:
gcc -v output:
Code: Select all
Configured with: /v203/gcc-4.22/configure djgpp --prefix=/dev/env/DJDIR --disable-nls --disable-werror --enable-languages=c,c++,fortran,objc,obj-c++,ada
Thread model: single
gcc version 4.2.2
GNU ld version 2.17
Posted: Mon Feb 25, 2008 11:53 am
by Combuster
Using inline assembly that way is bound to fail.
My first guess is that GCC gave you a push ebp; mov ebp, esp for free
Posted: Mon Feb 25, 2008 1:47 pm
by cyr1x
I don't know how you organize your GDT but are you sure that your data selector is 0x08? Usually it is 0x10. And why do you save ds,.. and then load some other values? int(i.e. when the cpu calls an ISR)/iret does that for you.
Posted: Mon Feb 25, 2008 2:40 pm
by 01000101
Also, I though when trying to avoid gcc-asm conflictions, shouldn't you use the __asm__ __volatile__ assignment?
Posted: Mon Feb 25, 2008 2:50 pm
by senaus
Also, why do sti before iret? iret will pop eflags from the stack anyway (hence returning the IF flag to its pre-interrupt value), so this is redundant and a little dangerous (you're going to get nested interrupts).
Oh, and according to your bochsout.txt, you are in real mode. Do segment selectors even apply here? I'm sure segments are a part of the actual address in real mode.
Posted: Mon Feb 25, 2008 9:01 pm
by iammisc
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]
Posted: Wed Feb 27, 2008 8:53 am
by lexter
Thanx for your help!
The problem was really obvious ... the inline assembly in gcc is not the very best friend of low-level programmer.
So, now I've created separate wrappers in .asm file, which call handling routines in handlers.c file. Everything works perfectly!
Thanx again!