保护模式下可以对内存进行任意分配,只要将分配好的内存信息传送值段描述符即可。
例如:段描述符的填充:填充一个数据段描述符和一个代码段描述符,每个段大小为8M。
则段界限为8M=1024*1024*8即2的23次方字节,800000H。而段界限只有20位,因此用段界限公式进行换算:limit*4k+0FFFH=段界限。将800000H代入公式,则limit应该写入的是7FFH,剩下的位则用0填充。
而段属性的填写,则是按照自己写保护模式下的操作系统的要求进行属性填写:
type为数据段并可读可写,因此为010;
DT为1,是存储段;
DPL为00,作为操作系统是最高特权级别;
P为1,该段描述符所描述的可以转换为物理地址;
limit为0000,多余的limit填充为0;
AVl:作为保留0值;
D:1,4GB数据段。
G:保护模式下则为1
因此属性部分就为1100 0000 1001 0010
而在汇编中对段描述符进行初始化的语句为:
dw 07FFH;segment limit 初始化
dw 0H
db 0H;对segment base3个部分置零
db 10010010
db 11000000
db oH
三、代码实现
1、gdt_table:为段描述符表
2、intel规定段描述符表的第一个描述符必须是空描述符,即全部填充为0,共8个字节。
3、CPU取得段描述符表的地址及长度是用的专门保存描述符表的48位寄存器,为GDT寄存器。
GDTR寄存器如下图:
CPU只要读取GDTR寄存器中的内容就是读到了段描述符的内容。
CPU读取段描述符表使用lgdt指令,就是将段描述符表中的内容存入GDTR寄存器中,指令格式如下:lgdt 【描述表地址】
四、A20地址线
由于8086有20根地址线,只能访问大小为1M的地址空间,因此如果访问的空间大于1M,则会出现地址回绕现象。而80386是完全兼容8086的,而8086中又有很多程序是根据地指回绕编写的,也就是说,要想在80386中完全实现8086的功能,也要在访问大于1M地址内容是同样出现地址回绕的现象。
但80386有32根地址线,因此只使用低20位来模拟8086,于是用0000 0000 0000 1111 1111 1111 1111 1111来与地址进行相与,将高12位清零,低20位不变。
而当时的80386CPU上8042键盘控制器上恰好有空闲引脚A20,来做为与门进行兼容性控制,因此叫做A20地址线。
但由于键盘控制其速度跟不上CPU速度,于是引入了A20快速门选项,后来又使用I/O端口0X92来处理A20地址线,避免慢速键盘。