Hello Michael,
first of all, thank you for the greate explaination. This is really amazing.
The Pseudo-Code of the IRETD i read very often. But i never saw "the big picture".
The most important sentences i will remind:
Quote:
when you are in ring 3 and that external interrupt comes in SS0:ESP0 are read from the TSS, and SS:ESP are set to those new values
Quote:
In the case of an interrupt occurring while already running in Ring0, the TSS isn't consulted
So, now will test, if I understood it correctly: We are using the tss only to ensure, that when we are interrupting a Ring3-Task, that the ISR get a separate Kernel Stack? And if a Ring0 Task is interrupted, we do NOT get a Stack from tss (so we stay on the current kernel stack).
So right, so far?
Ok, now the tricky test, where i will fail
Tss in considered when a Ring3 Task is interrupted. To change to another Ring3-Task, I push SS:ESP on the stack (like I'm doing it now) - stop....because they are already on the stack (because Ring 3 was interrupted), I need to pop them off before, correct? (I think, this is very tricky, because they are not at the top of the stack. Do I'm seeing something wrong?).
When switching to another Ring0 Channel, nothing needs to be considered. Just push CS:EIP and EFLAGS on the current Stack, with the EIP
Once SS0:ESP0 is initially set, will we ever need to change that on task switch?
By the way, here is my (real) code of the switching code. The code is working then all rings are 0, or all are ring 3. If mixed, it will not work. But I understand the matters.
Code:
private static void SwitchToThread(uint threadID, uint oldThreadID)
{
var thread = Threads[threadID];
var oldThread = Threads[oldThreadID];
//Assert.True(thread != null, "invalid thread id");
if (KConfig.TraceThreadSwitch)
KernelMessage.WriteLine("Switching to Thread {0}. ThreadStack: {1:X8}", threadID, (uint)thread.StackStatePointer);
var oldThreadWasUserMode = oldThread.User;
thread.Ticks++;
SetThreadID(threadID);
PIC.SendEndOfInterrupt(ClockIRQ);
if (thread.Status == ThreadStatus.Creating)
{
thread.Status = ThreadStatus.Running;
}
// K=Kernel, U=User, 1=Extra SS:ESP on Stack
// K->K: 0->0: InterruptReturnKernelToKernel
// U->U: 1->1: InterruptReturnUserToUser
// U->K: 1->0: InterruptReturnUserToKernel
// K->U: 0->1: InterruptReturnKernelToUser
if (thread.User && oldThreadWasUserMode)
{
Asm.InterruptReturnUser(thread.StackStatePointer);
}
else
{
Asm.InterruptReturn(thread.StackStatePointer);
}
}
ASM-Code (it's all the same for every version (yet)):
Code:
[BITS 32]
push ebp
mov ebp, esp
mov esi, [ebp+0x8] ;get stack pointer argument
mov esp, esi ;set stack pointer
mov eax, dword 0x23
mov gs,eax
mov ds,eax
mov fs,eax
mov es,eax
;mov [esp+13*4],esi
;mov [esp+14*4],dword 0x20
popad
add esp, 0x8
;mov [esp], dword 0xBBAABBAA
;mov [esp+4], dword 0xCCDDCCDD
sti
iretd
The Matrix in the Comment is the place, where I thought too complicated