首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 操作系统 >

JOS学习札记(六)

2013-03-21 
JOS学习笔记(六)接下来做part2,先上一张开启分页后的地址变换图:(完整的图在http://pdos.csail.mit.edu/6.

JOS学习笔记(六)

接下来做part2,先上一张开启分页后的地址变换图:(完整的图在http://pdos.csail.mit.edu/6.828/2011/lec/x86_translation_and_registers.pdf)

JOS学习札记(六)

然后再放一张具体的地址变换的图:

JOS学习札记(六)


好当我们把这两张图也牢记于心的时候就可以开始实验的part2了。

1、实验要求

完成以下几个函数:

pgdir_walk()        boot_map_region()        page_lookup()        page_remove()        page_insert()
然后通过mem_init()里面的check_page函数就算过关了。

虽然要求比较简单,但实现起来可真不容易。


2、原理

(1)地址变换

首先从硬件机制说起,当cpu拿到一个地址并根据这个地址访问主存时,在x86体系架构下要经过至少两级的地址变换,第一级成为段式地址变换而第二级成为页式地址变换。(为什么?主要是从安全、兼容老的os、考虑现代os等原因)

最原始的地址叫做虚拟地址,根据规定,将前16位作为段选择子,后32位作为偏移。根据段选择子查找gdt/ldt,查到的内容替加上偏移,此时的地址就变成了线性地址。

线性地址前10位被称作页目录入口(page directory entry也就是pde),其含义为该地址在页目录中的索引,中间10位为页表入口(page table entry,也就是pte),代表在页表中的索引,最后12位是偏移。

当一个线性地址进入页式地址变换机制时,首先cpu从cr3寄存器里得到页目录(page directory)在主存中的地址,然后根据这个地址加上pde得到该地址在页目录中对应的项。无论是页目录的项还是页表的项均是32位,前20位为地址,后12位为标志位。当获取了相应的页目录项之后,根据前20位地址得到页表所在地址,加上偏移pte得到页表项,取出前20位加上线性地址本身的后12位组成物理地址,整个变换过程结束。这也就是以上两个图所描述的功能。

值得注意的是,这个过程完全是由硬件实现,在这个部分的实验中要做的是初始化并维护页目录与页表,当页目录与页表维护好了,然后使cr3装载新的页目录,一切就交由硬件去处理地址变换了。

这里还有两个点需要说下:

1、为什么是20位就能表示页表所在地址?因为页表的分配以页为单位,换句话分配的过程是分配一个页面,而这个页面所有内容都用来当做页表,而页正好是4k,所以页表地址必定是4k对齐。

2、一个页表项对应一页(也就是4K内容),因为其后面有12位的偏移。一个页表有1024个页表项,因为一个页表大小为4K,一个页表项为32位(4B)。一个页目录项对应一个页表,对应4K*1024=4M空间的映射。一个页目录有1024个页目录项,对应4M*1024=4G地址的映射,正好是32位地址空间。

3、一个理发师只为不自己理发的人理发,当然我们在这里不套路罗素悖论。段页地址变换只为虚拟地址进行地址变换,而不为它本身的地址进行变换。换句话说变换过程中所出现的任何地址都是物理地址,在编写代码的时候尤其要注意这一点。


(2)JOS的相关部分

之前的日志里已经说过,JOS的机制中,虽然使用段式地址变换,但和没使用完全一样,因为只定义了一个段,其长度为4G,换句话说,经过段式地址变换后的内容和之前完全一样,虚拟地址和线性地址完全一样。

在part2中也就是mem_init()执行环境里,JOS已经开启了页式地址变换,但变换的比较粗糙,只是简单的把0--4M物理地址分别映射到了0--4M物理地址和0xf0000000开始的4M 地址处,之前也已经详细说过这个问题。但同时也感谢一下这种“粗糙”的变换方式,让我们在编程填充页表和页目录的时候方便了许多。(为什么?因为要往里填充物理地址,存在一个把当前符号地址转化成物理地址的过程,因为变换的粗糙,所以这个过程相对简单)。

值得注意的是,在代码里我们的所有地址均为虚拟地址,不同通过任何方法直接得到某个符号实际存在于物理内存中的地址,只有通过算才能得到我们需要的物理地址。


3、实现

(1)基本数据类型与函数说明

pde_t 代表一个页目录项

pte_t 代表一个页表项

pgdir_walk()  用于查找某个虚拟地址是否有页表项,如果没有也可以通过此函数创建,值得注意的是,有页表项并不代表已经被映射。

boot_map_region()  映射一个虚拟地址区间到一个物理地址区间,貌似在本部分没用到。

page_insert() 将一个虚拟地址映射到一个Page数据结构,也就是映射到某个物理地址。

page_lookup() 查找一个虚拟地址对应的Page数据结构,若没有映射返回空。

page_remove() 解除某个虚拟地址的映射。


(2)具体实现




热点排行