LTR and the TSS

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
stonedzealot

LTR and the TSS

Post 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.
Dreamsmith

Re:LTR and the TSS

Post 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.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:LTR and the TSS

Post 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 ?
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:LTR and the TSS

Post by Neo »

What do the base and segment limit in the TSS descriptor refer to? are they the same as the other GDT entries?
Only Human
Dreamsmith

Re:LTR and the TSS

Post 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).
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:LTR and the TSS

Post by Neo »

What is this IO bitmap actually? how is it created (by us or predefined)? has anyone here used it?
Only Human
stonedzealot

Re:LTR and the TSS

Post 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?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:LTR and the TSS

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:LTR and the TSS

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
stonedzealot

Re:LTR and the TSS

Post 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
Dreamsmith

Re:LTR and the TSS

Post 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
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:LTR and the TSS

Post 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 ...
Dreamsmith

Re:LTR and the TSS

Post 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...
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:LTR and the TSS

Post 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 :)
Post Reply