Linux系统中分为几大模块:进程调度、内存管理、进程通信、文件系统、网络模块;各个模块之间都有一定的联系,就像蜘蛛网一样,所以这也是为什么Linux内核那么难理解,因为不知道从哪里开始着手去学习。很多人会跟着系统上电启动 BIOS-->bootsect-->setup-->head-->main-->.....来学习,但是最后会发现当你在看main的时候你必须知道其他模块大概工作情况,要不然根本不知道为什么要这么做(也许其中的C代码和汇编你都能看懂,但真正含义其不知道)。注意下:下面的blog中涉及到的操作系统都是选择0.11版的Linux系统;
所幸的是我最开始入手选择了内存管理,而内存管理和其他模块联系就相对小一些(没看完其他模块,但感觉和其他模块联系不是很大),只有页面中断和进程那两个模块有些关系。好了,现在开始介绍下内存管理模块了(其实也是梳理下我的知识点)。
最开始的地方是在head汇编中,如果看boot中那三个汇编的应该记得(那三个汇编还是比较重要的)。首先是分页机制,在CR0的第31位(PG位)置1表示开启分页机制,顺便也介绍下其他几个控制寄存器:CR1保留,没用;CR2 用来记录页面异常时线性地址(不懂没关系,后面会介绍);CR3 当前CPU使用的页目录表的地址(有此可见系统中不仅仅只有一个页目录表,但是在某一时刻有效的页目录表只有一个);当然有关页面操作的前提是CR0的第31位必须打开,也就是必须是在分页机制开启的时候那几个控制寄存器才有效。
分页机制最最基础的就是把内存空间以4kb为单位分成多个页。
在Linux系统中全部内存分布情况为:
在setup汇编中已经把系统内核代码从0x100000移动到从0地址开始的1MB地址内,再根据main函数中设置内存不超过16MB,所以这里就拿16MB内存为例子;整个内存分布情况为:内核代码及系统数据使用0~1MB ------ 高速缓存使用1~4MB ------ 虚拟内存4MB~xxx(如果有虚拟内存)------ 主内存区xxx~16MB;具体的设置在main函数有,可以自己查看下。如果大于16MB内存那么就会限制只使用低16MB地址内存,大于16MB的内存将会废掉;如果想使用大于16MB,那么就要在main函数中和head汇编中修改下(具体修改就要自己动手了)
页目录表:由1024个目录项组成,每个目录项是4个字节组成,目录项中内容为页表结构的起始地址前20位(因为页表结构是2^12,所以低12位可以忽略)和该页表的属性组成;
页表:页表和页目录表和相似,都是由1024个表项组成,每个表项由4个字节组成,页表项中存放的内容为物理页的起始地址的前20位(因为物理页大小为 2^12,所以低12位可以忽略)和该物理页面的属性组成;
物理页面:一般是在主内存区中以4kb的倍数为起始地址,大小为4kb的连续内存地址(这里假设没有虚拟内存);
表项:表项分为页目录表项和页表表项,其中格式都是一样的。前20位页框地址,后12位表示对于页面的属性;表项结构如下:
若是页目录项:页框地址中的前20位表示的是页表的物理起始地址中的前20位(这里有几个重点的:1、表示的是页表的物理地址,而不是线性地址,这两个地址关系后面再分析;2、是起始地址,因为一个页表是4kb大小,所以一个页表就有4kb个地址(一个字节对于一个地址嘛),而起始地址表示偏移量为0的地址;3、前20位,因为分页机制中页(不管是页目录还是页表或者物理页)都是以4kb的倍数为起始地址的,也就是说页的起始地址的低12位全部为0,2^12 = 4kb);
若是页表项:页框地址中的前20位表示的是物理页的物理起始地址中的前20位;
低12位则用来表示相应的页的一些属性:p == 是否存在(1 存在;0不存在 == 缺页中断);r/w == 是否可读可写(默认都是可读的,1表示页面可写);u/s == 是否是超级用户(这个到现在还没有怎么用到,1表示超级用户);A == 是否访问,D == 是否修改(这两个位一般由硬件来处理);
下面是页目录表、页表、物理页的宏观关系图:
转载请注明作者和原文出处,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/43021405
若有不正确之处,望大家指正,共同学习!谢谢!!!