免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3690 | 回复: 7
打印 上一主题 下一主题

LDT的使用是每个进程一个吗? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-02 14:10 |只看该作者 |倒序浏览
LDT的理解搞糊涂了,是每个进程创建一个,还是共享一个?
或者不需要等

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
2 [报告]
发表于 2009-12-02 16:35 |只看该作者
Intel手册中说的是每个进程一个
而Kernel中没有使用LDT(或者是用了,但这个情况比较少)
《Linux内核源代码情景分析》中有类似描述,看2.2节 存储管理

论坛徽章:
0
3 [报告]
发表于 2009-12-02 17:57 |只看该作者
原帖由 Germin 于 2009-12-2 14:10 发表
LDT的理解搞糊涂了,是每个进程创建一个,还是共享一个?
或者不需要等


这个完全看你OS怎么实现了
有些OS是充分利用了LDT的。

论坛徽章:
2
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:57:09
4 [报告]
发表于 2009-12-02 18:31 |只看该作者

回复 #1 Germin 的帖子

现在的linux内核除了一些特别的进程外,是所有进程共用gdt里面的一个LDT。单独拥有IDT的最出名的进程就是wine了!

论坛徽章:
0
5 [报告]
发表于 2009-12-03 14:07 |只看该作者
原帖由 new_learner 于 2009-12-2 17:57 发表


这个完全看你OS怎么实现了
有些OS是充分利用了LDT的。


是不是windows充分利用了LDT,linux是共享默认的

论坛徽章:
0
6 [报告]
发表于 2009-12-03 19:03 |只看该作者
原帖由 Germin 于 2009-12-3 14:07 发表


是不是windows充分利用了LDT,linux是共享默认的

windows我不知道,
linux的你可以看看ulk

论坛徽章:
0
7 [报告]
发表于 2009-12-08 17:49 |只看该作者
看下代码吧:

  1. #define __KERNEL_CS        (GDT_ENTRY_KERNEL_CS * 8)
  2. #define __KERNEL_DS        (GDT_ENTRY_KERNEL_DS * 8)
  3. #define __USER_DS     (GDT_ENTRY_DEFAULT_USER_DS* 8 + 3)
  4. #define __USER_CS     (GDT_ENTRY_DEFAULT_USER_CS* 8 + 3)

  5. #define GDT_ENTRY_KERNEL_CS                (GDT_ENTRY_KERNEL_BASE + 0)
  6. #define GDT_ENTRY_KERNEL_DS                (GDT_ENTRY_KERNEL_BASE + 1)

  7. #define GDT_ENTRY_KERNEL_BASE        12

  8. #define GDT_ENTRY_DEFAULT_USER_CS        14
  9. #define GDT_ENTRY_DEFAULT_USER_DS        15
复制代码


所以换算出来就是:


  1. __KERNEL_CS == 1100000
  2. __KERNEL_DS == 1101000
  3. __USER_CS     == 1110011
  4. __USER_DS    ==  1111011
复制代码


由此可以看出,这四个Segment Selector的从低到高第2位(从0计数)的值都是0,所以都指向GDT,所以说明LINUX并没有使用LDT(通常情况下)。

但是ULK中提到了GDT里确实有一个segment descriptor是用于LDT的:
Most Linux User Mode applications do not make use of a Local Descriptor Table, thus the kernel defines a default LDT to be shared by most processes. The default Local Descriptor Table is stored in the default_ldt array. It includes five entries, but only two of them are effectively used by the kernel: a call gate for iBCS executables, and a call gate for Solaris /x86 executables (see the section "Execution Domains" in Chapter 20). Call gates are a mechanism provided by 80 x 86 microprocessors to change the privilege level of the CPU while invoking a predefined function; as we won't discuss them further, you should consult the Intel documentation for more details.

这是特殊情况,一般用不到。

另外,正如楼上有人说到的一样,有的进程会用到自己的own LDT
In some cases, however, processes may require to set up their own LDT. This turns out to be useful to applications (such as Wine) that execute segment-oriented Microsoft Windows applications. The modify_ldt( ) system call allows a process to do this.

Any custom LDT created by modify_ldt( ) also requires its own segment. When a processor starts executing a process having a custom LDT, the LDT entry in the CPU-specific copy of the GDT is changed accordingly.

User Mode applications also may allocate new segments by means of modify_ldt( ); the kernel, however, never makes use of these segments, and it does not have to keep track of the corresponding Segment Descriptors, because they are included in the custom LDT of the process.

这里的wine就是其中的例子。

不过这仅仅是Linux,其他OS不一定是这样用的。Linux这样用的目的有两个:

1. Memory management is simpler when all processes use the same segment register values that is, when they share the same set of linear addresses.

2. One of the design objectives of Linux is portability to a wide range of architectures; RISC architectures in particular have limited support for segmentation.

因为Linux是一个通用的OS,所以要照顾各种硬件的感受,虽然Linux是从X86起家的,不过由此可见Linus当年写雏形的时候就已经处心积虑要扩大Linux的硬件范围了。(我瞎说的,我不知道早期的Linux是不是这样设计的)。
我们公司自己也开发了一套基于INTEL的OS, 却是完全基于LDT来的,从某种意义上说,如果Intel哪天不生产X86了,我们公司就麻烦了。。。(我也是瞎说的,因为我不知道其他CPU是不是也用这种CPU模型)。

[ 本帖最后由 new_learner 于 2009-12-8 17:53 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2009-12-09 19:48 |只看该作者
__thread会用到, 不过LDT对程序员是透明的(如果不需要可移植, 如果__thread可用,对多线程来说是非常好用的)


http://lwn.net/Articles/5851/


[announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28
From:                 Ingo Molnar <mingo@elte.hu>
To:                 linux-kernel@vger.kernel.org
Subject:                 [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28
Date:                 Thu, 25 Jul 2002 19:35:34 +0200 (CEST)
Cc:                 Linus Torvalds <torvalds@transmeta.com>, Ulrich Drepper <drepper@redhat.com>, Richard Henderson <rth@redhat.com>

the following patch implements proper x86 TLS support in the Linux kernel,
via a new system-call, sys_set_thread_area():

   http://redhat.com/~mingo/tls-patches/tls-2.5.28-C6

a TLS test utility can be downloaded from:

    http://redhat.com/~mingo/tls-patches/tls_test.c

what is TLS? Thread Local Storage is a concept used by threading
abstractions - fast an efficient way to store per-thread local (but not
on-stack local) data. The __thread extension is already supported by gcc.

proper TLS support in compilers (and glibc/pthreads) is a bit problematic
on the x86 platform. There's only 8 general purpose registers available,
so on x86 we have to use segments to access the TLS. The approach used by
glibc so far was to set up a per-thread LDT entry to describe the TLS.
Besides the generic unrobustness of LDTs, this also introduced a limit:
the maximum number of LDT entries is 8192, so the maximum number of
threads per application is 8192.

this patch does it differently - the kernel keeps a specific per-thread
GDT entry that can be set up and modified by each thread:

     asmlinkage int sys_set_thread_area(unsigned int base,
               unsigned int limit, unsigned int flags)

the kernel, upon context-switch, modifies this GDT entry to match that of
the thread's TLS setting. This way user-space threaded code can access
per-thread data via this descriptor - by using the same, constant %gs (or
%gs) selector. The number of TLS areas is unlimited, and there is no
additional allocation overhead associated with TLS support.


the biggest problem preventing the introduction of this concept was
Linux's global shared GDT on SMP systems. The patch fixes this by
implementing a per-CPU GDT, which is also a nice context-switch speedup,
2-task lat_ctx context-switching got faster by about 5% on a dual Celeron
testbox. [ Could it be that a shared GDT is fundamentally suboptimal on
SMP? perhaps updating the 'accessed' bit in the DS/CS descriptors causes
some sort locked memory cycle overhead? ]

the GDT layout got simplified:

*   0 - null
*   1 - Thread-Local Storage (TLS) segment
*   2 - kernel code segment
*   3 - kernel data segment
*   4 - user code segment              <==== new cacheline
*   5 - user data segment
*   6 - TSS
*   7 - LDT
*   8 - APM BIOS support               <==== new cacheline
*   9 - APM BIOS support
*  10 - APM BIOS support
*  11 - APM BIOS support
*  12 - PNPBIOS support                <==== new cacheline
*  13 - PNPBIOS support
*  14 - PNPBIOS support
*  15 - PNPBIOS support
*  16 - PNPBIOS support                <==== new cacheline
*  17 - not used
*  18 - not used
*  19 - not used

set_thread_area() currently recognizes the following flags:

  #define TLS_FLAG_LIMIT_IN_PAGES         0x00000001
  #define TLS_FLAG_WRITABLE               0x00000002
  #define TLS_FLAG_CLEAR                  0x00000004

- in theory we could avoid the 'limit in pages' bit, but i wanted to
  preserve the flexibility to potentially enable the setting of
  byte-granularity stack segments for example. And unlimited segments
  (granularity = pages, limit = 0xfffff) might have a performance
  advantage on some CPUs. We could also automatically figure out the best
  possible granularity for a given limit - but i wanted to avoid this kind
  of guesswork. Some CPUs might have a plus for page-limit segments - who
  knows.

- The 'writable' flag is straightforward and could be useful to some
  applications.

- The 'clear' flag clears the TLS. [note that a base 0 limit 0 TLS is in
  fact legal, it's a single-byte segment at address 0.]

(the system-call does not expose any other segment options to user-space,
priviledge level is 3, the segment is 32-bit, etc. - it's using safe and
sane defaults.)

NOTE: the interface does not allow the changing of the TLS of another
thread on purpose - that would just complicate the interface (and
implementation) unnecesserily. Is there any good reason to allow the
setting of another thread's TLS?

NOTE2: non-pthreads glibc applications can call set_thread_area() to set
up a GDT entry just below the end of stack. We could use some sort of
default TLS area as well, but that would hard-code a given segment.

i fixed a number of unclean items in our GDT/IDT handling as well:

- the 'gdt' pointer is completely unnecessery, it introduces an
   additional redirection.

- ditto the 'idt' pointer.

- this also enabled simpler setting of the GDT/IDT descriptors.

- on UP the GDT got smaller in fact, by a few bytes

- cleaned up LDT loading: load_LDT_desc() now loads the (constant) LDT
   selector. A pity that we have to do this - but it's necessery to flush
   the LDT shadow descriptors.

- the thread context-switching hotpath included a call to a non-inlined
   function - set_ldt_desc() - this function is inlined now.

the patch compiles, boots & works just fine on UP and SMP x86 boxes.  
Comments and suggestions are welcome,

        Ingo
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP