more hardware multitasking problems
more hardware multitasking problems
Hi...
I'm still working on my hardware multitasking it consists of three
tasks:main(),task1() and task2(),every thing working perfect and
I can switch from task1() to task2() but when I try to switch back
form task2() to task()1 without paging I'm getting Invalid opcode,
but with paging I'm getting page fault,please note that I gave
all the tasks the same page directory when paging is enabled.
Thanx.
I'm still working on my hardware multitasking it consists of three
tasks:main(),task1() and task2(),every thing working perfect and
I can switch from task1() to task2() but when I try to switch back
form task2() to task()1 without paging I'm getting Invalid opcode,
but with paging I'm getting page fault,please note that I gave
all the tasks the same page directory when paging is enabled.
Thanx.
Now before the far jump to the selectors I reloaded the eip field
of each tss and this is what happining:
switching from main() to task1() -> task2() -> task1() ->task2()
when doing the 4th switching from task2() to task1() Bochs restart.
All tasks are PL0.
and here is the code.
of each tss and this is what happining:
switching from main() to task1() -> task2() -> task1() ->task2()
when doing the 4th switching from task2() to task1() Bochs restart.
All tasks are PL0.
and here is the code.
Code: Select all
void init_task()
{
disable();
unsigned int i=0;
for(i=0;i<max_tasks;i++)
{
tss[i].trace=0;
tss[i].io_map_addr=sizeof(TSS);
tss[i].ldtr=0;
tss[i].cr3=pbdr;
tss[i].fs=tss[i].gs=0;
tss[i].ds=tss[i].es=tss[i].ss=0x10;
tss[i].cs=0x8;
tss[i].eflags=0x202L;
tss[i].esp=(dword)&task_stack[i];
}
tss[1].eip=(dword)&task;
tss[2].eip=(dword)&task2;
ltr(0x18);
enable();
}
void ltr(unsigned short selector)
{
asm ("ltr %0": :"r" (selector));
}
void task()
{
printf("Hello form task()\n");
printf("press any key to continue\n");
getch();
tss[2].eip=(dword)&task2;
far_jmp(0x28);
}
void task2()
{
printf("Hello from task2()\n");
printf("press any key to continue\n");
getch();
tss[1].eip=(dword)&task;
far_jmp(0x20);
}
void far_jmp(unsigned int selector)
{
__asm__ __volatile__ ("ljmp *(%0)\n" : :"r"((void *)&selector -4) : "memory");
}
You should just put infinite loops inside your task functions if you want them to repeat the same code over and over again. When you switch to another task, the eip in the current task structure is set to the next instruction and the registers are also saved to it. So after a task is switched to again it should resume where it left off.
The invalid opcodes you were seeing before the "restore eip" hack were likely caused by invalid return addresses being popped off the stack when a task resumed. The page fault if paging was enabled could be caused by returning to unmapped memory, but also by trying to pop a return address off an empty stack (if the page after it was not mapped).
The way you're doing it now (with the hack), the eip gets set back to the beginning of the function, but the other registers aren't set back to what they should be.
This is likely especially important for esp, since the esp is set to the stack pointer in the far_jmp function (if it isn't inlined). So you're leaking stack memory, which could be the cause of the crash you're seeing if it causes the stack to overflow; kernel stack errors are nasty.
The invalid opcodes you were seeing before the "restore eip" hack were likely caused by invalid return addresses being popped off the stack when a task resumed. The page fault if paging was enabled could be caused by returning to unmapped memory, but also by trying to pop a return address off an empty stack (if the page after it was not mapped).
The way you're doing it now (with the hack), the eip gets set back to the beginning of the function, but the other registers aren't set back to what they should be.
This is likely especially important for esp, since the esp is set to the stack pointer in the far_jmp function (if it isn't inlined). So you're leaking stack memory, which could be the cause of the crash you're seeing if it causes the stack to overflow; kernel stack errors are nasty.
Once again It's working and I added the scheduler and every thing
is working fine.
Now my hardware multitasking consistes of three tasks:
main() which is PL0,task() which is PL3 and task2() also PL3
and I can switch from main() to task() or task2()but when I do
any more other switch from task() I get general protection fault,
so I can only switch from main() to task() or task2()
but I can't go back or switch between task() and task2().
To be more specific I can only switch from PL0 to PL3
but I can't do the opposite.
Also please not that paging isn't enabled right now.
here is the code:
Thanx.
is working fine.
Now my hardware multitasking consistes of three tasks:
main() which is PL0,task() which is PL3 and task2() also PL3
and I can switch from main() to task() or task2()but when I do
any more other switch from task() I get general protection fault,
so I can only switch from main() to task() or task2()
but I can't go back or switch between task() and task2().
To be more specific I can only switch from PL0 to PL3
but I can't do the opposite.
Also please not that paging isn't enabled right now.
here is the code:
Code: Select all
#define ACS_PRESENT 0X80 /* present segment */
#define ACS_CSEG 0X18 /* code segment */
#define ACS_DSEG 0X10 /* data segment */
#define ACS_CONIFORM 0X04
#define ACS_READ 0X02
#define ACS_WRITE 0X02
#define ACS_TSS_GATE 0X09
#define ACS_TSS (ACS_PRESENT | ACS_TSS_GATE)
/* ready-made values */
#define ACS_CODE (ACS_PRESENT | ACS_CSEG | ACS_READ)
#define ACS_DATA (ACS_PRESENT | ACS_DSEG | ACS_WRITE)
#define ACS_STACK (ACS_PRESENT | ACS_DSEG | ACS_WRITE)
#define ACS_DPL_0 0x00 /* descriptor privilege level #0 */
#define ACS_DPL_1 0x20 /* descriptor privilege level #1 */
#define ACS_DPL_2 0x40 /* descriptor privilege level #2 */
#define ACS_DPL_3 0x60 /* descriptor privilege level #3 */
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);
/* 0x8 code segment*/
gdt_set_gate(1, 0, 0xFFFF, ACS_CODE , 0xCF);
/* 0x10 data segment*/
gdt_set_gate(2, 0,0xFFFF, ACS_DATA , 0xCF);
/* 0x18 code segment descriptor PL3*/
gdt_set_gate(3,0,0xFFFF,ACS_CODE | ACS_DPL_3 ,0xCF);
/* 0x20 data segment descriptor PL3*/
gdt_set_gate(4,0,0xFFFF,ACS_DATA | ACS_DPL_3,0xCF);
/* -- 0x28 TSS for main() */
gdt_set_gate(5,(dword)&tss[0],sizeof(TSS),ACS_TSS,0xCF);
/* -- 0x30 TSS for task() */
gdt_set_gate(6,(dword)&tss[1],sizeof(TSS),ACS_TSS,0xCF);
/* --0x38 TSS for task2() */
gdt_set_gate(7,(dword)&tss[2],sizeof(TSS),ACS_TSS,0xCF);
/* Flush out the old GDT and install the new changes! */
gdt_flush();
printf("[Done]\n");
}
#define stack_size 1024
dword task_stack[max_tasks-1][stack_size];
dword pl0_stack[max_tasks-1][stack_size];
void init_task()
{
disable();
unsigned int i=0;
for(i=0;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];
tss[i].ss0=0x10 ;
tss[i].esp0=(dword)&pl0_stack[i];
}
tss[1].eip=(dword)&task;
tss[2].eip=(dword)&task2;
ltr(0x28); //main() selector
enable();
}
void task()
{
printf("Hello from task()\n");
getch();
far_jmp(0x38); //go to task2()
}
void task2()
{
printf("Hello from task2()\n");
getch();
far_jmp(0x28); //back to main()
}
This is cooperative scheduling thus it can hardly be called multitasking. Use a timer (PIT or APIC) to switch between tasks and then it will be true multitasking. And you'll see new problems arising. Ahh... the beauty and fun in os development.
Author of COBOS
I know that and this is not my problem ,I can switch from PL0 to PL3This is cooperative scheduling thus it can hardly be called multitasking. Use a timer (PIT or APIC) to switch between tasks and then it will be true multitasking
but I can't go back so I can't switch from PL3 to PL0 if I did
I get general protection fault.
Thanx.
I think this is to be expected because from PL0 to PL3 is going to a lesser protected level which is allowed by a far jump and from PL3 to PL0 is going to a more protected level which is NOT allowed by a far jump.abuashraf wrote:I know that and this is not my problem ,I can switch from PL0 to PL3
but I can't go back so I can't switch from PL3 to PL0 if I did
I get general protection fault.
Thanx.
Hence the suggestion to use a timer interrupt. On the interrupts the kernel switches to PL0 and you can do kernel/driver stuff and when finished it can switch to a task at PL3 en resume. You could test this by instead of using a far jump try to simulate an interrupt by using iret.
Author of COBOS
Try:
old PL3 task->timer interrupt->IRQ 0->PL 0 interrupt handler->task switch to PL0->rest of PL0 interrupt handler (keep eip within handler, but switch esp/cr3 to new task)->iret->new PL3 task
iret allows you to return to PL3, just look at the intel docs (2a) for iret to see what it expects on the stack.
Regards,
John.
old PL3 task->timer interrupt->IRQ 0->PL 0 interrupt handler->task switch to PL0->rest of PL0 interrupt handler (keep eip within handler, but switch esp/cr3 to new task)->iret->new PL3 task
iret allows you to return to PL3, just look at the intel docs (2a) for iret to see what it expects on the stack.
Regards,
John.
humm...
What I understand till now is that I'm not allowed to do a far jump
in PL3 so I have to use the Timer interrupt IRQ0.
so...am I right?
@jnc100:I think you didn't get me right,I want to switch from
PL3 to PL0 not the opposite.
Also if I have to use the Timer interrupt to achieve switching
from PL3 to PL0 how can I do that?I'm really confused about
using the Timer interrupt to do the switching could any one
enlighten me???
Thanx.
What I understand till now is that I'm not allowed to do a far jump
in PL3 so I have to use the Timer interrupt IRQ0.
so...am I right?
@jnc100:I think you didn't get me right,I want to switch from
PL3 to PL0 not the opposite.
Also if I have to use the Timer interrupt to achieve switching
from PL3 to PL0 how can I do that?I'm really confused about
using the Timer interrupt to do the switching could any one
enlighten me???
Thanx.