tss question
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
ok after a bit of readin in the intel manual, i changed the tss's as follows:
before enabling the clock interrupt i also do this:
this way, a clock interrupt while the kernel task is executing should cause task2 to execute, a clock interrupt while task2 is executing should cause task1 to execute, and a clock interrupt while task 1 is executing should cause task2 to execute and so on...
heres my new clock handler:
task1 and task 2 just look like this:
i dont get a bochs error any more, but nothing happens either..id have expected to see many "task1"s and "task2"s printed to the screen!
Code: Select all
kernelstate: tss_t := tss_t:[IDX_TASK2TSS*@size(segdesc),0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,$ffff];
task1state: tss_t := tss_t:[
IDX_TASK2TSS*@size(segdesc),
0,
$fffffffc,
IDX_TASK1STACK*@size(segdesc),
0,
0,
0,
0,
0,
0,
0,
0,
&task1,
$4000,
0,
0,
0,
0,
0,
0,
0,
0,
IDX_KERNELDATA*@size(segdesc),
0,
IDX_KERNELCODE*@size(segdesc),
0,
0,
0,
IDX_KERNELDATA*@size(segdesc),
0,
IDX_MEMORY*@size(segdesc),
0,
IDX_VIDEO*@size(segdesc),
0,
0,
0,
0,
0,
$ffff
];
task2state: tss_t := tss_t:[
IDX_TASK1TSS*@size(segdesc),
0,
$fffffffc,
IDX_TASK2STACK*@size(segdesc),
0,
0,
0,
0,
0,
0,
0,
0,
&task2,
$4000,
0,
0,
0,
0,
0,
0,
0,
0,
IDX_KERNELDATA*@size(segdesc),
0,
IDX_KERNELCODE*@size(segdesc),
0,
0,
0,
IDX_KERNELDATA*@size(segdesc),
0,
IDX_MEMORY*@size(segdesc),
0,
IDX_VIDEO*@size(segdesc),
0,
0,
0,
0,
0,
$ffff
];
Code: Select all
pushfd();
pop(eax);
or($4000,eax);
push(eax);
popfd();
heres my new clock handler:
Code: Select all
procedure clock_int; @nodisplay; @noalignstack; @noframe;
begin clock_int;
push(eax);
pushfd();
mov(PIC_EOI,al);
out(al,PIC1_COMMAND);
popfd();
pop(eax);
iret();
end clock_int;
Code: Select all
procedure task1;
begin task1;
forever
cli;
putstring("task1");
sti;
endfor;
end task1;
procedure task2;
begin task2;
forever
cli;
putstring("task2");
sti;
endfor;
end task2;
Have a look at the lowest diagram on http://www.sandpile.org/ia32/tss.htm to see how backlinking works. Basically, you need to adjust the task's NT flag and set the backlink field to the desired incoming task. IRET will then perform the task switch for you.
I would suggest having a look through the Intel Manuals again. Software switching is only touched on in there, but the type of Hardware switching you are trying to accomplish is fully explained.
Cheers,
Adam
I would suggest having a look through the Intel Manuals again. Software switching is only touched on in there, but the type of Hardware switching you are trying to accomplish is fully explained.
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
I really have read it. As it seems to me now, the situation is as follows:
If my current task has its NT flag set and a valid task selector in its backlink, it can execute an iret to return to the previous task. Ok.
But if during task execution an interrupt occurs (e.g. clock), the iret in the isr will simply return to the task, not to the task in the backlink of the task. This then means I can only return to the previous task with an explicit iret in the code of the task itself. But what I want is preemptive multitasking. Issuing an iret requires the task to be cooperative
If my current task has its NT flag set and a valid task selector in its backlink, it can execute an iret to return to the previous task. Ok.
But if during task execution an interrupt occurs (e.g. clock), the iret in the isr will simply return to the task, not to the task in the backlink of the task. This then means I can only return to the previous task with an explicit iret in the code of the task itself. But what I want is preemptive multitasking. Issuing an iret requires the task to be cooperative
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
No.
1) Timer interrupt fires and switches to ring 0 stack found in current task's TSS. You are still running 'Task 1' at this point, but have automatically made the transition to ring 0 to service the interrupt.
2) Your scheduler decides it is time for a task switch this time. Modify the backlink field and NT flag of Task 1, to point to Task 2.
3) IRET. Now you are running Task 2.
4) Timer fires and switches to ring 0 stack, but you don't need a task switch this time - just increment your tick counter and IRET with no modifications.
5) Timer fires and switched to ring 0 stack. You are still running Task 2 at this point, but have made the transition to ring 0 to service the interrupt.
6) We are due for another task switch this time. Modify the backlink field and NT flag of Task 2 to point to Task 1.
7) IRET. You are now running Task 1 again. No need for any IDT modifications.
....and so on.
The one circumstance where you may want your IDT to contain a task gate is the double fault. This will ensure you are running on a clean stack.
Cheers,
Adam
1) Timer interrupt fires and switches to ring 0 stack found in current task's TSS. You are still running 'Task 1' at this point, but have automatically made the transition to ring 0 to service the interrupt.
2) Your scheduler decides it is time for a task switch this time. Modify the backlink field and NT flag of Task 1, to point to Task 2.
3) IRET. Now you are running Task 2.
4) Timer fires and switches to ring 0 stack, but you don't need a task switch this time - just increment your tick counter and IRET with no modifications.
5) Timer fires and switched to ring 0 stack. You are still running Task 2 at this point, but have made the transition to ring 0 to service the interrupt.
6) We are due for another task switch this time. Modify the backlink field and NT flag of Task 2 to point to Task 1.
7) IRET. You are now running Task 1 again. No need for any IDT modifications.
....and so on.
The one circumstance where you may want your IDT to contain a task gate is the double fault. This will ensure you are running on a clean stack.
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Ok, suppose I want to achieve the following:
My kernel runs and I have ltr'ed the kernel tss. When the first timer interrupt occurs, I want a task switch to task 2. On the second timer interrupt, I want a task switch to task 1. After that task 1 and 2 keep alternating on every timer interrupt. I can only try this out when I get home from work but do you think I have a chance that this will finally work:
My kernel runs and I have ltr'ed the kernel tss. When the first timer interrupt occurs, I want a task switch to task 2. On the second timer interrupt, I want a task switch to task 1. After that task 1 and 2 keep alternating on every timer interrupt. I can only try this out when I get home from work but do you think I have a chance that this will finally work:
Code: Select all
procedure clock_int; @nodisplay; @noalignstack; @noframe;
begin clock_int;
push(eax);
pushfd();
pop(eax);//popping the flags so I can set the NT bit
or($4000,eax);
push(eax);
streg(ax);
if (ax = IDX_KERNELTSS*@size(segdesc)) then
mov(IDX_TASK2TSS*@size(segdesc),kernelstate.backlink);
elseif (ax = IDX_TASK1TSS*@size(segdesc)) then
mov(IDX_TASK2TSS*@size(segdesc),task1state.backlink);
else
mov(IDX_TASK1TSS*@size(segdesc),task2state.backlink);
endif;
mov(PIC_EOI,al);
out(al,PIC1_COMMAND);
popfd();
pop(eax);
iret();
end clock_int;
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
I *seem* to be on the right track, but this keeps giving me errors.
When the iret is executed, bochs gives me "TSS selector points to bad TSS".
I'll paste my initialisation of task2 tss again:
of type:
What the heck am I still doing wrong?
When the iret is executed, bochs gives me "TSS selector points to bad TSS".
I'll paste my initialisation of task2 tss again:
Code: Select all
task2state: tss_t := tss_t:[
0,
0,
$fffffffc,
IDX_TASK2STACK*@size(segdesc),
0,
0,
0,
0,
0,
0,
0,
0,
&task2,
0,
0,
0,
0,
0,
0,
0,
0,
0,
IDX_KERNELDATA*@size(segdesc),
0,
IDX_KERNELCODE*@size(segdesc),
0,
0,
0,
IDX_KERNELDATA*@size(segdesc),
0,
IDX_MEMORY*@size(segdesc),
0,
IDX_VIDEO*@size(segdesc),
0,
0,
0,
0,
0,
104
];
Code: Select all
type tss_t:
record;
backlink: word;
zeroes1: word;
sp0: dword;
ss0: word;
zeroes2: word;
sp1: dword;
ss1: word;
zeroes3: word;
sp2: dword;
ss2: word;
zeroes4: word;
cr3_reg: dword;
eip_reg: dword;
eflag_reg: dword;
eax_reg: dword;
ecx_reg: dword;
edx_reg: dword;
ebx_reg: dword;
esp_reg: dword;
ebp_reg: dword;
esi_reg: dword;
edi_reg: dword;
es_reg: word;
zeroes5: word;
cs_reg: word;
zeroes6: word;
ss_reg: word;
zeroes7: word;
ds_seg: word;
zeroes8: word;
fs_seg: word;
zeroes9: word;
gs_seg: word;
zeroes10: word;
ldt_sel: word;
zeroes11: word;
debug: byte; //set lowest bit TRUE to raise a debug exception on a task switch
zeroes12: byte;
iomap_base: word;
endrecord;
- 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:
Would you *please* try and look for the answer yourself. That includes searching on the error message in the bochs sources:
Code: Select all
// AR byte must specify TSS, else #TS(new TSS selector)
// new TSS must be busy, else #TS(new TSS selector)
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
I'll (try to) do my best.
I didn't know the busy flag needs to be set, so that may be the cause. I'll try out at home. The AR byte is definitely correctly set.
But let me get that straight: The error message tells me "something is wrong with the TSS", but a look into the source code tells me, what this really wants to say is "something is wrong with the descriptor"???
That really put me on the wrong track!
I didn't know the busy flag needs to be set, so that may be the cause. I'll try out at home. The AR byte is definitely correctly set.
But let me get that straight: The error message tells me "something is wrong with the TSS", but a look into the source code tells me, what this really wants to say is "something is wrong with the descriptor"???
That really put me on the wrong track!
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
hi
i *kind of* got the multitasking to work
i had to modify my clocl handler still a little bit, it now looks like this:
So the sequence should be as follows:
-Kernel executes, clock interrupts
-clock switches to task1
-task1 executes
-clock switches to task2
-task2 executes
-clock switches to task1
-task1 executes
-clock switches to...
and so on
task1 and task2 simply output 1's and 2's respectively so I can see who's currently executing:
when i run this the following happens:
i quickly see many 1's, then many 2's, then it hangs
so the first switch from kernel to task1 and from task1 to task2 execute fine
i suspect the problem lies somehow with the fact that i first iret'ed from task1 to task2 and then try to iret from task2 to task1
i checked in the intel manuals and found out that whenever i iret from task1 to task2, the busy flag of task1 is cleared, so I put also code in the clock handler to set the busy flag of the task i want to iret to (as you can see above)
but the problem remains, system hangs when trying to switch back from task2 to task1
i also tried the other way round: have the kernel first switch to task2 and then to task1 and then to task2 and so on
the result was the same, only that now the system hung duiring task1, so the problem clearly seems to lie with the fact that i am iretting TO a task that i iretted FROM just before that...
i cannot provide an error message since i have to use virtualbox now..after i found out that bochs didnt properly handle expand down stack segments, i tried virtualbox where it ran fine..but now i have no debugger
i *kind of* got the multitasking to work
i had to modify my clocl handler still a little bit, it now looks like this:
Code: Select all
procedure clock_int; @nodisplay; @noalignstack; @noframe;
begin clock_int;
push(eax);
push(ebx);
pushfd();
pop(eax);//popping the flags so I can set the NT bit
or($4000,eax);
push(eax);
streg(ax);
if (ax = IDX_KERNELTSS*@size(segdesc)) then
mov(IDX_TASK1TSS*@size(segdesc),kernelstate.backlink);
mov(GDT_BASE,eax);
add(IDX_TASK1TSS*@size(segdesc),eax);
fseg: mov((type segdesc [eax]).props1,bl);
or(%00000010,bl);
fseg: mov(bl,(type segdesc [eax]).props1);
elseif (ax = IDX_TASK2TSS*@size(segdesc)) then
mov(IDX_TASK1TSS*@size(segdesc),task2state.backlink);
mov(GDT_BASE,eax);
add(IDX_TASK1TSS*@size(segdesc),eax);
fseg: mov((type segdesc [eax]).props1,bl);
or(%00000010,bl);
fseg: mov(bl,(type segdesc [eax]).props1);
else
mov(IDX_TASK2TSS*@size(segdesc),task1state.backlink);
mov(GDT_BASE,eax);
add(IDX_TASK2TSS*@size(segdesc),eax);
fseg: mov((type segdesc [eax]).props1,bl);
or(%00000010,bl);
fseg: mov(bl,(type segdesc [eax]).props1);
endif;
mov(PIC_EOI,al);
out(al,PIC1_COMMAND);
popfd();
pop(ebx);
pop(eax);
iret();
end clock_int;
-Kernel executes, clock interrupts
-clock switches to task1
-task1 executes
-clock switches to task2
-task2 executes
-clock switches to task1
-task1 executes
-clock switches to...
and so on
task1 and task2 simply output 1's and 2's respectively so I can see who's currently executing:
Code: Select all
procedure task1;
begin task1;
forever
cli;
putstring("1");
sti;
endfor;
end task1;
i quickly see many 1's, then many 2's, then it hangs
so the first switch from kernel to task1 and from task1 to task2 execute fine
i suspect the problem lies somehow with the fact that i first iret'ed from task1 to task2 and then try to iret from task2 to task1
i checked in the intel manuals and found out that whenever i iret from task1 to task2, the busy flag of task1 is cleared, so I put also code in the clock handler to set the busy flag of the task i want to iret to (as you can see above)
but the problem remains, system hangs when trying to switch back from task2 to task1
i also tried the other way round: have the kernel first switch to task2 and then to task1 and then to task2 and so on
the result was the same, only that now the system hung duiring task1, so the problem clearly seems to lie with the fact that i am iretting TO a task that i iretted FROM just before that...
i cannot provide an error message since i have to use virtualbox now..after i found out that bochs didnt properly handle expand down stack segments, i tried virtualbox where it ran fine..but now i have no debugger