problem in demo 8
Moderator:Moderators
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.
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
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
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
void _cdecl i86_pit_irq () {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
_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
Ahh
That would explain the problem.
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
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
}
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
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!
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
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
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
The problem is solved!
I modified the code to
And all works well currently!
Thanks very much!
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
}
Thanks very much!
Re: problem in demo 8
my soulition for pic and pit interrupts:
and for software 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
this is very good. how can i get extra information in this method?Matrix7 wrote:The problem is solved!
I modified the code toCode: 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 }
what is "_declspec (naked)" do?
Re: problem in demo 8
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.)pswin wrote:what is "_declspec (naked)" do?
Lead Programmer for BrokenThorn Entertainment, Co.
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com
Re: problem in demo 8
__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.
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:
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
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;
}
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
(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
Andyhhp:
thanks, how can i resolve this problem
thanks, how can i resolve this problem
Re: problem in demo 8
I dont understand what you mean? I thought you said you already solved the problem.how can i resolve this problem
~Andrew

Re: problem in demo 8
how can i solve it?A side effect of this is that you can't have any local variables in a naked function.
Re: problem in demo 8
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
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
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
}
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
