GDT e LDT

Hi,

I?m studying about the IA-32 and Windows. During my studies I faced some questions and after some research I conclude the following:

  1. Windows doesn?t use LDT, only GDT;

  2. The FS segment register in UM points to the TEB structure. I saw that every thread in a process have the same value for this segment register, so I conclude that GDT is stored by thread and not by process.

Am I going in the right direction?

Thanks in advance,

Regards,

-George

George Luiz Bittencourt wrote:

I´m studying about the IA-32 and Windows. During my studies I faced some questions and after some research I conclude the following:

  1. Windows doesn´t use LDT, only GDT;

Specifically, 32-bit and 64-bit processes in the NT-derived systems do
not use the LDT. 16-bit processes running in WOW use the LDT, as did
the 16-bit Windows systems (3.x, 95, 98, ME).

  1. The FS segment register in UM points to the TEB structure. I saw that every thread in a process have the same value for this segment register, so I conclude that GDT is stored by thread and not by process.

I guess that depends on how you look at it. On a thread switch, the
page table entries for the virtual address in FS are changed to point to
a different set of physical pages.

Am I going in the right direction?

I guess that depends on where you’re trying to go! This is rather
esoteric information.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> 1. Windows doesn?t use LDT, only GDT;

Correct…

The FS segment register in UM points to the TEB structure. I saw that every thread in a
process have the same value for this segment register,

Correct. UM FS points to TEB, and kernel-mode one point to Processor Control Block…

so I conclude that GDT is stored by thread and not by process.

Incorrect conclusion…

GDT is the same for everyone who happens to run on a given CPU - it is per-CPU table. What the system has to update is GDT *entry* pointed to by UM FS register. It does not have to do it for KM FS, because it points to PCR which, among other entries, stores a pointer to ETHREAD of currently running thread, so that it has to update PCR, rather than GDT…

Anton Bassov

>1. Windows doesn?t use LDT, only GDT;

LDT is used in 32bit Windows by NTVDM (DOS/Win16 virtual machine) to emulate the Win16’s segments.

  1. The FS segment register in UM points to the TEB structure.

Yes. fs:[00000000] is the list head of the exception handling frames (__SEH_Rec structures).

In kernel mode, FS segment points to _KPCR - Processor Control Region, which is actually the “processor object”. “Current thread” is one of the fields there, so is current IRQL.

I saw that every thread in a process have the same value for this segment register

This GDT entry is updated on each thread switch.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Now I understood, all the threads have the same value for the FS segment register. However when a context switch occurs the entry pointed by this segment register is changed. GDTR and the FS segment register keep its values.

Thanks Maxim, Anton and Tim!

-George

George Luiz Bittencourt wrote:

Now I understood, all the threads have the same value for the FS segment register. However when a context switch occurs the entry pointed by this segment register is changed. GDTR and the FS segment register keep its values.

Right. FS is 003B, the FS base is 7FFDF000 (on XP), but the physical
page that maps to varies by thread.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

No. fs is based at a different address on a per-thread basis. That is, fs for a different thread in the same process would point to a different flat address other than 7FFDF000. There is no per-thread physical page swapping going on for the TEB.

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Monday, December 01, 2008 2:15 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] GDT e LDT

George Luiz Bittencourt wrote:

Now I understood, all the threads have the same value for the FS segment register. However when a context switch occurs the entry pointed by this segment register is changed. GDTR and the FS segment register keep its values.

Right. FS is 003B, the FS base is 7FFDF000 (on XP), but the physical
page that maps to varies by thread.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Tim,

On a thread switch, the page table entries for the virtual address in FS are changed
to point to a different set of physical pages.

Well, it would be quite unreasonable approach even by Windows standards if it worked this way.
First of all, if it did, then every thread would require at least extra 4096 bytes, i.e. one physical page (plus one more page for page directory - more on it below) just in order to map GDT, while all GDT entries, apart from 0x30th, one are the same for all threads and processes.

FS is 003B, the FS base is 7FFDF000 (on XP), but the physical page that maps to varies by thread.

Now consider what happens when 2 threads of the same process run simultaneously on different CPUs, i.e. the same page directory is loaded into more than one CPU’s CR3 register at a time. The only possible way to avoid inconsistencies under these circumstances if it worked the way you have described would be giving every thread its own page directory, i.e. wasting yet another 4096 bytes per thread for no reason whatsoever.

Therefore, the OS just updates the 0x30th entry upon the context switch. If there are more than one thread in a process, each thread will have its own virtual address that FS[0x30] maps to - as Ken pointed out, UM FS is not always mapped to 0x7FFDF000. As a result, you eliminate the possibility of inconsistency if the same page directory is used by 2 or more CPUs at once.

As you can see, there is no need to allocate 2 pages at the time when all that you need is just 8 bytes…

Anton Bassov

xxxxx@hotmail.com wrote:

> On a thread switch, the page table entries for the virtual address in FS are changed
> to point to a different set of physical pages.
>

Well, it would be quite unreasonable approach even by Windows standards if it worked this way.
First of all, if it did, then every thread would require at least extra 4096 bytes, i.e. one physical page (plus one more page for page directory - more on it below) just in order to map GDT, while all GDT entries, apart from 0x30th, one are the same for all threads and processes.

Yes, the foolishness of my original statement has now been hammered home
quite sufficiently. A few moments additional thought would have
prevented much grief. I can only offer as an excuse my continued
anguish over the performance of my alma mater Oregon State Beavers on
Saturday.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> Well, it would be quite unreasonable approach even by Windows standards if it worked this way.

First of all, if it did, then every thread would require at least extra 4096 bytes, i.e. one physical page
(plus one more page for page directory - more on it below) just in order to map GDT, while all GDT
entries, apart from 0x30th, one are the same for all threads and processes.

Not so. The GDT is nonpaged and is per-CPU. The entries for the FS segment - both for user and kernel mode - are updated on each context switch on this CPU.

Now consider what happens when 2 threads of the same process run simultaneously on different
CPUs, i.e. the same page directory is loaded into more than one CPU’s CR3 register at a time.

This is really so. So what? each CPU has its own GDT.

have described would be giving every thread its own page directory

This is not done so.

Therefore, the OS just updates the 0x30th entry upon the context switch.

Yes.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

>> First of all, if it did, then every thread would require at least extra 4096 bytes, i.e. one physical page >>(plus one more page for page directory - more on it below) just in order to map GDT, while all GDT >>entries, apart from 0x30th, one are the same for all threads and processes.

The GDT is nonpaged and is per-CPU.

And??? Please note that you cannot make PTE describe less than a page. Therefore, if every page directory had its own copy of GDT that maps to the same virtual address but refers to different physical pages the way Tim originally described it (it can be done only via page directory and PTEs), you would have to waste a page of RAM for each page directory

The entries for the FS segment - both for user and kernel mode - are updated on each
context switch on this CPU.

What is the point of updating kernel FS which points to Processor Control Block, i.e. per-CPU structure that, apart from other things, keeps a pointer to ETHREAD of a thread that it currently executes??? The only thing it has to update is UM FS…

> Now consider what happens when 2 threads of the same process run simultaneously on different >>CPUs, i.e. the same page directory is loaded into more than one CPU’s CR3 register at a time.

This is really so. So what? each CPU has its own GDT.

Imagine what happens if all threads have TEB at the same virtual address under these circumstances - you would have to give every thread its own page directory in order to avoid collisions and sharing violations…

>have described would be giving every thread its own page directory

This is not done so.

Of course not - what is the point of wasting memory for nothing??? However, in order to do things the way Tim originally described you would need page directory for every thread, plus an extra page that
describes GDT, which would be pretty unwise approach…

Anton Bassov