Page 1 of 1

LTR and the TSS

Posted: Thu Sep 02, 2004 12:18 pm
by stonedzealot
Hi all, been awhile since I've been around =).

Anyway, I've been stumbling in the dark on and off for a few weeks...or months...trying to figure out this tasking thing. So in terms of the TSS, this is what I'm getting...

You create the TSS, obviously (I'm using the struct defined on www.distantvoices.org). Your fourth (or nth, I guess) GDT descriptor is a TSS descriptor pointing to that TSS you've created. I've done this part, no problem, it's just allocating space for the TSS and modifying the GDT, done.

However, when I load the task register (ltr) with 24 (the selector for my TSS Descriptor in the GDT), it gives me a GPF (error code: 0xff50). One of the problems here is that I can't figure out how to initialize the TSS. I've loaded it with esp, ss, cs, eip of the kernel and it's failed.

All in all, I'm just really confused about this whole thing.

Re:LTR and the TSS

Posted: Thu Sep 02, 2004 2:18 pm
by Dreamsmith
There are only a few circumstances where the processor will even look at the TSS of the current task. Mostly it uses it as a place to store values when it switches away from that task. It reads them later when you switch back, of course, but the point is, initializing the TSS of the current task you're about to set using LTR is extremely easy -- few of the values have to be set to anything in particular.

Try something like this:
memset(&tss, 0, sizeof(tss));
tss.iomap = sizeof(tss);

If you're using paging, also set the pdbr field. If privilege transitions can occur while this task is active, setup the ss0/esp0 (and 1 and 2 if you use those rings).

Things you don't need to set to anything sensible: eip, cs, eax, esp, ss, etc. Since these are only looked at when switching from some other task to this task, what their current value is in the current task's TSS is irrelevant, and destined to be overwriten at the next task switch.

I suspect this in fact has nothing to do with your problem. It should be noted that the error code of a GPF is 0 unless the GPF was caused by an attempt to load an invalid or somehow messed up segment descriptor, in which case the error code is the offending segment descriptor. If you're getting an error code of 0xFF50, you either don't have a segment 0xFF50 or it's messed up, and this is occuring when code is attempting to load a segment register with 0xFF50.

Re:LTR and the TSS

Posted: Fri Sep 03, 2004 8:42 am
by Pype.Clicker
do you load your TSS via some inline asm ? any chance you're doing something like "LTR 24" instead of "LTR $24" and thus loading the TR with memory at address 24 ?

Re:LTR and the TSS

Posted: Mon Sep 06, 2004 12:09 pm
by Neo
What do the base and segment limit in the TSS descriptor refer to? are they the same as the other GDT entries?

Re:LTR and the TSS

Posted: Mon Sep 06, 2004 12:38 pm
by Dreamsmith
Neo wrote:What do the base and segment limit in the TSS descriptor refer to? are they the same as the other GDT entries?
Yes, they're the same. Base needs to point to the first byte of your TSS structure, and limit should be its size minus one (103, unless you have an I/O bitmap attached).

Re:LTR and the TSS

Posted: Wed Sep 08, 2004 1:59 pm
by Neo
What is this IO bitmap actually? how is it created (by us or predefined)? has anyone here used it?

Re:LTR and the TSS

Posted: Wed Sep 08, 2004 3:25 pm
by stonedzealot
Here's a little question that's related but I thought I'd tack it on to this thread rather than start another.

The TSS descriptor within the GDT (the thing I'm pointing LTR to)... I found the structure in the Intel manuals, looks just like any other entry, correct? i.e.

short limit
short base 0 - 15
char base 16 - 23
char lotsacrap
char lotsacrap2
char base 23-31

currently, I'm setting limit with 103 (sizeof(struct tss) - 1) and bases with the base of the tss struct (with paging enabled, not the raw physical address) and

lotsacrap1 (type, dpl, present) as type=11010, dpl=00 and present=1 which turns into 11010001 or 209 (in decimal)

lotsacrap2 (limit 16-19, avl, 0, 0, G) as limit 16-19 = 0000 avl=0 0 0 G=0 so, the entire thing turns out to be 0... is this correct?

Re:LTR and the TSS

Posted: Wed Sep 08, 2004 9:23 pm
by Brendan
Hi,
wangpeng wrote: lotsacrap1 (type, dpl, present) as type=11010, dpl=00 and present=1 which turns into 11010001 or 209 (in decimal)
Something isn't right here - 11010001 is present, dpl=2, type=10001. You'd want 10001001 (137 in decimal), which is present, dpl=0, type=01001.

Everything else is correct though :)


Cheers,

Brendan

Re:LTR and the TSS

Posted: Wed Sep 08, 2004 9:54 pm
by Brendan
Hi,
Neo wrote: What is this IO bitmap actually? how is it created (by us or predefined)? has anyone here used it?
The IO bitmap is used by the CPU to determine if a task is allowed to access an IO port when CPL > IOPL (or when the task wouldn't be allowed access to the IO port otherwise).

The IO bitmap is created by the OS/kernel/us. There's a bit for each IO port, so for all IO ports you'd need 8 kb, but you can have less in the IO bitmap (for e.g. with 128 bytes you could have 1024 IO ports). If the task can't access the IO port anyway (e.g. running in CPL0) then a clear bit will allow access to a specific IO port, and a set bit will result in a general protection fault (same as normal). If the IO bitmap is smaller than 8 KB then the CPU pretends that the missing/higher bits are set.

The start of the IO port bitmap is stored in the "IO port Bitmap Base Address" which is the last word in the TSS. The end of the IO port bitmap is determined by the limit in the TSS descriptor (in the GDT). So for 1024 IO ports you'd set the IO port Bitmap Base Address to 104, and the TSS descriptor limit to 231 (128+104-1).

I have used it (a long time ago). It's easier to use if you also use hardware task switching. With software task switching you can dynamically change the IO port bitmap each time you switch tasks, or you can simulate the IO port bitmap in the general protection fault handler (without using any IO port bitmaps).

I'm using simulation (the general protection fault handler) because I don't want to copy the IO bitmap each task switch (most tasks don't use IO ports anyway). This also allows me to protect certain things in some IO ports - for e.g. preventing the keyboard driver from resetting the system or disabling gateA20 even though it does have access to IO ports 0x60 and 0x64.


Cheers,

Brendan

Re:LTR and the TSS

Posted: Wed Sep 08, 2004 10:20 pm
by stonedzealot
D'Oh, I got a little confused with the endian, I think. I'd set the type to 9 though? Hmmm, I'll give it a whirl

Re:LTR and the TSS

Posted: Wed Sep 08, 2004 10:33 pm
by Dreamsmith
Neo wrote:has anyone here used it?
My kernel uses it in one place -- the TSS for the Virtual-8086 task I use for making BIOS calls. Allowing the BIOS to just use the I/O ports as desired is a lot easier and faster than implementing I/O instruction support in the V86 monitor. I just follow the 104 bytes of the TSS with 8192 0x00 bytes, and one 0xFF byte, giving the BIOS full access to I/O despite running in ring-3. The extra 0xFF byte is required to work around a bug in some processors -- when trying to access the last byte of your I/O bitmap, they may read that and the byte after it -- if your I/O bitmap ends without the pad byte, Bad Things happen. :P

Re:LTR and the TSS

Posted: Thu Sep 09, 2004 4:38 am
by Pype.Clicker
another trick that can be used to allow the iobitmap to be used when software task switchin' is in place consist of placing the IO bitmap on a page-start boundary and giving each process another content for that page ... this way, when switching address space, you automatcially switch IO bitmap ...

Re:LTR and the TSS

Posted: Thu Sep 09, 2004 4:39 pm
by Dreamsmith
Pype.Clicker wrote:another trick that can be used to allow the iobitmap to be used when software task switchin' is in place consist of placing the IO bitmap on a page-start boundary and giving each process another content for that page ... this way, when switching address space, you automatcially switch IO bitmap ...
Oooo... clever...

Re:LTR and the TSS

Posted: Fri Sep 10, 2004 5:32 am
by Pype.Clicker
that was a suggestion of someone else here :) Note that Intel states somewhere that only *one* page check will be performed when loading a TSS and that if the OS doesn't align the TSS on a page boundary, it should make sure that any PF caught for the lowest part of the TSS loads *all* the TSS :)