ISR Problem

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
lexter
Posts: 3
Joined: Sun Feb 24, 2008 4:58 pm

ISR Problem

Post 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?
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post 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.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Post by 01000101 »

Your code would indeed be helpful.

do you push all core registers before executing your ISR and then restore them after?
lexter
Posts: 3
Joined: Sun Feb 24, 2008 4:58 pm

Post by lexter »

Oh, yeps ... Sorry, I've forgotttten the code part ... :oops:

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
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post 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 :P
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
cyr1x
Member
Member
Posts: 207
Joined: Tue Aug 21, 2007 1:41 am
Location: Germany

Post 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.
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Post by 01000101 »

Also, I though when trying to avoid gcc-asm conflictions, shouldn't you use the __asm__ __volatile__ assignment?
senaus
Member
Member
Posts: 66
Joined: Sun Oct 22, 2006 5:31 am
Location: Oxford, UK
Contact:

Post 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.

Code: Select all

-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/M/MU d- s:- a--- C++++ UL P L++ E--- W+++ N+ w++ M- V+ PS+ Y+ PE- PGP t-- 5- X R- tv b DI-- D+ G e h! r++ y+
------END GEEK CODE BLOCK------
iammisc
Member
Member
Posts: 269
Joined: Thu Nov 09, 2006 6:23 pm

Post 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]
lexter
Posts: 3
Joined: Sun Feb 24, 2008 4:58 pm

Post 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!
Post Reply