Linux内核采用页式存储管理。虚拟地址空间划分成固定大小的“页面”,由MMU在运行时将虚拟地址“映射”成(或者说变换成)某个物理内存页面中的地址。与段式存储管理相比,页式存储管理有很多好处。首先,页面都是固定大小的,便于管理。更重要的是,当要将一部分物理空间中的内容换出到磁盘上的时候,在段式存储管理中要将整个段(通常都很大)都换出,而在页式存储管理中则是按页进行,效率显然要高得多。页式存储管理与段式存储管理所要求的硬件支持不同,一种CPU既然支持页式存储管理,就无需再支持段式存储管理。但是,i386的情况是特殊的。由于i386系列的历史演变过程,它对页式存储管理的支持是在其段式存储管理已经存在了相当长的时间以后才发展起来的。所以,不管程序是怎样写的,i386 CPU一律对程序中使用的地址先进行段式映射,然后才能进行页式映射。既然CPU的硬件结构是这样,Linux内核也只好服从Intel的选择。这样的双重映射其实是毫无必要的,也使映射的过程变得不容易理解,以至有人还得出了Linux采用“段页式”存储管理技术这样一种似是而非的结论。Linux内核所采取的办法是使段式映射的过程实际上不起作用(除特殊的VM86模式外,那是用来模拟80286的)。
Linux内核中只使用四种不同的段寄存器数值,两种用于内核本身,两种用于所有的进程:
-----------------------------------------------------------
__KERNEL_CS 0x10 0 0 0 0 0 0 0 0 0 0 0 1 0 | 0 | 0 0
__KERNEL_DS 0x18 0 0 0 0 0 0 0 0 0 0 0 1 1 | 0 | 0 0
__USER_CS 0x23 0 0 0 0 0 0 0 0 0 0 1 0 0 | 0 | 1 1
__USER_DS 0x28 0 0 0 0 0 0 0 0 0 0 1 0 1 | 0 | 1 1
-----------------------------------------------------------
按照Intel对段寄存器的定义我们可以看出这四个段地址描述符都使用GDT表,再结合linux初始化时设置的GDT表的内容(全局段地址描述符表)我们可以知道他们所描述的段都是从0地址到4GB的整个32位地址空间,也就是说经过这些段地址描述符映射后的地址与映射前保持原值不变。所以说实际上Linux根本没有使用80386以上CPU所提供的段式存储管理机制。
Linux内核中只使用四种不同的段寄存器数值,两种用于内核本身,两种用于所有的进程:
-----------------------------------------------------------
__KERNEL_CS 0x10 0 0 0 0 0 0 0 0 0 0 0 1 0 | 0 | 0 0
__KERNEL_DS 0x18 0 0 0 0 0 0 0 0 0 0 0 1 1 | 0 | 0 0
__USER_CS 0x23 0 0 0 0 0 0 0 0 0 0 1 0 0 | 0 | 1 1
__USER_DS 0x28 0 0 0 0 0 0 0 0 0 0 1 0 1 | 0 | 1 1
-----------------------------------------------------------
按照Intel对段寄存器的定义我们可以看出这四个段地址描述符都使用GDT表,再结合linux初始化时设置的GDT表的内容(全局段地址描述符表)我们可以知道他们所描述的段都是从0地址到4GB的整个32位地址空间,也就是说经过这些段地址描述符映射后的地址与映射前保持原值不变。所以说实际上Linux根本没有使用80386以上CPU所提供的段式存储管理机制。
它们之间的唯一区别就是内核态的优先级是0,而用户态的优先级是3。
至于windows:
windows只靠分页来隔离的
windows下虚拟地址=线性地址
windows下的CS,DS对应的段描述符实际指向的是同一个段(就一个4G的平坦段),只是使用了别名技术,顺便规定了访问权限
来源:
http://bbs.pediy.com/archive/index.php?t-77889.html
http://zhidao.baidu.com/link?url=vwmKmF1zrBd7vy3zzPUg_ipkoCUc-Qq3OX6MlrjzeIdEkN2dD1cUq6PqmRBFjUz78TbudTMOl0McuU3vM--Ei_