Issue in Task Linking with lcall and iret on x86
Posted: Tue Dec 06, 2011 2:46 am
Can you please help me and let me know , why the "push ebp" instruction is corrupting the GDT entries ?.
Thing to note is that , some times it works and some times dont work.
Description with code is given below. I am sorry , its a big .
I am writing program for Task switching with Linking on x86 with help of FAR CALL (lcall) and IRET.
I have 3 TASKs ( T1,T2 & T3) with separate TSS and LDT for each task in GDT. I have also made kernel as TASK0 (i.e. T0) with its TSS0 and LDT0 in GDT table.
I have tried to give relevant code only to avoid confusion.
Kernel init code is given below.
TASK structure are given below:
Scheduler code will select the TASK based on priority and switch to it.
Each task's TSS will have separate EIP to start the execution, which is set in Sched_init() function.
Below is code for which T3's EIP is linked in T3's TSS structure.
As mentioned in file task.s, when i step into "call do_task3" , i find the instruction as "push ebp and mov ebp, esp" which is done as we enter into function by compiler.
As soon as i execute the push ebp instruction i see that GDT table for T0,T1 and T2 are changed to initial value (assume T3 is running)which have TSS low and high address as 0x0.. GDT table entry for T3 is not changed and i see its BUSY with proper TSS struct address.
Can you please help me and let me know , why the "push ebp" instruction is corrupting the GDT entries ?
Initial GDT values are :
Thing to note is that , some times it works and some times dont work.
Description with code is given below. I am sorry , its a big .
I am writing program for Task switching with Linking on x86 with help of FAR CALL (lcall) and IRET.
I have 3 TASKs ( T1,T2 & T3) with separate TSS and LDT for each task in GDT. I have also made kernel as TASK0 (i.e. T0) with its TSS0 and LDT0 in GDT table.
I have tried to give relevant code only to avoid confusion.
Kernel init code is given below.
Code: Select all
Kernel_init()
{
setGDT();
setIDT();
Init_Timer(); // to 0x20
Sched_init(); // Will initialize the GDT with TSS and LDT for each task and load TR register too
for(;;)
{
if(TimerFlag != 1){
// Wait for First TimerInterrupt ;
// Timer interrupt is used to change the priority
continue;
}
Scheduler();
}
}
Code: Select all
// file task.h
struct TSS_STRUCT {
uint32 back_link;
uint32 esp0, ss0;
uint32 esp1, ss1;
uint32 esp2, ss2;
uint32 cr3;
uint32 eip;
uint32 eflags;
uint32 eax,ecx,edx,ebx;
uint32 esp, ebp;
uint32 esi, edi;
uint32 es, cs, ss, ds, fs, gs;
uint32 ldt;
uint32 trace_bitmap;
};
/* structure of a task*/
struct TASK_STRUCT {
struct TSS_STRUCT tss;
uint64 tss_entry; //descriptor of the TSS entry//
uint64 ldt[2];
uint64 ldt_entry;
sint32 state;
sint32 priority;
ULONG task_tss_sel;
struct TASK_STRUCT *next;
};
Code: Select all
// file task.c
struct TASK_STRUCT *current = &TASK0; // initial setting
Scheduler()
{
unsigned int sel[2], eflags;
struct TASK_STRUCT *v = &TASK0, *tmp = 0;
unsigned int cp;
cp = current->priority;
// This to select task based on priority
for (; v; v = v->next) {
if (((v->state==TS_RUNABLE) && (cp>v->priority))){
tmp = v;
cp = v->priority;
}
}
if (tmp && (tmp != current)) {
current->state = TS_RUNABLE;
tmp->state = TS_RUNNING;
current = tmp;
sel[0]= 0;
sel[1]= current->task_tss_sel;
// Code to do FAR CALL
__asm__ ("lcall %0": :"m" (*sel));
}
}
void do_task3 ()
{
// Write to memory and return
WritetoMemory( 0x3333);
return;
}
Below is code for which T3's EIP is linked in T3's TSS structure.
Code: Select all
// file - task.s
task3_run:
call do_task3 //problem is here
iret
task3_end: jmp task3_run
As soon as i execute the push ebp instruction i see that GDT table for T0,T1 and T2 are changed to initial value (assume T3 is running)which have TSS low and high address as 0x0.. GDT table entry for T3 is not changed and i see its BUSY with proper TSS struct address.
Can you please help me and let me know , why the "push ebp" instruction is corrupting the GDT entries ?
Code: Select all
// After "push ebp" one GDT entry will look like :
0x00c0890000000067ULL ;// with TSS address as 0x0
// Before "push ebp", one GDT entry will look like :
0xffc089fedae00067ULL; // where fffedae0 is TSS address
Code: Select all
uint64 kgdt[MAX_GDT_ENTRIES] = {
0x0000000000000000ULL , // null -0
0x00cf9b000000FFFFULL, // cs -
0x00cf93000000ffffULL, // ds and ss -2
0x00c0890000000067ULL, // tss0 // 0x18
0x00c082000000000fULL , //ldt 0 //0x20
0x00c0890000000067ULL, // tss1 // 0x28
0x00c082000000000fULL, // ldt1 // 0x30
0x00c0890000000067ULL, // tss2 // 0x38
0x00c082000000000fULL, // ldt2 // 0x40
0x00c0890000000067ULL, // tss3 // 0x48
0x00c082000000000fULL, // ldt3 // 0x50
};