problem in demo 8

If you are new to OS Development, plan on spending some time here first before going into the other forums.

Moderator:Moderators

Post Reply
Matrix7
Posts:8
Joined:Sat Apr 25, 2009 6:11 pm
problem in demo 8

Post by Matrix7 » Wed Jul 08, 2009 3:28 am

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.

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: problem in demo 8

Post by Andyhhp » Thu Jul 09, 2009 8:24 am

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
Image

Matrix7
Posts:8
Joined:Sat Apr 25, 2009 6:11 pm

Re: problem in demo 8

Post by Matrix7 » Thu Jul 09, 2009 9:18 am

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
}

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: problem in demo 8

Post by Andyhhp » Thu Jul 09, 2009 3:27 pm

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
Image

Matrix7
Posts:8
Joined:Sat Apr 25, 2009 6:11 pm

Re: problem in demo 8

Post by Matrix7 » Fri Jul 10, 2009 4:19 pm

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!

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: problem in demo 8

Post by Andyhhp » Fri Jul 10, 2009 4:40 pm

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
Image

Matrix7
Posts:8
Joined:Sat Apr 25, 2009 6:11 pm

Re: problem in demo 8

Post by Matrix7 » Sat Jul 11, 2009 3:15 pm

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!

pswin
Posts:15
Joined:Mon Jun 22, 2009 5:33 pm

Re: problem in demo 8

Post by pswin » Sat Jul 25, 2009 7:00 am

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
	}
}

pswin
Posts:15
Joined:Mon Jun 22, 2009 5:33 pm

Re: problem in demo 8

Post by pswin » Sat Jul 25, 2009 7:23 am

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?

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: problem in demo 8

Post by Mike » Sat Jul 25, 2009 7:53 pm

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.)
Lead Programmer for BrokenThorn Entertainment, Co.
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: problem in demo 8

Post by Andyhhp » Sat Jul 25, 2009 7:55 pm

__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
Image

pswin
Posts:15
Joined:Mon Jun 22, 2009 5:33 pm

Re: problem in demo 8

Post by pswin » Wed Aug 05, 2009 4:18 pm

Andyhhp:
thanks, how can i resolve this problem

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: problem in demo 8

Post by Andyhhp » Thu Aug 06, 2009 1:40 pm

how can i resolve this problem
I dont understand what you mean? I thought you said you already solved the problem.

~Andrew
Image

pswin
Posts:15
Joined:Mon Jun 22, 2009 5:33 pm

Re: problem in demo 8

Post by pswin » Thu Aug 06, 2009 2:57 pm

A side effect of this is that you can't have any local variables in a naked function.
how can i solve it?

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: problem in demo 8

Post by Andyhhp » Thu Aug 06, 2009 6:04 pm

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
Image

Post Reply