multitasking few questions
multitasking few questions
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.
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.
- Combuster
- 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:
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
)
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
![Sad :(](./images/smilies/icon_sad.gif)
- Combuster
- 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:
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.
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.
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.
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();
}
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.
![Sad :(](./images/smilies/icon_sad.gif)
![Sad :(](./images/smilies/icon_sad.gif)
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.
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,
For the ltr,
try to use this instead:
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,
i think that goes to 0x18.. not 0x20.. ?tmp=(word)&tss[0];
gdt_set_gate(3,tmp,sizeof(Tss),0x89,0);
For the ltr,
try to use this instead:
Note! Msvc inline assembler syntax! but easy to "port"...__asm {
mov eax, 18h
ltr ax
}
my os sure 32bit...
but i still get the general protection fault when i'm loading the TR
with 0x18
also i fixed the ltr function to this..
any way Thanx.
you'r right i fixed that mistake.i think that goes to 0x18.. not 0x20.. ?
but i still get the general protection fault when i'm loading the TR
with 0x18
![Sad :(](./images/smilies/icon_sad.gif)
![Sad :(](./images/smilies/icon_sad.gif)
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
Don't use a seperate function to do the ltr!
inline that..
for example:
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:
![Wink :wink:](./images/smilies/icon_wink.gif)
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.
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 :wink:](./images/smilies/icon_wink.gif)
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.
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... copmiled with GCC
Thanx.
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.
![Sad :(](./images/smilies/icon_sad.gif)
![Sad :(](./images/smilies/icon_sad.gif)
code...assembled with nasm
Code: Select all
global _ltr_load
_ltr_load:
mov eax,18h
ltr ax
ret
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");
}