multitasking few questions

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

multitasking few questions

Post by xyjamepa »

Hi
I have been reading "PMode Tutorials in C & ASM by Alexei A. Frounze"
I think most of you knows this tutorial and I have a few questions...
In the 6th tutorial he added simple multitasking with only tow tasks
"task1 and main()" and I noteced he used a stack with long 1024 bytes
why does he need this stack?what does this stack do?
another thing he loaded the TR register with value(0x28)
where did this value come from?what does it mean?
also am I right when I'm saying the segment selector refers to the
Tss descriptor of the active task?
Last thing is the syntacs of this long jump using GCC right?
__asm__ __volatile__("ljmp $" TSS_SEL", $0\n\t");

Thanx.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

any one there :?: 8) :?:
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

For starters, I never saw this tutorial until today... The only tutorial that the majority knows is the kernel development tut from osdever.

0x28 is the 6th entry in the GDT: the gdt is loaded in tut06.c (the same file that loads the task register)

The stack would be needed as the function builds a stack frame: local variables are declared on-the-stack.

You should be aware with the AT&T syntax that the tutorial uses 16 bit code while gcc is 32 bit. This makes this tutorial very difficult to port. You might want to try the tutorials by Christopher Giese instead. (It's still dos however :( )
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

humm...
forget about the tutorial,let's assume we only have two tasks
why do we need a stack in hardware multitasking
would you please give me a more detailed explain about stack job in multitasking.
and after getting the answer from you i'll ask the rest of my questions.
Thanx.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

The concept and use of the stack is no different if you use hardware task switching or not. The stack is used implicitly when calling interrupts, exceptions, and virtually any running code.

Things that involve the stack:
- Function calls, local variables (inherent in virtually all programming paradigms)
- Exceptions (inherent in human nature)
- System calls (inherent in operating system design)
- Interrupts (well, you might keep these disabled, but still)

That means each thread/task needs its own separate stack. You can't sensibly do without one. Not with hardware task switches, nor with software task switches.

The twist is, when one jumps to more-privileged code, a new stack is selected as a security measure. That means that each task requires two stacks: one for running in userland, one for in-kernel. With hardware task switching you just load the appropriate values into esp0/ss0 for each task, with software task switches you replace these values in the tss.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...
I'm trying to write a very basic hardware multitasking
but now when I'm testing my code i'm getting General protection fault.
My multitasking has two tasks the function main() and task1() which prints
a message,in main() i do far jum to the selector of task1() print the message and go back to the main().
My GDT works fine but I'm worry about the task1() descriptor
and main() descriptor becuase I've just added them to the GDT table,
here is my code I'm using gcc and nasm.... Thanx.

Code: Select all

void gdt_install()
{
    /* Setup the GDT pointer and limit */
 unsigned long tmp;
 gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
 gp.base = &gdt;

    /* NULL descriptor */
 gdt_set_gate(0, 0, 0, 0, 0);
 gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
 gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
   
   /*
     0x20 --Tss for main()
   */

  tmp=(word)&tss[0];
  gdt_set_gate(3,tmp,sizeof(Tss),0x89,0);

  /*0x28 --Tss for task1() */
  tmp=(word)&tss[1];
  gdt_set_gate(4,tmp,sizeof(Tss),0x89,0);

    /* Flush out the old GDT and install the new changes! */
  gdt_flush();
}

asm function:

;Task switching
;------------------------------------------------
global _lldt					;|
_lldt:						;|
        push    bp				;|
        mov     bp, sp				;|
        mov     ax, [ss:bp+4]			;|	
        lldt    ax              ; load LDTR	;|
        pop     bp				;|
        retn					;|
						;|
global _ltr					;|
_ltr:						;|
        push    bp				;|
        mov     bp, sp				;|
        ltr     word [ss:bp+4]			;|
        pop     bp				;|
        retn					;|
						;|
global _load_fs					;|
_load_fs:					;|	
        push    bp				;|
        mov     bp, sp				;|
        mov     fs, [ss:bp+4]			;|
        pop     bp				;|
        retn					;|
						;|
global _load_gs					;|
_load_gs:					;|
        push    bp				;|
        mov     bp, sp				;|
        mov     gs, [ss:bp+4]			;|
        pop     bp				;|
        retn					;|
;------------------------------------------------

and...

void init_task()
{
 load_fs(0x10);
 load_gs(0x10);

 
 lldt(0);	// clear ldtr
 
 tss[0].trace=tss[1].trace=0;
 tss[0].io_map_addr=tss[1].io_map_addr=sizeof(Tss); //i/o map just after the tss
 tss[0].ldtr=tss[1].ldtr=0;			    //ldtr=0
 tss[1].fs=tss[1].gs=0;
 tss[1].ds=tss[1].es=tss[1].ss=0x10;
 tss[1].esp=(word)&task_stack+stack_size;	    //sp points to task stack top
 tss[1].cs=0x8;
 tss[1].eip=(word)&task1;
 tss[1].eflags=0x202L;
 disable();
 ltr(0x20);	 //load Tr with selector of the main()
 enable();
}
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

I'm talking with my self :( :(
now the problem happens when I'm loading the TR register with
selector of the main() unsing the asm function ltr...
so does any one know what'wrong here?
I'm getting general protection fualt.
and how can I be sure that the descriptor of the main() is right?
and nothing wrong with it?
Thanx.
Gnippel
Posts: 14
Joined: Tue Mar 06, 2007 6:49 pm

Post by Gnippel »

hmm.. i'm really tired now, sow i'm not shure if i'm understanding you correctly.
so sorry if i say something that is unrelated or uncorrect now..


why do you use 16 bit code? is your kernel 16 bit?
if not, try to use 32 bit code wherever possible.

also,
tmp=(word)&tss[0];
gdt_set_gate(3,tmp,sizeof(Tss),0x89,0);
i think that goes to 0x18.. not 0x20.. ?

For the ltr,
try to use this instead:
__asm {
mov eax, 18h
ltr ax
}
Note! Msvc inline assembler syntax! but easy to "port"...
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

my os sure 32bit...
i think that goes to 0x18.. not 0x20.. ?
you'r right i fixed that mistake.
but i still get the general protection fault when i'm loading the TR
with 0x18 :( :(

also i fixed the ltr function to this..

Code: Select all

global _ltr					
_ltr:						
        push    ebp
        mov     ebp, esp
        ltr     [PARAM_1]
        pop     ebp
        ret
any way Thanx.
Gnippel
Posts: 14
Joined: Tue Mar 06, 2007 6:49 pm

Post by Gnippel »

Don't use a seperate function to do the ltr!
inline that..

for example:
void init_task()
{
load_fs(0x10);
load_gs(0x10);

lldt(0); // clear ldtr

tss[0].trace=tss[1].trace=0;
tss[0].io_map_addr=tss[1].io_map_addr=sizeof(Tss); //i/o map just after the tss
tss[0].ldtr=tss[1].ldtr=0; //ldtr=0
tss[1].fs=tss[1].gs=0;
tss[1].ds=tss[1].es=tss[1].ss=0x10;
tss[1].esp=(word)&task_stack+stack_size; //sp points to task stack top
tss[1].cs=0x8;
tss[1].eip=(word)&task1;
tss[1].eflags=0x202L;
disable();

// Like this:

//load Tr with selector of the main()
// For Msvc Only!
__asm {
mov eax, 18h
ltr ax
}

// Or this:

// For Gcc Only!
// Note: Im not familiar with gcc...
asm("movl $0x18, %eax");
asm("ltr %ax");

enable();
}

Note:
i've included Both gcc and msvc example in the same code..
remember to modify!

i belive that you can do the same with the rest of those small asm functions.
Or you could create inline functions to simplify it a bit:
example:
__inline void Do_ldt()
{
asm("movl $0x18, %eax");
asm("ltr %ax");
}
:wink:

Edit:
Just for knowledge..
i belive that "ltr [PARAM_1]" is 'illegal'.
you *must* put 18h in eax and use ltr with ax!

i got that clear to me when i testing how to do the 'ltr'.
anybody disagree? if so, please explain.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

unfortunatly still get the "General protection fault"
I tried to rewrite it agin,I just added two descriptors to the GDT
one for main() 0x18 and the other one 0x20 for task1() and then simply loaded the TR register with 0x18,but didn't work. :( :(

code...assembled with nasm

Code: Select all

global _ltr_load
_ltr_load:
 mov eax,18h
 ltr ax
 ret
code... copmiled with GCC

Code: Select all

void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
    /* Setup the descriptor base address */
 gdt[num].base_low = (base & 0xFFFF);
 gdt[num].base_middle = (base >> 16) & 0xFF;
 gdt[num].base_high = (base >> 24) & 0xFF;

    /* Setup the descriptor limits */
 gdt[num].limit_low = (limit & 0xFFFF);
 gdt[num].granularity = ((limit >> 16) & 0x0F);

    /* Finally, set up the granularity and access flags */
 gdt[num].granularity |= (gran & 0xF0);
 gdt[num].access = access;
}


void gdt_install()
{
 printf("Installing GDT...");

    /* Setup the GDT pointer and limit */
 
 gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
 gp.base = &gdt;

    
 gdt_set_gate(0, 0, 0, 0, 0);

 gdt_set_gate(1, 0, 0xFFFF, 0x9A, 0xCF);

  gdt_set_gate(2, 0,0xFFFF, 0x92, 0xCF);
   
  /* 0x18 -- Tss for main()*/
   gdt_set_gate(3,0,sizeof(Tss),0x89,0xCF);

  /* 0x20 -- Tss for task1()*/
    gdt_set_gate(4,0,sizeof(Tss),0x89,0xCF);
  
    
  gdt_flush();

  printf("[Done]\n");
}
Thanx.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

It's working right now ...
I used this:

void ltr1(unsigned short selector)
{
asm ("ltr %0": :"r" (selector));
}

I'll ask more questions when I get into more trouble... :wink:
Thanx.
Post Reply