(转)“段寄存器”的故事

转载自:http://blog.csdn.net/michael2012zhao/article/details/17421383

一、 段寄存器的产生

段寄存器的产生源于Intel 8086 CPU体系结构中数据总线与地址总线的宽度不一致。

数据总线的宽度,也即是ALU(算数逻辑单元)的宽度,平常说一个CPU是“16位”或者“32位”指的就是这个。8086CPU的数据总线是16位。

地址总线的宽度不一定要与ALU的宽度相同。因为ALU的宽度是固定的,它受限于当时的工艺水平,当时只能制造出16位的ALU;但地址总线不一样,它可以设计得更宽。地址总线的宽度如果与ALU相同当然是不错的办法,这样CPU的结构比较均衡,寻址可以在单个指令周期内完成,效率最高;而且从软件的解决来看,一个变量地址的长度可以用整型或者长整型来表示会比较方便。

但是,地址总线的宽度还要受制于需求,因为地址总线的宽度决定了系统可寻址的范围,即可以支持多少内存。如果地址总线太窄的话,可寻址范围会很小。如果地址总线设计为16位的话,可寻址空间是2^16=64KB,这在当时被认为是不够的;Intel最终决定要让8086的地址空间为1M,也就是20位地址总线。

地址总线宽度大于数据总线会带来一些麻烦,ALU无法在单个指令周期里完成对地址数据的运算。有一些容易想到的可行的办法,比如定义一个新的寄存器专门用于存放地址的高4位,但这样增加了计算的复杂性,程序员要增加成倍的汇编代码来操作地址数据而且无法保持兼容性。

Intel想到了一个折中的办法:把内存分段,并设计了4个段寄存器,CS,DS,ES和SS,分别用于指令、数据、其它和堆栈。把内存分为很多段,每一段有一个段基址,当然段基址也是一个20位的内存地址。不过段寄存器仍然是16位的,它的内容代表了段基址的高16位,这个16位的地址后面再加上4个0就构成20位的段基址。而原来的16位地址只是段内的偏移量。这样,一个完整的物理内存地址就由两部分组成,高16位的段基址和低16位的段内偏移量,当然它们有12位是重叠的,它们两部分相加在一起,才构成完整的物理地址。

|    Base      |    b15 ~ b12    |    b11 ~ b0    |                |
|    Offset    |                 |    o15 ~ o4    |    o3 ~ o0     |
|    Address   |                      a19 ~ a0                     |

这种寻址模式也就是“实地址模式”。在8086中,段寄存器还只是一个单纯的16位寄存器,而且操作寄存器的指令也不是特权指令。通过设置段寄存器和段内偏移,程序就可以访问整个物理内存,无安全性可言。

总之一句话,段寄存器的设计是一个权宜之计,现在看来可以说是一个临时性的解决方案,设计它的目的是为了把地址空间从64KB扩展为1MB,仅此而已。但是它的加入却为日后Intel系列芯片的发展带来诸多不便,也为理解i386体系带来困扰。

二、 实现保护模式

到了80386问世的时候,工艺已经有了很大的进步,386的ALU有已经从16位跃升为32位,也就是说,38086是32位的CPU,而且结构也已经比较成熟,接下来的80486一直到Pentium系列虽然速度提高了几个数量级,但并没有质的变化,所以被统称为i386结构。

对于32位的CPU来说,只要地址总线宽度与数据总线宽度相同,就可以寻址2^32=4GB的内存空间,这已经足够用,已经不再需要段寄存器来帮助扩展。但这时Intel已经无法把段寄存器从产品中去掉,因为新的CPU也是产品系列中的一员,根据兼容性的需要,段寄存器必须保留下来。

这时,技术的发展需求Intel在其CPU中实现“保护模式”,用户程序的可访问内存范围必须受到限制,不能再任意地访问内存所有地址。Intel决定利用段寄存器来实现他们的保护模式,把保护模式建立在段寄存器的基础之上。

对于段的描述不再只是一个20位的起始地址,而是全新地定义了“段描述项”。段描述项的结构如下:

|    B31 ~ B24     |    DES1 (4 bit)    |    L19 ~ L16    |
|    DES2 (8 bit)  |                 B23 ~ B16            |
|                       B15 ~ B0                          |
|                       L15 ~ L0                          |

每一行是两个字节,总共8个字节,64位。

DES1和DES2分别是一些描述信息,用于描述本段是数据段还是代码段,以及读写权限等等。B0B31是段的基地址,L0L19是段的长度。

注意,规定段的长度是非常必要的,如果不限定段长度,“保护”就无从谈起,用户程序的访问至少不能超过段的范围。另外,段长度只有20位,所代表的最大可能长度为220=1M,而整个地址空间是232=4GB,这样来看,段的长度是不是太短了?其实,在DES1中,有一位用于表示段长度的单位,当它被置1时(一般情况下都是如此),表示长度单位为4KB,这样,一个段的最大可能尺寸就成了1M*4K=4G,与地址空间相稳合。4KB也正是一个内存页的大小,说明段的大小也是向页对齐的。

另外,注意到一个有趣的现象吗?段描述项的结构被设计得不连续,不论是段基地址还是段长度,都被分成了两节表示。这样的设计与80286的过渡有关。上面的段描述项结构去掉第一行后剩下的三行正是286的段描述项。286被设计为24位地址总线,所以段基址是24位,相应地段长是16位。在386的地址总线扩展为32位之后,还必须兼容286产品的设计,所以只好在段描述项上“打补丁”。

在386中,段寄存器还是16位,那么16位的段寄存器如何存放得下64位的段描述项? 段描述项不再由段寄存器直接持有。段描述项存放在内存里,系统中可以有很多个段描述项,这些项连续存放,共同构成一张表,16位的段寄存器里只是含有这张表里的一个索引,但也并不仅是一个简单的序号,而是存储了一种数据结构,这种结构的定义如下:

|    index (b15 ~ b3)    |    TI (b2)    |    RPL (b1 ~ b0)    |

其中index是段描述表的索引,它指向其中的某一个段描述项。RPL表示权限,00最高,11最低。

还有一个关键的问题,内存中的段描述表的起始地址在哪里?显然光有索引是有不够的。为此,Intel又设计了两个新的寄存器:GDTR(global descriptor table register)和LDTR(local descriptor table register),分别用来存储段描述表的地址。段寄存器中的TI位正是用于指示使用GDTR还是LDTR。

当用户程序要求访问内存时,CPU根据指令的性质确定使用哪个段寄存器,转移指令中的地址在代码段,取数指令中的地址在数据段;根据段寄存器中的索引值,找到段描述项,取得段基址;指令中的地址是段内偏移,与段长比较,确保没有越界;检查权限;把段基址和偏移相加,构成物理地址,取得数据。

新的设计中处处有权限与范围的限制,用户程序只能访问被授权的内存空间,从而实现了保护机制。就这样,在段寄存器的基础上,Intel实现了自己的“保护模式”。

三、 与页式存管并存

现代操作系统的发展要求CPU支持页式存储管理。

页式存管本身是与段式存管分立的,两者没有什么关系。但对于Intel来说,同样是由于“段寄存器”这个历史的原因,它必须把页式存管建立在段式存管的基础之上,尽管这从设计的角度来说这是没有道理,也根本没有必要的。

在段式存管中,由程序发出的变量地址经映射(段基址+段内偏移)之后,得到的32位地址就是一个物理地址,是可以直接放到地址总线是去取数的。

在页式存管中,过程也是相似的,由程序发出的变量地址并不是实际的物理地址,而是一个三层的索引结构,这个地址经过一系统的映射之后才可以得到物理地址。

现在对于Intel CPU来说,以上两个映射过程就要先后各做一次。由程序发出的变量地址称为“逻辑地址”,先经过段式映射成为“线性地址”,线性地址再做为页式映射的输入,最后得到“物理地址”。

Linux内核实现了页式存储管理,而且并没有因为两层存管的映射而变得更复杂。Linux更关注页式内存管理,对于段式映射,采用了特殊的方式把它简化。让每个段寄存器都指向同一个段描述项,即只设了一个段,而这个段的基地址为0,段长度设为最大值4G,这个段就与整个物理内存相重合,逻辑地址经映射之后就与线性地址相同,从而把段式存管变成“透明”的。

这,就是Intel处理器中“段寄存器”的故事。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容