lab2内存管理解析

来源:互联网 发布:2017个人发卡平台源码 编辑:程序博客网 时间:2024/06/05 20:01

一、预备知识

lab2pc启动过程如图1

 

1           pc启动过程

2   段页式内存管理机制

    逻辑地址是编程人员所用到的地址,经过段转换后得到线性地址。若开启了页式转换,则线性地址将转换为物理地址,否则线性地址就是物理地址。

        段翻译的过程:通过逻辑地址中的选择符index,在相应的描述符表(GDTLDT)中取得段描述符。然后验证逻辑地址的offset的合理性(应该不超过段描述符中的LIMIT)。最后将段描述符中的段基址base加上逻辑地址中的offset得到线性地址。

        页翻译的过程:通过线性地址取得页目录,作为页目录表中的索引,取得页表的地址。然后通过线性地址取得页表项作为索引,取得页面的地址,最后通过线性地址中的页内偏移量取得物理地址。

 

二、内核虚拟地址

       虚拟地址空间被分为了三个部分:

ULIM之上的部分是kernel专用的部分,kernal具有readwrite的权限,用户没问访问这一部分的权限;

UTOPULIM的部分用于存储一些kernel的数据结构,比如页表和管理物理页面的数组pages就存储在这一部分,kernel和用户都只有read的权限,没有write的权限。

UTOP之下的部分是用户空间。

         UPAGES映射到了pages数据结构,UVPTVPT都映射到了pgdir的起始地址处,kernal映射到了bootstack.

 

虚拟内存的映射:

         pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_W | PTE_P;

         pgdir[PDX(UVPT)] = PADDR(pgdir) | PTE_U | PTE_P;  

         这两句建立起了VPTUVPTpgdir的映射。有了这个映射后,虚拟地址到物理地址的变换有两种情况:      

情况一:  

 

    即先通过PDX(va)在页目录中找到相应页表的地址,然后通过PTX(va)在页表中找到相应页面的地址,最后通过va的低12位找到页面中相应的物理地址。图中绿色部分表示一个页面。

 

情况二:

 

        pgdir[PDX(va)]指的是va对应的页表的地址,也就是说此时的页表是页目录表。因为VPT区域内虚拟地址的特殊性(即对于任何在该区域里的va,PDX(va)是想通过的),因此所有该区域里的va对应的页表都是页目录。这样每个虚拟地址对应的是一个页表项。由于虚拟地址和物理地址里的内容是一样的,现在VPT里的虚拟地址里的内容就是pte里面的内容了也就是哪个包含页面地址的32位数据。

    由于虚拟地址的连续性和页表地址在页目录中的连续排放,使得[VPT, KERNBASE)这个区域里的虚拟地址保存的是4G空间的所有pte的排布。这样做的好处是,查找一个va对应的页面,不需要像以前先pgdirpgtable那样,而是直接VPT[PDX(va) * 4K + PTX(va)]就可以找到页面对应的pte了。 

三、开启分页前后的内存映射问题

         我们最终要实现的是开启分页,并且将段式翻译的基址设置为0。目前我们的地址映射机制是:kernebase + x => x => x,即段式翻译中的基址为-kernbase,页式翻译未开启,x => x的映射是由于此时线性地址等于物理地址。我们需要在分页开启之后使用原来的映射机制kernebase + x => x => x ,才不会出问题。

         所以,在开启分页前,pgdir[0] = pgdir[PDX(KERNBASE)]; 因为在此之前,有

         boot_map_segment(pgdir, KERNBASE, 0x10000000, 0, PTE_W);

         将线性地址KERNBASE映射到物理地址0处,所以在pgdir[0] = pgdir[PDX(KERNBASE)];之后,线性地址0也映射到0处,即0---4MB线性地址映射到了0---4MB物理地址。由于假设内核小于4MB。从而实现了 x => x的物理地址到线性地址的转换。

        

         开启分页之后,重新加载gdt,将段基址设置为0,然后赋值pgdir[0] = 0。此时的地址映射为kernebase + x => kernebase + x => x 。

         至此,开启分页完成。