more hardware multitasking problems
Ok, i'll try to be a little more explicit. In a multitasking environment you have a bunch of applications they all should run on PL3. Next to those applications you have some drivers or kernel processes They should run on PL < 3 (PL0, PL1, PL2) for portability issues its better to only use PL0.
Using a Timer interrupt gives you a mechanism to switch beteen these process on different PLs. For instance like : PL0 - # - PL3 - # - PL3 - # - PL0 - # - PL3 where the hash is the timer interrupt occuring.
Each process has it's own stack and memory where in case of context switching (PL0->PL3 or PL3->PL0 or PL3->PL3 (other application)) the timer interrupt handler switches to the stack of the new application and thus gives the cpu to the new application.
As fas as i can gather from your code it seems you use TSS alot so it is hardware based contect switching. You might consider software based context switching since in x86-64 hardware based context switching is not supported anymore. And software based switching is faster anyways.
I think there is good documentation on this subject in the wiki otherwise google for it. I cannot give details about x86 in protected mode as i am only sufficient with 64 bit long mode. But as mentioned in another reply read the intel or amd manuals for information about how the stack behaves during interrupts. I know there is a difference between interrupts on different PLs and interrupts on the same PL.
In a nutshell it should work like this (very abstract):
1) process 1 is running on PL0
2) # (timer interrupt) occurs, which stores all registers on the stack of process1, including the segement registers which contain the PL.
3) find the next process to run which is process 2 and switch to its stack
4) get all registers from the stack and segments.
5) do the interrupt return (iret). (effectively changes PL).
Using a Timer interrupt gives you a mechanism to switch beteen these process on different PLs. For instance like : PL0 - # - PL3 - # - PL3 - # - PL0 - # - PL3 where the hash is the timer interrupt occuring.
Each process has it's own stack and memory where in case of context switching (PL0->PL3 or PL3->PL0 or PL3->PL3 (other application)) the timer interrupt handler switches to the stack of the new application and thus gives the cpu to the new application.
As fas as i can gather from your code it seems you use TSS alot so it is hardware based contect switching. You might consider software based context switching since in x86-64 hardware based context switching is not supported anymore. And software based switching is faster anyways.
I think there is good documentation on this subject in the wiki otherwise google for it. I cannot give details about x86 in protected mode as i am only sufficient with 64 bit long mode. But as mentioned in another reply read the intel or amd manuals for information about how the stack behaves during interrupts. I know there is a difference between interrupts on different PLs and interrupts on the same PL.
In a nutshell it should work like this (very abstract):
1) process 1 is running on PL0
2) # (timer interrupt) occurs, which stores all registers on the stack of process1, including the segement registers which contain the PL.
3) find the next process to run which is process 2 and switch to its stack
4) get all registers from the stack and segments.
5) do the interrupt return (iret). (effectively changes PL).
Author of COBOS
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
Software multitasking is much simpler to implement and to modify as well. If you want, PM me and I can give you some code (and an explanation, so you aren't blindly copying-and-pasting) so you can get an understanding of how stack-switching works. I didn't understand it until I got help from 'frank' (here on this forum) and it works really well.
With the hardware multitasking, I'd suggest you shy away from it as you have a limit on the number of TSS's you can have (it's something thousand... but who wants to be limited?) because of the GDT.
My 2c.
With the hardware multitasking, I'd suggest you shy away from it as you have a limit on the number of TSS's you can have (it's something thousand... but who wants to be limited?) because of the GDT.
My 2c.
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
I do not think the AMD64 or IA64 support hardware task switching.
The microcode is supposed to be very old in the IA32 modern processors that supports the hardware task switching, IIRC. So someone correct me if I am wrong which I could be.
Not really sure if it makes a performance impact as I do not a engineer for processor chips, but I figure they stopped for a reason. As well, Window and Linux both use software task switching.
The microcode is supposed to be very old in the IA32 modern processors that supports the hardware task switching, IIRC. So someone correct me if I am wrong which I could be.
Not really sure if it makes a performance impact as I do not a engineer for processor chips, but I figure they stopped for a reason. As well, Window and Linux both use software task switching.
I like it better.Software multitasking is much simpler to implement and to modify as well.
humm...
First of all thank you guys... so you're advicing me to go for
software multitasking but the problem here I don't know any thing
about software multitasking and I mean no thing....
Thanx.
First of all thank you guys... so you're advicing me to go for
software multitasking but the problem here I don't know any thing
about software multitasking and I mean no thing....
yes,would you please ?If you want, PM me and I can give you some code (and an explanation, so you aren't blindly copying-and-pasting) so you can get an understanding of how stack-switching works.
Thanx.
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
Yes, but not right now. Within the next day. I have work to do ATM
If you want to take a look at code, look at my CVS repositry on sourceforge. I've comment pretty regularly so you shouldn't get lost looking there. Specifically, you'll want to look at CPP_Kernel/tasking/mt.cc, CPP_Kernel/irq.inc and CPP_Kernel/syscore/gdt.cc (for tss).
If you want to take a look at code, look at my CVS repositry on sourceforge. I've comment pretty regularly so you shouldn't get lost looking there. Specifically, you'll want to look at CPP_Kernel/tasking/mt.cc, CPP_Kernel/irq.inc and CPP_Kernel/syscore/gdt.cc (for tss).
Also, take a look at http://www.osdever.net/tutorials/multitasking.php.
Ok...till that time could any one please explain to me
how can I use the Timer interrupt from PL3 to go back to PL0?
os64dev gave me nice explain but till now I don't know how I can
go back to PL0 using IRQ0,to be more specific I don't know
the mechanism to do that,what is the connect between IRQ0
and RPL,DPL and CPL,I'm soooooo confused about that.
Please note I'm using hardware taskswitching so the IRET
will not do any thing in my case.
Thanx.
how can I use the Timer interrupt from PL3 to go back to PL0?
os64dev gave me nice explain but till now I don't know how I can
go back to PL0 using IRQ0,to be more specific I don't know
the mechanism to do that,what is the connect between IRQ0
and RPL,DPL and CPL,I'm soooooo confused about that.
Please note I'm using hardware taskswitching so the IRET
will not do any thing in my case.
Thanx.
Hi,
Assume you are running in ring 3 when a timer IRQ fires. The CPU will switch to CPL0 automatically, pushing the current SS and ESP for your ring 3 code. It loads a ring 0 stack from the TSS.
The nice thing about this is that you do not need to worry about switching back to ring 0 as the CPU does this for you.
Cheers,
Adam
Assume you are running in ring 3 when a timer IRQ fires. The CPU will switch to CPL0 automatically, pushing the current SS and ESP for your ring 3 code. It loads a ring 0 stack from the TSS.
The nice thing about this is that you do not need to worry about switching back to ring 0 as the CPU does this for you.
Cheers,
Adam
unfortunately it didn't work I got Invalid opcode exception
Also would you please check my code over there.
Thanx.
are you sure you're talking about hardware multitasking not software?Assume you are running in ring 3 when a timer IRQ fires. The CPU will switch to CPL0 automatically, pushing the current SS and ESP for your ring 3 code. It loads a ring 0 stack from the TSS.
I'm worry about that ...I've been hanging in PL3 and could'nt go back to PL0 for about three days,so could some one end my tragedy??????The nice thing about this is that you do not need to worry about switching back to ring 0 as the CPU does this for you.
Also would you please check my code over there.
Thanx.
for switching to PL0 from PL3 you problably need something like a callgate. They are explained nicely in the intel or amd manuals. Can't help you with those due to lack of experience (i dont use them ).
Still you should consider doing software switching. It does make your life easier.
Still you should consider doing software switching. It does make your life easier.
Author of COBOS
OK - firstly, it doesn't matter whether I'm talking about hardware or software multitasking - a timer IRQ will still get you back in to ring 0. When the timer fires, the CPU will automatically do the following:abuashraf wrote:unfortunately it didn't work I got Invalid opcode exception
...
are you sure you're talking about hardware multitasking not software?
I've been hanging in PL3 and could'nt go back to PL0 for about three
Code: Select all
Switch to CPL0 with a ring 0 stack loaded from your TSS values.
PUSH user mode SS [if you are in ring 3]
PUSH user mode ESP [if you are in ring 3]
PUSH EFLAGS [whatever ring you were in]
PUSH CS [whatever ring you were in]
PUSH EIP [whatever ring you were in]
NOTE: At this point, no task switch has occurred!
Then, if you are doing *hardware* multitasking, you need to do the following (pseudo-code):
Code: Select all
CALL _scheduler ;this selects your next task (your own scheduler)
FAR jmp [tss index] ;this saves your old task TSS and loads the new
;one automatically using the CPUs built in mechanisms.
Alternatively, if you are *software* multitasking, you need to do the following (again, pseudo-code):
Code: Select all
;all pushes are on to the outgoing task's ring 0 stack (which has been
;restored by the CPU).
PUSH ds, es, fs and gs ;saving outgoing task's segments
PUSHA ;saving outgoing task's GP registers
MOV eax, esp ;saving current ESP
MOV [task_struct+offset], eax ;saving esp in your own defined task structure
MOV esp, [kernel esp] ;a stack your kernel can use for the _schedule
;function
CALL _schedule ;your custom scheduler function
;now we have returned, your scheduler has ensured that the *incoming*
;task structure is now pointed to by task_struct
MOV eax, [task_struct+offset] ;restore the new tasks ring 0 stack
MOV esp, eax
MOV [_your_tss_esp0], x ;where x is the desired *base* ring 0 esp value
;for when the next task switch happens.
POPA ;incoming GP regs restored
POP ds, es, fs, gs ;incoming segment regs restored
IRET ;POPs EIP, CS and EFLAGS if CS has a RPL of 3,
;CPU also POPs ESP3 and SS3 from stack.
So, don't worry about call gates and so on, set up an IRQ and get the CPU to switch for you - that's how the internal mechanisms are designed to work, after all...
HTH
Adam
unfortunately it didn't work I got general protection fault
for more simplicity I just made the multitasking consists of two
tasks :main() PL0 and task() PL3,I used the back link of the tss
and loaded it with the selector of the previous task which is ox28
so now here's my code may be some one will figure out what is the wrong
with it....
Thanx.
for more simplicity I just made the multitasking consists of two
tasks :main() PL0 and task() PL3,I used the back link of the tss
and loaded it with the selector of the previous task which is ox28
so now here's my code may be some one will figure out what is the wrong
with it....
Code: Select all
#define max_gdt_entrys 7
void gdt_install()
{
printf("Installing GDT...");
/* Setup the GDT pointer and limit */
unsigned long tmp;
gp.limit = (sizeof(struct gdt_entry) * max_gdt_entrys) - 1;
gp.base = &gdt;
/* Our NULL descriptor 0x00 */
gdt_set_gate(0, 0, 0, 0, 0);
/* The second entry is our Code Segment. The base address
* is 0, the limit is 4GBytes, it uses 4KByte granularity,
* uses 32-bit opcodes, and is a Code Segment descriptor.
* Please check the table above in the tutorial in order
* to see exactly what each value means 0x08*/
gdt_set_gate(1, 0, 0xFFFF, ACS_CODE , 0xCF);
/* The third entry is our Data Segment. It's EXACTLY the
* same as our code segment, but the descriptor type in
* this entry's access byte says it's a Data Segment 0x10 */
gdt_set_gate(2, 0,0xFFFF, ACS_DATA , 0xCF);
/* 0x18 code segment descriptor*/
gdt_set_gate(3,0,0xFFFF,ACS_CODE | ACS_DPL_3 ,0xCF);
/* 0x20 data segment descriptor*/
gdt_set_gate(4,0,0xFFFF,ACS_DATA | ACS_DPL_3,0xCF);
/* -- 0x28 TSS for main() */
tmp=(word)&tss[0];
gdt_set_gate(5,(dword)&tss[0],sizeof(TSS),ACS_TSS,0xCF);
/* -- 0x30 TSS for task() */
tmp=(word)&tss[1];
gdt_set_gate(6,(dword)&tss[1],sizeof(TSS),ACS_TSS,0xCF);
/* Flush out the old GDT and install the new changes! */
gdt_flush();
printf("[Done]\n");
}
struct tss_t
{
dword link,
esp0,
ss0,
esp1,
ss1,
esp2,
ss2,
cr3,
eip,
eflags,
eax,
ecx,
edx,
ebx,
esp,
ebp,
esi,
edi,
es,
cs,
ss,
ds,
fs,
gs,
ldtr;
word trace,
io_map_addr;
};
typedef struct tss_t TSS;
#define max_tasks 2
TSS tss[max_tasks];
#define stack_size 1024
dword task_stack[max_tasks-1][stack_size]; //kernel stack
dword pl0_stack[max_tasks-1][stack_size]; //user stack
void init_task()
{
disable();
unsigned int i=0;
for(i;i<max_tasks;i++)
{
tss[i].trace=0;
tss[i].io_map_addr=sizeof(TSS);
tss[i].ldtr=0;
tss[i].fs=tss[i].gs=0;
tss[i].ds=tss[i].es=tss[i].ss=0x20 | 3;
tss[i].cs=0x18 | 3;
tss[i].eflags=0x3202L;
tss[i].esp=(dword)&task_stack[i]; //stack for user programes
tss[i].ss0=0x10;
tss[i].esp0=(dword)&pl0_stack[i]; //stack for kernel
}
tss[1].eip=(dword)&task;
tss[1].link=0x28; //main() selector
ltr(0x28);
enable();
}
void ltr(unsigned short selector)
{
asm ("ltr %0": :"r" (selector));
}
void task()
{
printf("Hello from task()\n");
__asm__ __volatile__("iret"); //back to main()
}
1) Can we see the Bochs output?
2) Are you *sure* that your kernel is running in user mode pages (pages with the user/supervisor mode bit set)? As your PL3 task is running in ring 3 and is statically linked with the kernel, the *entire* kernel needs to be running in user pages.
3) You still seem to be using cooperative multitasking. How about trying that timer interrupt?
4) Before you iret in your task, you need to ensure that NT is set to avoid the CPU trying to pop the required regs off the stack. This is another reason why you need a timer interrupt - you can then put the task in to a for(;;); loop rather than trying to iret while you are testing the multitasking. I panic when I see iret (or any ISR associated code) in inline asm - this could just be me.
5) Can you post a link to your entire kernel code (in archive format of your choice )?
2) Are you *sure* that your kernel is running in user mode pages (pages with the user/supervisor mode bit set)? As your PL3 task is running in ring 3 and is statically linked with the kernel, the *entire* kernel needs to be running in user pages.
3) You still seem to be using cooperative multitasking. How about trying that timer interrupt?
4) Before you iret in your task, you need to ensure that NT is set to avoid the CPU trying to pop the required regs off the stack. This is another reason why you need a timer interrupt - you can then put the task in to a for(;;); loop rather than trying to iret while you are testing the multitasking. I panic when I see iret (or any ISR associated code) in inline asm - this could just be me.
5) Can you post a link to your entire kernel code (in archive format of your choice )?
humm...
here's a minimized version of my kernel you will find:
pm.c which treats with protected mode stuff like gdt idt isrs...
scr.c treats with video like printf....
str.c treats with string like strcmp...
the most important for us is task.c which treats with hardware
multitasking.
you can do what ever you want with this code,you may please try
using the Timer interrupt which exist in "pm.c"
Also you will find an IMG file,I think it may help...
Please note paging isn't enabled.
any way I'm so grateful thak you so much.
here's a minimized version of my kernel you will find:
pm.c which treats with protected mode stuff like gdt idt isrs...
scr.c treats with video like printf....
str.c treats with string like strcmp...
the most important for us is task.c which treats with hardware
multitasking.
you can do what ever you want with this code,you may please try
using the Timer interrupt which exist in "pm.c"
Also you will find an IMG file,I think it may help...
Please note paging isn't enabled.
any way I'm so grateful thak you so much.
- Attachments
-
- knl.tar.gz
- kernel
- (14.62 KiB) Downloaded 17 times
-
- a.tar.gz
- IMG file
- (46.85 KiB) Downloaded 21 times