Linux从头学16:操作系统-如何把【页目录和页表】当做普通物理页进行操作的?
扫描二维码
随时随地手机看文章
作 者:道哥,10 年嵌入式开发老兵,专注于:C/C 、嵌入式、Linux。关注下方公众号,回复【书籍】,获取 Linux、嵌入式领域经典书籍;回复【PDF】,获取所有原创文章( PDF 格式)。
-
问题描述
-
CPU接收的是线性地址,不是物理地址
-
对页目录进行"自操作"
-
一级查表:构造线性地址的前十位
-
二级查表:构造线性地址的中间十位
-
三级查表:构造线性地址的最后十二位
-
三个地址段合体
-
对页表进行"自操作"
问题描述
在上一篇文章中,我们举了这样一个示例:
如下图所示:
- 假设实际的物理内存是1 GB;
- 用户程序文件在硬盘上的长度是20 MB;
- 操作系统把用户程序加载到内存中时,从 0x4000_0000 的虚拟内存地址处开始存放;
- 操作系统读取程序结束后,为所有的地址构造好了页目录和页表;
详细的讨论过程,请参考上一篇文章:Linux从头学15:【页目录和页表】-理论 实例 图文的最完全、最接地气详解!。
- 拆分线性地址:0x4100_1800 = 0100_0001_0000_0000___0001_1000_0000_0000;
- 根据线性地址的前 10 位,找到页目录中的索引 260,从而确定页表的物理地址是 0x0800_4000(表项中的值是 0x08004,还要补上低位的 12 个 0);
- 根据线性地址的中间 10 位,找到 0x0800_4000 这个页表中的索引 1,从而确定普通物理页的物理地址是 0x0210_1000(表项中的值是 0x02101,还要补上低位的 12 个 0);
- 根据线性地址的最后 12 位,确定普通页内的偏移量是 2048,普通页的开始地址加上这个偏移量,就得到了最终的物理地址 0x0210_1800。
处理器接收的是线性地址,不是物理地址
因为现在已经开启了分页处理单元,0x0100_0400是我们最后想得到的物理地址,而处理器只接受线性地址,虽然我们知道这是一个物理地址,但是处理器不知道啊!
由于使用的是“平坦型”的段结构,所以这里就忽略了段处理过程,直接讨论页处理过程。所以,我们应该使用某些方法,构造出一个线性地址 addr,让这个地址经过页处理单元之后,得到0x0100_0400这个物理地址:
对页目录进行操作
重新梳理一下思路:如果对一个普通物理页(下文简称为:普通页)里的一个地址处的数据进行操作,需要经过3次查表操作:
一级查表:构造线性地址的前 10 位,来确定页表的物理地址
一级查表:查找的对象是页目录。
二级查表:构造线性地址的中间 10 位,来确定“普通页”的物理地址
二级查表:查找的对象是页表,也就是一级查表得到的那个“页表”。
三级查表:构造线性地址的最后 12 位,来确定“普通页”的页内偏移量
现在,已经构造出了线性地址addr(这是我们的最终目标)的前20位,并且经过页表的前两级查表,成功的定位到了页目录自己!
三个地址段合体
把上面三个步骤中,得到的地址聚合在一起:
例如:mov [0xFFFF_4000], xxxx以上就是操作系统在操作页目录自身时,所采取的策略。
对页表进行寻址
既然已经弄明白了操作系统是如何操作页目录的,那么对页表的操作就不是什么大问题了。
一级查表
按照正常的分页查找流程,从页目录的某个表项中,查找我们想操作的那个页表。
二级查表
利用这个页表的最后一个表项(index = 1023),预先填写一个地址(0x08000),让它指向这个页表自己的开始物理地址。
三级查表
此时,已经找到最后的普通物理页了(其实它是一个页表,被当作普通物理页使用)。
------ End ------