tss question
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
OK - Hardware Task Switch:
1) Set up a TSS for your kernel. Don't bother filling anything in here.
2) LTR on this TSS. You shouldn't see anything magic happen here - the task register will just contain your TSS descriptor.
3) Set up a TSS for your incoming task. You will need to fill out initial register values (probably just zero for now), and the ESP field should contain a value pointing to the top of an empty stack (malloc'd space, if you like).
4) SS0/ESP0 in the second TSS should also point to the top of a separate empty stack which must have ring 0 privileges. Forget about ESP1/ESP2.
5) Ensure all segment registers in your second TSS contain valid values, and that EIP points to the start of the incoming task.
6) Far Jump / Far Call / IRET to your new TSS descriptor.
7) Add a new available (busy flag clear) TSS descriptor pointing to your second TSS.
The CPU will automagically now fill your first (kernel TSS) in with appropriate values for the outgoing task. New register values will be loaded from the incoming TSS. TR now points to your new TSS descriptor and your new task should be running. When an interrupt happens, ESP0/SS0 will be loaded from this new TSS. This means you are running in kernel mode again (ring0) and can IRET to whatever TSS descriptor you see fit (by modifying the backlink field, IIRC, or by playing with the stack).
Cheers,
Adam
1) Set up a TSS for your kernel. Don't bother filling anything in here.
2) LTR on this TSS. You shouldn't see anything magic happen here - the task register will just contain your TSS descriptor.
3) Set up a TSS for your incoming task. You will need to fill out initial register values (probably just zero for now), and the ESP field should contain a value pointing to the top of an empty stack (malloc'd space, if you like).
4) SS0/ESP0 in the second TSS should also point to the top of a separate empty stack which must have ring 0 privileges. Forget about ESP1/ESP2.
5) Ensure all segment registers in your second TSS contain valid values, and that EIP points to the start of the incoming task.
6) Far Jump / Far Call / IRET to your new TSS descriptor.
7) Add a new available (busy flag clear) TSS descriptor pointing to your second TSS.
The CPU will automagically now fill your first (kernel TSS) in with appropriate values for the outgoing task. New register values will be loaded from the incoming TSS. TR now points to your new TSS descriptor and your new task should be running. When an interrupt happens, ESP0/SS0 will be loaded from this new TSS. This means you are running in kernel mode again (ring0) and can IRET to whatever TSS descriptor you see fit (by modifying the backlink field, IIRC, or by playing with the stack).
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
What error message does your emulator give when it crashes with LTR. There aren't really many possibilities. For example - have you double checked that your TSS descriptor is what it should be? It would be good practice to point the TSS descriptor to zeroed data. You may also like to set the IO Map pointer to 0xFFFF.
Can you please post a Bochs register dump following the crash? Just before that register dump, it will say something along the lines of "Panic: LTR Descriptor does not point to available TSS" or something similar.
Cheers,
Adam
Can you please post a Bochs register dump following the crash? Just before that register dump, it will say something along the lines of "Panic: LTR Descriptor does not point to available TSS" or something similar.
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
does that give you a clue?
Code: Select all
00002677260i[BIOS ] Booting from 0000:7c00
00003177177e[CPU ] fetch_raw_descriptor: GDT: index (4f)9 > limit (37)
00003177177i[CPU ] CPU is in protected mode (active)
00003177177i[CPU ] CS.d_b = 32 bit
00003177177i[CPU ] SS.d_b = 32 bit
00003177177i[CPU ] | EAX=00010048 EBX=00000001 ECX=00000004 EDX=534d0000
00003177177i[CPU ] | ESP=0000fff0 EBP=0000fff0 ESI=ffff017a EDI=00080248
00003177177i[CPU ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00003177177i[CPU ] | SEG selector base limit G D
00003177177i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00003177177i[CPU ] | CS:0008( 0001| 0| 0) 00014700 0009b500 0 1
00003177177i[CPU ] | DS:0010( 0002| 0| 0) 00014700 0009b500 0 1
00003177177i[CPU ] | SS:0018( 0003| 0| 0) 00000700 000ffffc 0 1
00003177177i[CPU ] | ES:0010( 0002| 0| 0) 00014700 0009b500 0 1
00003177177i[CPU ] | FS:0030( 0006| 0| 0) 00000000 000fffff 1 1
00003177177i[CPU ] | GS:0028( 0005| 0| 0) 000b8000 000f0fa0 0 1
00003177177i[CPU ] | EIP=000000ba (000000ba)
00003177177i[CPU ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00003177177i[CPU ] | CR3=0x00000000 CR4=0x00000000
00003177177i[CPU ] >> ltr ax : 0F00D8
00003177177e[CPU ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00003177177i[SYS ] bx_pc_system_c::Reset(SOFTWARE) called
Next at t=3177177
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b ; ea5be000f0
<bochs:6> info registers
eax: 0x00000000 0
ecx: 0x00000000 0
edx: 0x00000543 1347
ebx: 0x00000000 0
esp: 0x00000000 0
ebp: 0x00000000 0
esi: 0x00000000 0
edi: 0x00000000 0
eip: 0x0000fff0
eflags 0x00000002
IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
<bochs:7>
You are trying to load a GDT descriptor which is beyond the end of the GDT (you are trying to load descriptor 0x4F, when the table limit is 0x37).
The most likely explanation is that you have created a GDT descriptor and added it to the GDT, but your gdt limit (which you load in to the GDTR with LGDT) is set at a value less than this. You therefore need to increase the GDT limit.
Cheers,
Adam
The most likely explanation is that you have created a GDT descriptor and added it to the GDT, but your gdt limit (which you load in to the GDTR with LGDT) is set at a value less than this. You therefore need to increase the GDT limit.
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
hi
thanks for that tip!
now im getting a different error
i though the ldt wasnt necessary:
thanks for that tip!
now im getting a different error
i though the ldt wasnt necessary:
Code: Select all
00000720000i[XGUI ] charmap update. Font Height is 16
00000800000i[XGUI ] charmap update. Font Height is 16
00001088736i[BIOS ] Booting from 0000:7c00
00001589165e[CPU ] LTR: LDT descriptor not present!
00001589165i[CPU ] CPU is in protected mode (active)
00001589165i[CPU ] CS.d_b = 32 bit
00001589165i[CPU ] SS.d_b = 32 bit
00001589165i[CPU ] | EAX=00010048 EBX=00000001 ECX=00000004 EDX=534d0000
00001589165i[CPU ] | ESP=0000fff0 EBP=0000fff0 ESI=ffff017a EDI=00000004
00001589165i[CPU ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00001589165i[CPU ] | SEG selector base limit G D
00001589165i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00001589165i[CPU ] | CS:0008( 0001| 0| 0) 00014700 0009b500 0 1
00001589165i[CPU ] | DS:0010( 0002| 0| 0) 00014700 0009b500 0 1
00001589165i[CPU ] | SS:0018( 0003| 0| 0) 00000700 000ffffc 0 1
00001589165i[CPU ] | ES:0010( 0002| 0| 0) 00014700 0009b500 0 1
00001589165i[CPU ] | FS:0030( 0006| 0| 0) 00000000 000fffff 1 1
00001589165i[CPU ] | GS:0028( 0005| 0| 0) 000b8000 000f0fa0 0 1
00001589165i[CPU ] | EIP=000000c1 (000000c1)
00001589165i[CPU ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00001589165i[CPU ] | CR3=0x00000000 CR4=0x00000000
00001589165i[CPU ] >> ltr ax : 0F00D8
00001589165e[CPU ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00001589165i[SYS ] bx_pc_system_c::Reset(SOFTWARE) called
Next at t=1589165
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b ; ea5be000f0
- 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:
nah its a typo in the sourcecode:i though the ldt wasnt necessary:
Code: Select all
/* #NP(selector) if TSS descriptor is not present */
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("LTR: LDT descriptor not present!"));
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc, 0);
}
In the meantime I'll send a mail to the developers
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
But that's just not true:Combuster wrote: In other words, the present bit is not set.
Code: Select all
;(9) this is the descriptor for the tss of the (boot) kernel
dw 104 ;limit of the segment
dw 0 ;base address of segment
db 0 ;still belonging to base address of segment
db 10001001 ;1 for "TSS is present"
;00 for DPL of 0
;010
;0 for "task not busy"
;1
db 00000000 ;0 for byte-granularity
;000
;0000b for last bits of segment limit
db 0 ;last byte of base address
[edit]Sorry, I didn't know, that in the tss descriptor, 0 means present and 1 not present[/edit]
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Ok I'm having another problem.
My "kernel" runs and I get the ltr instruction to work. Now I tried the following:
I wrote two procedures called task1 and task2. Both are compiled and linked into the kernel. They also execute in ring 0. I wrote 2 new tss descriptors and 2 new stack segment descriptors for them:
The base addresses in these descriptors are again written to at run time to point to the following two TSS:
of type:
Then I introduced a variable task which tells me which task is currently running and rewrote my clock interrupt as follows:
But as soon as the ltreg(ax) gets executed in the timer, I get:
Can anyone help me again?
PS: the mov syntax in HLA is "mov(source,target)"
My "kernel" runs and I get the ltr instruction to work. Now I tried the following:
I wrote two procedures called task1 and task2. Both are compiled and linked into the kernel. They also execute in ring 0. I wrote 2 new tss descriptors and 2 new stack segment descriptors for them:
Code: Select all
;(10) this is the descriptor for the tss of task1
dw 104 ;limit of the segment
dw 0 ;base address of segment
db 0 ;still belonging to base address of segment
db 00001001 ;0 for "TSS is present"
;00 for DPL of 0
;010
;0 for "task not busy"
;1
db 00000000 ;0 for byte-granularity
;000
;0000b for last bits of segment limit
db 0 ;last byte of base address
;(11) this is the descriptor for the tss of task2
dw 104 ;limit of the segment
dw 0 ;base address of segment
db 0 ;still belonging to base address of segment
db 00001001 ;0 for "TSS is present"
;00 for DPL of 0
;010
;0 for "task not busy"
;1
db 00000000 ;0 for byte-granularity
;000
;0000b for last bits of segment limit
db 0 ;last byte of base address
;(12)..stack segment for task1
dw 0 ;limit of the segment
dw 0 ;base address of segment
db 011h ;still belonging to base address of segment
db 10010010b ;1 for "segment is present"
;00 for "privilege 0"
;1 for "data or code segment"
;0 for "data segment"
;0 for "expand downward"
;1 for writable
;0 (access flag set by cpu on 1st access)
db 01001111b ;0 for byte-granularity
;1 for 32-bit stack pointer
;0 (reserved bit)
;0 (available to system programmers)
;1111b for last bits of segment limit
db 0 ;last byte of base address
;(13)..stack segment for task2
dw 0 ;limit of the segment
dw 0 ;base address of segment
db 012h ;still belonging to base address of segment
db 10010010b ;1 for "segment is present"
;00 for "privilege 0"
;1 for "data or code segment"
;0 for "data segment"
;0 for "expand downward"
;1 for writable
;0 (access flag set by cpu on 1st access)
db 01001111b ;0 for byte-granularity
;1 for 32-bit stack pointer
;0 (reserved bit)
;0 (available to system programmers)
;1111b for last bits of segment limit
db 0 ;last byte of base address
Code: Select all
task1state: tss_t := tss_t:[
0,
0,
$fffffffc,
IDX_TASK1STACK*@size(segdesc),
0,
0,
0,
0,
0,
0,
0,
0,
&task1,
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,
$ffff
];
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,
$ffff
];
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;
Code: Select all
procedure clock_int; @nodisplay; @noalignstack; @noframe;
begin clock_int;
push(eax);
pushfd();
mov(task,ax);
if (ax = IDX_TASK2TSS*@size(segdesc)) then
mov(IDX_TASK1TSS*@size(segdesc),ax);
else
mov(IDX_TASK2TSS*@size(segdesc),ax);
endif;
mov(ax,task);
mov(IDX_TASK1TSS*@size(segdesc),ax);
ltreg(ax);
mov(PIC_EOI,al);
out(al,PIC1_COMMAND);
popfd();
pop(eax);
iret();
end clock_int;
Code: Select all
0000641512i[VGA ] VBE known Display Interface b0c0
00000641544i[VGA ] VBE known Display Interface b0c4
00000644469i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00000720000i[XGUI ] charmap update. Font Height is 16
00000800000i[XGUI ] charmap update. Font Height is 16
00001088736i[BIOS ] Booting from 0000:7c00
00001830923e[CPU ] LTR: doesn't point to an available TSS descriptor!
00001830923i[CPU ] CPU is in protected mode (halted)
00001830923i[CPU ] CS.d_b = 32 bit
00001830923i[CPU ] SS.d_b = 32 bit
00001830923i[CPU ] | EAX=00000050 EBX=00000001 ECX=00000004 EDX=534d0000
00001830923i[CPU ] | ESP=0000ffdc EBP=0000fff0 ESI=ffff017a EDI=00080248
00001830923i[CPU ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00001830923i[CPU ] | SEG selector base limit G D
00001830923i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00001830923i[CPU ] | CS:0008( 0001| 0| 0) 00014700 0009b500 0 1
00001830923i[CPU ] | DS:0010( 0002| 0| 0) 00014700 0009b500 0 1
00001830923i[CPU ] | SS:0018( 0003| 0| 0) 00000700 000ffffc 0 1
00001830923i[CPU ] | ES:0010( 0002| 0| 0) 00014700 0009b500 0 1
00001830923i[CPU ] | FS:0030( 0006| 0| 0) 00000000 000fffff 1 1
00001830923i[CPU ] | GS:0028( 0005| 0| 0) 000b8000 000f0fa0 0 1
00001830923i[CPU ] | EIP=00000c62 (00000c62)
00001830923i[CPU ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00001830923i[CPU ] | CR3=0x00000000 CR4=0x00000000
00001830923i[CPU ] >> ltr ax : 0F00D8
00001830923e[CPU ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00001830923i[SYS ] bx_pc_system_c::Reset(SOFTWARE) called
Next at t=1830923
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b ; ea5be000f0
PS: the mov syntax in HLA is "mov(source,target)"
- 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:
Your GDT is still borked
I think I figured why: gets parsed as a decimal number (1001), but not as binary
I think I figured why:
Code: Select all
db 00001001
-
- 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:
Alas, it didn't help!
Something still seems to be wrong with the way I set up my TSS descriptors.
Instead of ltr'ing the kernels tss descriptor on startup, I tried with one of the tasks, and it didn't crash.
But ltr'ing in the clock interrupt makes it crash(and gives me the same error: "LTR: doesn't point to an available TSS descriptor!"). So I assume the probleme occurs as soon as the iret is done.
This is what my descriptors look like now:
Something still seems to be wrong with the way I set up my TSS descriptors.
Instead of ltr'ing the kernels tss descriptor on startup, I tried with one of the tasks, and it didn't crash.
But ltr'ing in the clock interrupt makes it crash(and gives me the same error: "LTR: doesn't point to an available TSS descriptor!"). So I assume the probleme occurs as soon as the iret is done.
This is what my descriptors look like now:
Code: Select all
;(9) this is the descriptor for the tss of the (boot) kernel
dw 104 ;limit of the segment
dw 0 ;base address of segment
db 0 ;still belonging to base address of segment
db 10001001b ;1 for "TSS is present"
;00 for DPL of 0
;010
;0 for "task not busy"
;1
db 00000000b ;0 for byte-granularity
;000
;0000b for last bits of segment limit
db 0 ;last byte of base address
;(10) this is the descriptor for the tss of task1
dw 104 ;limit of the segment
dw 0 ;base address of segment
db 0 ;still belonging to base address of segment
db 10001001b ;1 for "TSS is present"
;00 for DPL of 0
;010
;0 for "task not busy"
;1
db 00000000b ;0 for byte-granularity
;000
;0000b for last bits of segment limit
db 0 ;last byte of base address
;(11) this is the descriptor for the tss of task2
dw 104 ;limit of the segment
dw 0 ;base address of segment
db 0 ;still belonging to base address of segment
db 10001001b ;1 for "TSS is present"
;00 for DPL of 0
;010
;0 for "task not busy"
;1
db 00000000b ;0 for byte-granularity
;000
;0000b for last bits of segment limit
db 0 ;last byte of base address