Page 1 of 1
problem in demo 8
Posted: Wed Jul 08, 2009 3:28 am
by Matrix7
After enabling interrupt, it will generate General Protection Fault when we using for(;;){}
I think the stack is damaged and the #GP is generated after i86_pit_irq() is called.
The ebp is changed after i86_pit_irq() is called.
But i don't know why it changes.
Re: problem in demo 8
Posted: Thu Jul 09, 2009 8:24 am
by Andyhhp
What code are you using for your i86_pit_irq() function?
In almost all normal functions used as irq handlers, C/C++ doesnt deal properly with the stack pointer because the order of the stack for Interrupts.
~Andrew
Re: problem in demo 8
Posted: Thu Jul 09, 2009 9:18 am
by Matrix7
Andyhhp wrote:What code are you using for your i86_pit_irq() function?
In almost all normal functions used as irq handlers, C/C++ doesnt deal properly with the stack pointer because the order of the stack for Interrupts.
~Andrew
void _cdecl i86_pit_irq () {
_asm add esp, 12
_asm pushad
//! increment tick count
_pit_ticks++;
//! tell hal we are done
interruptdone(0);
_asm popad
_asm iretd
}
Re: problem in demo 8
Posted: Thu Jul 09, 2009 3:27 pm
by Andyhhp
Ahh
That would explain the problem.
Code: Select all
void _cdecl i86_pit_irq () {
_asm add esp, 12
_asm pushad
//! increment tick count
_pit_ticks++;
//! tell hal we are done
interruptdone(0);
_asm popad
_asm iretd
}
In that definition, i86_pit_irq is a standard fuction that deals with its own stack pointer.
You then add 3 dwords to it and then push all the registers onto the stack.
Then increment _pit_ticks which is ok to do as it is not a local variable.
Then call interruptdone() which I assume sends the IRQ complete message to the PIC.
Then you popad, which undoes the pushad which is correct.
However, you then iretd which takes the next dword off the stack (amongst other things) and tries returning from the exception. At this point, the dword in question is the top one of the 3 that you added to esp - in other words, whatever junk was left on the stack from before. Upon doing this, a General Protection Fault occurs because it is more than likely that you are now executing junk elsewhere in memory.
Even if you sort that problem by removing the initial add esp, 12 the handler still wouldnt work because internally, the function is setting up its own frame pointer which is still set up at the point at which you call iretd.
I suggest you read this post which was my solution to the problem in a neat way. Be aware that the bit about name mangling is specific for C++ but the concepts apply to C as well
http://www.brokenthorn.com/forums/viewt ... f=12&t=131
Hope it helps,
~Andrew
Re: problem in demo 8
Posted: Fri Jul 10, 2009 4:19 pm
by Matrix7
I found that i86_pit_irq() pushed 4 dword when it is called!
If I replaced "_asm add esp, 12" with "_asm add esp, 16", the #GP is not generated!
But the DebugPuts works wrong, it only display first line!
And I want to know when it generate "invalid op code"!
Thanks!
Re: problem in demo 8
Posted: Fri Jul 10, 2009 4:40 pm
by Andyhhp
You can get functions to work like that for interrupts.
However - there are several major problems with doing it like that:
1) you dont have direct access to information passed by the exception.
2) some exceptions pass a different number of parameters depending on how they are called. for those 3, your handler will not successfully handle all of them without a #GF
3) as you develop your handler, the compiler will put more stuff on the stack, causing your current hack to stop working. Also, any compiler optimization might cause it to stop working as well.
I very much suggest you do a proper fix before continuing any further.
~Andrew
Re: problem in demo 8
Posted: Sat Jul 11, 2009 3:15 pm
by Matrix7
The problem is solved!
I modified the code to
Code: Select all
void _declspec (naked) i86_pit_irq () {
_asm pushad
//! increment tick count
_pit_ticks++;
//! tell hal we are done
interruptdone(0);
_asm popad
_asm iretd
}
And all works well currently!
Thanks very much!
Re: problem in demo 8
Posted: Sat Jul 25, 2009 7:00 am
by pswin
my soulition for pic and pit interrupts:
Code: Select all
void _cdecl pit_irq ()
{
_asm add esp, 16
_asm pushad
//! increment tick count
g_uPitTicks++;
//! tell hal we are done
ahalInterruptDone(0);
_asm popad
_asm iretd
}
and for software interrupts:
Code: Select all
void vec34(void)
{
_asm add esp, 12
_asm pushad
printf("interrupt 34 executed\n");
__asm
{
popad
iretd
}
}
Re: problem in demo 8
Posted: Sat Jul 25, 2009 7:23 am
by pswin
Matrix7 wrote:The problem is solved!
I modified the code to
Code: Select all
void _declspec (naked) i86_pit_irq () {
_asm pushad
//! increment tick count
_pit_ticks++;
//! tell hal we are done
interruptdone(0);
_asm popad
_asm iretd
}
this is very good. how can i get extra information in this method?
what is "_declspec (naked)" do?
Re: problem in demo 8
Posted: Sat Jul 25, 2009 7:53 pm
by Mike
pswin wrote:what is "_declspec (naked)" do?
This removes prologue and eprologue code added by the compiler for normal functions. That is, in a normal function, the compiler adds code before and after that modifies the stack. Using _declspec (naked) removes this, so there is nothing that touches the stack (Thus we dont need to remove the bytes pushed on the stack anymore.)
Re: problem in demo 8
Posted: Sat Jul 25, 2009 7:55 pm
by Andyhhp
__declspec (naked) defines a fuction to have no prolog or epilog code.
When you define a function in C or C++, there is a bit of code that is silently added.
e.g.
Code: Select all
int myFunction(int a, int b)
{
return a + b;
}
Even for a basic function like this, a stack frame needs setting up. The prolog code does this. At the end of the function, the epilog code removes the stack frame.
The disassembly of the example function above is this:
Code: Select all
push ebp
mov ebp,esp
mov eax,[ebp+4]
add eax,[ebp+8]
leave
ret
In that case, the prolog code is the first push and mov and the epilog code is the leave and ret.
(leave is functionally identical to 'pop ebp' to restore to the previous frame pointer but faster to execute immediatly before a ret instruction)
A naked function is one that has no prolog or epilog code.
A side effect of this is that you can't have any local variables in a naked function.
Hope this helps,
~Andrew
Re: problem in demo 8
Posted: Wed Aug 05, 2009 4:18 pm
by pswin
Andyhhp:
thanks, how can i resolve this problem
Re: problem in demo 8
Posted: Thu Aug 06, 2009 1:40 pm
by Andyhhp
how can i resolve this problem
I dont understand what you mean? I thought you said you already solved the problem.
~Andrew
Re: problem in demo 8
Posted: Thu Aug 06, 2009 2:57 pm
by pswin
A side effect of this is that you can't have any local variables in a naked function.
how can i solve it?
Re: problem in demo 8
Posted: Thu Aug 06, 2009 6:04 pm
by Andyhhp
You cant. There is no way you can use local variables in naked functions.
The reason you can have local variables in normal functions is because of the prolog and epilog code that the compiler inserts that sets up the stack frame. Without creating a stack frame, you cant index local variables.
There is a hack to get round the problem
Code: Select all
void real_irq()
{
//Local variables are fine in this function
//! increment tick count
_pit_ticks++;
//! tell hal we are done
interruptdone(0);
}
void _declspec (naked) i86_generic_irq () {
_asm push eax
real_irq();
_asm pop eax
_asm iretd
}
What this does is have a stub naked function that deals with the stack, that calles a non-naked function that actually handels the interrupt. Note that you now only have to push and pop eax as that is the only register that is not going to be preserved by the function call.
As i said - this is a hack but it does work, at the cost of an extra jump which is not ideal in an interrupt handler.
~Andrew