内核空间的地址映射:
物理地址和虚拟地址之间相差0XC0000000
虚拟地址 –0XC0000000 ==物理地址
物理地址 +0XC0000000 ==虚拟地址
并且内核的页面不交换,不进行换出到磁盘中。因为内核要随时准备服务。
Inter X86 32 cpu linux kernel
实模式:
CPU一上电强制进去实模式,只能访问2^20==1M的内存且没有程序间隔离,没有内存的读写保护,内存的越界保护。
Intel在8086中设置了4个寄存器:
CS(代码段寄存器),DS(数据段寄存器),SS(堆栈段寄存器),ES(扩展段寄存器)
每个段寄存器都是16位,对应每个段的起始地址的高16位。这是由于物理地址被划分成一段一段的,每个内存段都是16的整数倍,即在20位的地址中,低四位全为0,没有必要存储,所以只用这四个寄存器来保存相应物理地址的高16位。
因此,实模式下地址映射表达式为:(假如寻找数据的真实物理地址)
DS<<4 + IP = 物理地址
DS<<4得到真实的20位段基地址(左移四位相当于*16),加上IP寄存器存放的偏移量(逻辑地址),就可以找到数据所存放的位置,这里的数据地址为物理地址。因此,在实模式下,可以直接通过修改段寄存器的内容访问内存中的任何一个地址单元,不受任何权限控制,没有保护措施
内核的代码加载从0X100000(1M)的地址之后开始加载,前1M存放BIOS代码和其他重要的内核引导代码。
保护模式:
Inter 80386的32位CPU为讨论对象,由于Intel80386芯片要兼容以前设计,保留以前16位的段寄存器,同时又增添了两个新的寄存器:FS和GS。设计的基本思路:设计一个数据结构,包含基地址,地址段长度及访问权限等信息,在保护模式下需要改变段寄存器的功能,把原来存放段基址的功能改变成存放一个数据结构的指针。
基本过程:
(1)根据指令的性质判断使用哪一个段寄存器;数据段则用DS寄存器
(2)在段寄存器中找到相应的数据结构;
(3)在此数据结构中找到段基地址;
(4)根据指令地址(偏移量)和地址段大小比较,判断是否越界;
(5)根据指令权限与数据结构中的权限对比,判断是否越权;
(6)段基址+指令地址得到物理地址。
实现过程:
增加了两个寄存器:
GDTR(global descriptortable register)全局的段描述表寄存器,所有进程所共享的.存放GDT在物理内存中的起始地址
LDTR(local descriptortable register)局部的段描述表寄存器,每个进程私有的,已经不使用。
16位段寄存器的高13位index存放GDT数组的下标索引。 2^13== 8k,已经有12项被内核系统预留下来,用户进程使用的有8K – 12==8192个全局或局部的段描述表项,它与GDTR或LDTR保存的其实地址相加才得到描述表项的起始地址。
第三位TI:0表示在GDT存,1表示LDT存
段寄存器的低两位RPL表示CPU的特权级00表示内核态,11表示用户态
段描述符表(GDT):在物理内存中保存,表中的每一项为8字节共64位,存放段基址,段大小和其他读写信息,具体结构如图所示:
起始地址32位:B31-B24,B23-B16,B15-B0
长度20位:L19-L16,L15-L0
长度单位G,为0代表单位为字节,为1时代表页面
保护模式下的地址映射:
内存的分段式映射:GDT[DS>>3].BaseAddr + IP寄存器 ===线性地址
注:假设要找数据段上的地址,故使用DS寄存器。GDTR保存了GDT的地址。BaseAddr: 保存在GDT表项中的B31-B24,B23-B16,B15-B0等位。IP寄存器保存了偏移量。
DS>>3取得GDTR表项的下标,GDTR[DS>>3].BaseAddr找到该表项的基地址,再加上逻辑地址,得到该数据的线性地址。此处不为物理地址是还要进行内存分页机制。
得到线性地址后:
如果内核没有开启线性地址的话:线性地址就是物理地址。
如果内核开启了分页机制线性地址就是虚拟地址。
虚拟地址经过多级的页表映射到物理地址,接下来是多级页表映射过程也叫内存的分页式映射。
CPU寄存器:
CR0:该寄存器的最高位PG位为1表示开启了内存分页,0没有开启
CR2:该寄存器访问发生缺页异常的虚拟地址
CR3: 该寄存器记录当前进程的页目录的起始地址
CR4: 该寄存器的PAE位,物理地址扩展。0表示未开启,1表示开启
内存的分页式映射:
32位需要二级页面映射1024*1024*4K=4G,36位三级页面映射,64位四级页面映射
上面过程得到的线性地址也叫32位虚拟地址0x0018ff44分成三份
CR3寄存器存放了当前进程的也目录表的起始地址
高10位保存了页目录中的下标,每个页目录项保存了页表的起始地址
中间10位保存了页表中的下标,每个页表项保存了物理地址的起始地址
低12位是在4K的物理页上的偏移量
分页式映射关系:
页目录PG[下标]==PT的首地址地址
页表PT[下标]==物理页的首地址其实也是一个数组下标
页表PT[下标]+低12位的偏移量==真实物理地址
因为页表PT首地址和物理页的起始地址都是4K的整数倍,所以二进制的后12位都是0不需要存,而在页目录中每项的低12位用来存权限。
在页表中的每项的低12位也是用来存权限,其中最低的一位是0表示物理页在交换分区中,如果是1则表示页面在物理内存中。
物理页面在内核中是用动态数组来管理的mem_map_t *mem_map;
页表中保存的就是这个数组的下标,物理页面的框号也是这个数组下标,4K整数倍的后12位都是0不需要保存,相互转换的话是通过移位运算。