以下内容都是我阅读《从x86实模式到保护模式》一书的总结笔记,大约在11章~13章,主要记录一下有关GDT的内容。
GDT的引入
在实模式下最大可以访问1M大小的地址,进入保护模式后,由于需要内存保护,必须一五一十的记录段的权限–哪个段是系统级别的权限,哪个段时应用级别的权限,这样就可以使得系统可以对所有硬件进行直接访问,限定应用程序对硬件的直接访问,以免怀有恶意的应用程序对计算机破坏。
负责记录段权限的就是GDT,全称全局描述符表,它由64位比特组成,也就是两个字,下图是GDT的示意图
- Base:段的基地址,由一个字大小组成,意味着它可以是保护模式下4G内存中任意一个地址。
- Limit 和 G:Limit 是段的大小范围也叫段界限,由20个比特组成,也就是1M大小,G是段界限的单位。另外,如果G位为0就以字节为单位,如果为1就以4KB为单位。假设G位为0,那么
Limit+1
是多少,此段大小就为多少字节,范围为1B~1M
;设G位位1,那么此段大小为(Limit+1)*4KB
大小,范围为4KB~4G
。
- P:存在标志位,为0就说明段不存在内存中,为1就存在内存中。这里可以引发一个中断,当CPU检查到这一位为0,后面指令又要使用此段的时候,可以引发一个缺段中断,然后跳转到加载段的中断程序以加载此段到内存中。
- DPL: 此段的特权等级,由两位比特组成,最高特权等级为00,最低特权等级为11,一共有三个特权等级。
- S 和 TYPE: S 位用于指定描述符的类型。当该位是0时,表示是一个系统段;为“1时,表示是一个代码段或者数据段(栈段也是特殊的数据段)。当S为1时,也就是为代码段或数据段时,TYPE的情况如下:
也就是说,X为0时候就是数据段,X为1时候就是代码段,而关于依从的概念是关系到切换任务时候特权的更变的,后面再说。当S为0时也就是此段是一个系统段,而系统段也有好几种,TYPE里所代表的就是系统段的种类。(目前据我所知,TYPE是0010的为 LDT描述符、是1011或1001的为TSS描述符、是1100的为调用门描述符等) - D/B:默认的操作数大小或者默认的栈指针大小,该标志位主要是为了能够在32位处理器上兼容运行16 位保护模式的程序。该标志位对不同的段有不同的效果。对于代码段,此位为D位,用于指示指令中默认的偏移地址和操作数尺寸。D=0 表示指令中的偏移地址或者操作数是16 位的;D=1,指示32 位的偏移地址或者操作数。对于数据段,此位为B位…
- L:是64 位代码段标志,保留此位给64位处理器使用。如果还是32位保护模式,我们将此位置0即可。
- AVL:此位是保留位,留给操作系统用的,用也可以不用也可以。
段界限
这里重点关注一下段界限,有两点:
- 段界限的计算
- 栈段界限和栈的范围
段界限的计算
有一点需要注意段界限在数值上,是比实际大小少1的,为什么呢?比如内存单元的0~7
,这里的0也是可以作为一个内存单元的,因此0~7
实际的大小为8比特,而不是7比特。
实际段界限值 = (描述符中段界限值+1)*(段界限的颗粒大小:4KB或1B)-1
实际段界限值 = 0xffffffff或0xffff(段界限的颗粒大小:4KB或1B) - 需要设置的栈的大小
这里假设描述符中段界限值为0xFFFFF
G为0,颗粒大小为1字节,根据公式实际段界限值就是描述符中段界限值
G为1,颗粒大小为4KB字节,实际段界限值=0x100000*0x1000-1=0xFFFFFFFF
4KB=4*1024B=4096B
4096为十进制
4096B的十六进制为1000
栈段界限与栈的范围
我当时也一脸懵逼,但是后来慢慢理解上了。
普通的数据段,偏移量是从0x00000000
开始,一直到段界限值,因为数据段是向上增长的,是增加的;而作为栈的数据段就不一样了,栈是向下减少的,方向和数据段相反,所以偏移量的起点应该也要相反,也就是说偏移量应该是从0xFFFFFFFF
开始,一直减少到段界限值。
总的来说,数据段的范围为:0x00000000
~ Limit
,栈段的范围为:0xFFFFFFFF
~ Limit
而栈基址的作用是啥?我认为是一种定位的作用,比如我设置一个栈段界限为0xFFFFE
,栈段基地址为0x7c00
,会发生什么呢?看下图就懂了:
原本栈段基地址为0时候,栈段范围为0xFFFFFF
~ 0xFFFFEFFF
,有了基地址,两头分别加上栈段基地址0x7c00
,由于底部和顶部两端是相连的(0xFFFFFF + 1 = 0x000000),所以栈段的范围变成了0x00006C00~0x00007BFF
而关于ESP的值的问题,原本不加栈段基地址设置为0,那就可以自动从0落到0xFFFFFF
~ 0xFFFFEFFF
范围,如果加了栈段基地址,就会落到0x00006C00~0x00007BFF
范围里。
一旦CPU访问此栈段时候,实际访问的物理地址超过0x00006C00~0x00007BFF
这个范围,就会触发异常中断,以保护其他段的数据安全。
有关GDT的第一部分完成,第二部分是有关保护模式下的特权保护相关内容,会记录一下选择子的笔记,也就是GDT里的DPL以及CPL,还有选择子的RPL
你或许也想写一个简单的操作系统,没错我也是,欢迎来一起讨论操作系统相关问题,这是我的QQ:2197651308