the FS segment, thread local storage and ldt

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
sigler
Posts: 15
Joined: Wed Oct 31, 2007 11:37 am

the FS segment, thread local storage and ldt

Post by sigler »

Hello,

I was thinking about supporting thread local storage in my OS. I wanted to implement it like windows does it. It uses the fs segment register to point to some thread local data.

So the fs register must be set on each task switch.
The fs register is a segment, so must have an entry in the gdt ?

OR

Is this the time to introduce ldt's in my OS? I haven't understood them yet, not seen the use for them. Is this a case where they should be used?

--
Sigurd Lerstad
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

Are you intending to port to a 64-bit CPU at some point?
sigler
Posts: 15
Joined: Wed Oct 31, 2007 11:37 am

Post by sigler »

bewing wrote:Are you intending to port to a 64-bit CPU at some point?
I'll probably have both 32 and 64 bit versions.

please explain why you ask that question...

--
Sigurd Lerstad
User avatar
Combuster
Member
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:

Post by Combuster »

please explain why you ask that question...
The effects of FS change when in long mode - in 64-bit mode the contents of the segment registers are close to meaningless. The offset added when addressing using FS is taken from a Model-specific register.
In 'legacy' mode FS holds a segment selector, which loads a base and limit from the GDT or LDT.

The key difference is, in legacy modes you'll have to save FS as part of the thread's state, and record some sort of information in either the GDT or a LDT specific for the current process (or you could modify a GDT entry on the fly). If some program decides to reload FS, then it can, and the base it has will be lost.

In long mode, you'll have to change the FS MSR as part of a thread switch instead of FS itself.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
sigler wrote:So the fs register must be set on each task switch.
The fs register is a segment, so must have an entry in the gdt ?

OR

Is this the time to introduce ldt's in my OS? I haven't understood them yet, not seen the use for them. Is this a case where they should be used?
For 32-bit kernels, I'd consider having one GDT entry (per CPU) and changing the base and limit of that GDT entry during task switches (and reloading GS but not saving it). The idea is to use statically assigned GDT entries rather than having a "dynamic GDT/LDT manager" that needs to search for free GDT/LDT entries (and also needs to handle the "no free entries" condition).

One problem here is passing data to kernel API functions (and libraries). Imagine a kernel function like "int foo(char *bar)" - how does the kernel know if "bar" is a normal address or an address in thread local storage? Would the kernel function need to be something like "int foo(bool TLSflag, char *bar)", or would user space code need to do something like "result = foo( (void *)bar + TLSbase );"? Note: I'm not sure if expand down segments could be used to solve this or not.

There is another alternative - use paging for thread local storage. This has some advantages - it's impossible for one thread to access/corrupt data in another thread's local storage, you end up with more address space (e.g. if 32 threads use 64 MB of thread local storage each, then it only needs to consume 64 MB of the address space instead of 2048 MB), and there's no hassles passing data to kernel API functions (and libraries). It also has disadvantages - you either need to modify a shared page directory during thread switches (which becomes a nightmare for multi-CPU, where several threads that belong to the same process could be running at the same time on different CPUs) or maintain a seperate page directory for each thread (and ensure that "non-thread-local" pages are the same in all threads that belong to the process).


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
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

Combuster wrote: In long mode, you'll have to change the FS MSR as part of a thread switch instead of FS itself.
And AFAIK 64bit AMD CPUs do not support that MSR?
User avatar
Combuster
Member
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:

Post by Combuster »

And AFAIK 64bit AMD CPUs do not support that MSR?
The AMD Manual wrote:To allow loading all 64 bits of the base address, the FS.base and GS.base hidden descriptor-register fields are mapped to MSRs. Privileged software (CPL=0) can load the 64-bit base address into FS.base or GS.base using a single WRMSR instruction. The addresses written into the expanded FS.base and GS.base registers must be in canonical form. A WRMSR instruction that attempts to write a noncanonical address to these registers causes a general-protection exception (#GP) to occur.

The FS.base MSR address is C000_0100h while the GS.base MSR address is C000_0101h.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply