Page 1 of 1
GPF When three or more threads running
Posted: Mon Aug 29, 2011 9:06 pm
by Nessphoro
Hey guys, perhaps anybody has experienced this problem before,
When I create three threads, the first one executed okay, so does the second one, but the third one causes GPF.
Threads are in Ring 0,
The opcodes at which it faults are 0xCD (int3) and 0xF|0xA9 which are not privileged instructions anyways.
Re: GPF When three or more threads running
Posted: Tue Aug 30, 2011 2:03 am
by Combuster
#GP instead of #DE on int3 means your IDT/GDT is messed up
#GP instead of #MF/#NM on what looks like an FPU opcode (please check!) means your IDT/GDT is messed up...
So probably your IDT/GDT got messed up
Re: GPF When three or more threads running
Posted: Tue Aug 30, 2011 3:11 pm
by Nessphoro
0xF|A9 Is "pop GS "
Re: GPF When three or more threads running
Posted: Tue Aug 30, 2011 3:29 pm
by Nessphoro
I traced to the point where the problem is, but I do not see why it causes a problem.
The behavior is very unusual, threads get switched in the right way, for some amount of time before it #GF on the task switch( Mostly)
EDIT: I found the reason, it happen because the stack has wrong values, but why? If it works lets say 10 seconds what corrupts the stack. Hmm...
EDIT 2:Quite the same problem as with the guy who posted "Strange stack clobber problem"
Re: GPF When three or more threads running
Posted: Wed Aug 31, 2011 4:55 am
by mduft
heh. yeah multi-threading and why things go wrong is pretty hard to grock
can i help?
edit: what pit i fell into first was that i wasn't removing the error code from the stack, as the cpu never removes the error code. thus you have to add $0x4 (or $0x8, is it x86_64?) at the end of the interrupt handlers for it...
Re: GPF When three or more threads running
Posted: Wed Aug 31, 2011 3:11 pm
by Nessphoro
Yes, I have removed the error code. I have a unified stack regardless of error code being present or not, so I just ADD ESP,8 to clear it (Interrupt number is also passed there).
What happens is the ESP of the thread (where all the registers are stored), changes by a small amount, and the POP GS fails, because that Selector does not exist.
Re: GPF When three or more threads running
Posted: Wed Aug 31, 2011 4:24 pm
by gerryg400
Remember that when a stack switch occurs in long mode the new stack is forced to a 16 byte alignment by the processor. Is that the reason your stack 'changes by a small amount' ?
[edit] Ooops, sorry, thought you were in long mode.
Re: GPF When three or more threads running
Posted: Wed Aug 31, 2011 4:25 pm
by Nessphoro
No, I wouldn't say that, I'm not using long mode.
Re: GPF When three or more threads running
Posted: Thu Sep 01, 2011 12:29 am
by mduft
hm, not too many more ideas then. i've been using the IST from the very beginning of my kernel on, but AFAIK that is not available without long mode, right? do you actually switch stacks? or do you keep going with whatever comes along..?
are you willing to share some source that we can look at, or is it closed source? that would make analysis a little less guessing
Re: GPF When three or more threads running
Posted: Thu Sep 01, 2011 9:20 pm
by Nessphoro
Certainly,
Switch tasks:
Code: Select all
MOV ECX,0xDEADC0DE
MOV EAX,[_SwitchRequested]
CMP EAX,1
JNE CleanUp ;Somewhere in the code there was a request to switch
MOV BYTE [_SwitchRequested],0
MOV ECX,0xDEAD7A6D
CALL _GetNextThread
MOV EAX,[_RunningThread] ;Get the Thread struct address
MOV EBX,[EAX+12] ;PageDirectory
MOV EBX,[EBX+0x2000] ;Physical
MOV ECX,0xDEAD2E2
MOV CR3,EBX
;We're now in the next tasks VM
MOV ECX,0xDEAD57AC
MOV EAX,[EAX+4]
MOV ESP,EAX
CleanUp:
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
Next thread:
Code: Select all
extern "C" void GetNextThread()
{
RunningThread->ESP0=(unsigned int)get_current_context();
if(RunningThread->Parent->TaskID==1&&RunningThread->DontSave)
{
mem_copy(get_current_context(),RunningThread->Context,sizeof(context_86)); //This is to hack the kernel to run as a task
}
if(RunningThread->DontSave)
{
RunningThread->DontSave=false;
}
else
{
if(!RunningThread->VM)
mem_copy(RunningThread->Context,get_current_context(),sizeof(context_86));
else
mem_copy(RunningThread->Context,get_current_context(),sizeof(context_86_vm));
}
while(RunningThread->Next->Exit)
{
Thread* DeleteThread=RunningThread->Next;
RunningThread->Next=RunningThread->Next->Next;
EndThread(DeleteThread);
//ParentTask->Threads->Delete(DeleteThread);
}
RunningThread=RunningThread->Next;
while(RunningThread->Blocking)
{
while(RunningThread->Next->Exit)
{
Thread* DeleteThread=RunningThread->Next;
RunningThread->Next=RunningThread->Next->Next;
EndThread(DeleteThread);
//ParentTask->Threads->Delete(DeleteThread);
}
RunningThread=RunningThread->Next;
}
if(!RunningThread->VM)
set_kernel_stack(RunningThread->ESP0+sizeof(context_86));
else
set_kernel_stack(RunningThread->ESP0+sizeof(context_86_vm));
}