- 论坛徽章:
- 2
|
第2章
2.2节需要理解的点:
*页式存储管理相对于段式存储管理的好处:大小固定,方便管理;换出到磁盘时,提高效率
*i386既有段式存管,又有页式存管,是因为他在支持页式的时候,段式已经存在相当长时间了,为了保留已有资源,Linux内核作为软件要面对他,也只能跟着多此一举,只能“服从”,实际上是“欺骗”
*通过“Hello world!\n”程序熟悉地址映射全过程
a. ld为elf格式可执行代码从0x8000000开始安排代码段,运行时用内核分配的物理页面决定到底在内存的什么地方
b. CPU根据指令性质判断相应地址对应的段寄存器,根据段寄存器值(“|-描述项下标-|-GDTR/LDTR-|-权限-|”)以及逻辑地址,得到段映射得到的虚拟地址
c. 内核建立新进程时,会将regs(进程的寄存器“现场”吧)的cs,ds、es、ss的值分别设置为__USER_CS(index=4,TI=0,RPL=3),__USER_DS(index=5,TI=0,RPL=3),这里验证了“第2、3个描述项用于内核代码段和数据段,第4、5项用于当前进程的代码段和数据段”这句话
内核进程RPL=0,用户进程RPL=3
d. GDT内容固定不变,其中根据第4、5个描述项内容,可以计算基地址为0,段长度为4GB,从而Linux中虚拟地址到线性地址映射不变,糊弄i386 CPU,而之所以可以糊弄,是因为Linux保护机制是在页式管理做的,不依赖i386本身的保护
内核进程DPL=0,用户进程DPL=3
e. asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));进入内核,切换到新进程
这行代码切换了CR3值,会不会造成前后的代码不连续?个人理解,不知道对不对,希望大牛指导:这是不是因为在内核里,地址不会经过页式映射,即不会受到CR3影响?因为可以反过来想CR3是干什么的,是切换用户进程的,而不内核只有一个,没有“在不同内核切换”的说法,顶多内核态用户态之间有切换。或者说,GDTR=CR3所指向的GDT,让每个用户进程的空间隔离了,才使得每个进程都有“3GB”自己独立空间,如果在内核态地址映射也这样,内核岂不也“虚拟”了,但实际上内核空间是共享的。
f. 根据线性地址(与逻辑地址一样),以及刚设置好CR3赋值到GDTR所指向的目录表,结合线性地址映射物理地址过程,得到物理地址
*段描述项结构
*分页管理由硬件支持,并且得用高速缓存,所以很快
*modify_ldt(),vm86(),暂且不管
*经过前面软硬件对比,可以发现,Linux内核要面对的是各种CPU,所以不能依赖某一种CPU的特性去完成某种机制,换句话说,如果遇到另外一种CPU没有这种特性,那么这种机制也失效了,作为Linux,他是不会让这种情况发生的,所以看到一些不和睦的地方:
Linux内核不理i386 CPU意图一:三层映射“欺骗”两层映射
Linux内核不理i386 CPU意图二:糊弄i386的段页映射,逻辑地址->线性地址不变
Linux内核不理i386 CPU意图三:ds、es、ss都赋值__KERNEL_DS或__USER_DS
Linux内核不理i386 CPU意图四:Intel希望每个用户进程用自己的LDT,但Linux内核建立的进程,TI=0,即都用GDT。LDT只是在VM86模式中运行wine能及其它在Linux上模拟运行Windows软件或DOS软件的程序中才使用 |
|