ucore Lab2 物理内存管理

一、实验目的

实验二主要涉及操作系统的物理内存管理。操作系统为了使用内存,还需高效地管理内存资源。在实验二中大家会了解并且自己动手完成一个简单的物理内存管理系统。

  • 理解基于段页式内存地址的转换机制
  • 理解页表的建立和使用方法
  • 理解物理内存的管理方法

二、实验内容

本次实验包含三个部分。首先了解如何发现系统中的物理内存;然后了解如何建立对物理内存的初步管理,即了解连续物理内存管理;最后了解页表相关的操作,即如何建立页表来实现虚拟内存到物理内存之间的映射,对段页式内存管理机制有一个比较全面的了解。本实验里面实现的内存管理还是非常基本的,并没有涉及到对实际机器的优化,比如针对 cache 的优化等。如果大家有余力,尝试完成扩展练习。

三、实验练习

1.练习0:填写已有实验
将Lab1中完成的代码复制到Lab2中,涉及到的文件为kern/debug/kdebug.c和kern/trap/trap.c。

2.练习1:实现first-fit连续物理内存分配算法(需要编程)
在实现first fit内存分配算法的回收函数时,要考虑地址连续的空间块之间的合并操作。提示:在建立空闲页块链表时,需要按照空闲页块起始地址来排序,形成一个有序的链表。可能会修改default_pmm.c中的default_init,default_init_menmmap,default_alloc_pages,default_free_pages等相关函数。请仔细查看和理解default_pmm.c中的注释。

① 设计实现过程
a.first-fit算法基本思想:
物理内存管理器顺着双向链表进行搜索空闲区域内存区域,直到找到一个足够大的空间,如果空间大小和申请分配的大小相等,则直接把这个空闲区域分配出去;如果空间大于申请分配的空间大小,则将此区域分为两部分,一部分分配出去,另一部分留下形成一个新的空闲区。
释放内存通过将区域重新放回空闲列表中即可。

b.实现first-fit连续物理内存分配算法的实现过程:
ucore采用面对对象编程的思想,将物理内存管理的内容抽象成若干个特定的函数,并使用结构体pmm_manager来将这些函数的指针封装起来,当具体使用物理内存管理功能时,调用已经初始化完成的pmm_manager的实例中的函数指针即可。通过这种抽象来实现将物理内存管理的具体实现与ucore其他部分分隔开来的效果。pmm_manager中提供的物理内存管理函数如下:

  • default_init:对物理内存管理器的初始化。可以初始化free_列表,并将nr_free设置为0.

  • default_init_memmap:对管理的空闲页的数据进行初始化。调用map:kern_init–>pmm_init–>page_init–>init_memmap–>pmm_manager->init_memmap

  • p->flags应设置为bit PG_属性,表示此页有效。

  • 保留的位PG_在p->flags中设置。

  • 如果此页是空闲的,并且不是空闲块的第一页,则p->property应设置为0

  • 如果此页是空闲的,并且是空闲块的第一页,则p->property应设置为所有块的页数

  • p现在是空闲的,则p->ref为0

  • 可以使用p->page_link来将此页面链接到free_list(空闲列表)中(例如:list add before(&free list,&(p->page link));)

  • 最后,可以求空闲块的总数:nr_free += n

  • default_alloc_pages:申请分配指定数量的物理页。在空闲列表中搜索并找到第一个空闲块(块大小>=n),然后重新划分空闲块,返回地址。

  • default_free_pages:申请释放若干指定物理页。将页面重新链接到空闲列表,可能会将小的空闲块合并到大的空闲块中。

  • default_nr_free_pages:查询当前的空闲页总数

  • default_check:对物理内存管理器进行测试

c.default_pmm.c文件可以看出,最终ucore中所使用的物理内存管理器中的函数指针分别指向了default_init,default_init_memmap等函数,可以通过修改这些函数,来实现对first-fit连续内存分配算法。

d.函数修改:

  • default_init函数:对空闲内存块链表进行初始化,并将总空闲数目置零,与具体物理内存分配算法无关,不进行修改。
    在这里插入图片描述
  • default_init_memmap函数:对最初的一整块未被占用的物理内存空间中的每一页所对应的page结构(状态)进行初始化。相邻物理页对应的page结构在内存上也是相邻的,因此可以直接通过第一个空闲物理页对应的page结构加上一个偏移量的方式,来访问所有的空闲的物理页的page结构。具体初始化方式:
    遍历所有空闲物理页的page结构,将page结构中描述空闲块数目的变量置零(故该成员变量只有在整个空闲块的第一个page中才有意义),然后清空这些物理页的引用计数,再通过设置flags的位的方式将其标记为空闲。
    在这里插入图片描述
    再对空闲块的第一个页的page结构进行初始化,具体实现为,将其表示空闲块大小的成员变量设置为参数环路的空闲块大小(单位为页),然后更新存储所有空闲页数量的全局变量,再将这个空闲块插入到空闲内存块链表中(只需将第一个page的page_link插入即可)。
    在这里插入图片描述
  • default_alloc_pages:分配指定页数的连续空闲物理空间,并将第一页的page结构的指针作为结果返回。具体实现方式:
    对参数进行合法性检查,并查询总的空闲物理页数目是否足够进行分配。如果不足够进行分配,直接返回NULL,分配失败。
    从头开始遍历保存空闲物理内存块的链表(按照物理地址从小到大的顺序),如果找到一个连续内存块的大小满足当前需要的内存块,则说明可以成功匹配。优先选择第一个遇到的满足条件的空闲内存块来完成内存分配。代码实现如下:
    在这里插入图片描述
    如果内存块的大小大于需要的内存大小,则将空闲内存块分裂为两块,一块大小为所需内存大小,另一块则重新进行初始化。重新初始化包括对第一个page中表示空闲块代销的成员变量进行设置,其应当设置为剩下的空闲块大小,并将这个分裂出来的空闲块插入到空闲块链表中(链表中的空闲块按照物理地址从小到大排序)。如果内存块大小与所需大小相同,则不用分裂,对分配出去的物理内存的每一个描述信息(对应的page结构)进行初始化,修改flags成员变量,设置成非空闲,再将原始空闲块在空闲链表中删除,更新表示总空闲页数量的全局变量;最后返回用于分配到的物理内存的page结构指针。代码如下:
    在这里插入图片描述
  • default_free_pages:释放指定的某一物理页开始的连续物理页,并且完成first-fit算法中需要的一些信息维护。具体实现如下:
    考虑遍历需要释放的物理页的page结构,对其进行更新。更新方式:
    1.判断原先这些物理页是否被占用,如果释放未被占用的物理页,说明出现异常
    2.设置flags将这些物理页标记为空闲
    3.清空这些物理页的引用计数
    在这里插入图片描述
    4.将这一新的空闲块插入到空闲块链表中
    在这里插入图片描述
    5.对空闲块跟其相邻的空闲块合并。通过merge_backward函数实现,将指定的某一个空闲块与其链表后的空闲块进行合并,如果合并失败返回0,否则返回1.
    在这里插入图片描述
    6.merge_backward函数:
    在这里插入图片描述
  • first-fit算法实现至此基本完成。
    ② 回答问题:你的first-fit算法是否有进一步的改进空间
    答:
    有的。最主要的不足在时间效率。每次要查询一块适合条件的空闲内存块时,需要对链表进行遍历。最坏的情况需要找遍整个链表,时间复杂度为O(n),n为当前链表大小。
    改进方法:采取树的结构来取代简单的链表结构,按照中序遍历把得到的空闲块序列的物理地址按照从小到大的顺序排列。时间复杂度可以从O(n)提升到O(log n)

3.练习2:实现寻找虚拟地址对应的页表项(需要编程)
通过设置页表和对应的页表项,可建立虚拟内存地址和物理内存地址的对应关系。其中的get_pte函数是设置页表项环节中的一个重要步骤。此函数找到一个虚地址对应的二级页表项的内核虚地址,如果此二级页表项不存在,则分配一个包含此项的二级页表。本练习需要补全kern.mm/pmm.c中的get_pte函数,实现其功能。请仔细查看和理解get_pte函数中的注释。get_pte函数的调用关系图如下所示:
在这里插入图片描述
① 设计实现过程

  • get_pte函数:根据给定的页目录项page directory以及线性地址,查询出该linear address对应的页表page table entry,并且根据输入参数要求判断是否需要创建不存在的页表。代码实现:
    在这里插入图片描述
    ② 回答如下问题:
    a.请描述页目录项(Page Director Entry)和页表(Page Table Entry)中每个组成部分的含义和以及对ucore而言的潜在用处。
    答:

  • 页目录项PDE的每个组成部分如下:
    前20位表示4K对齐的该PDE对应的页表起始位置(物理地址,该物理地址的高20位即PDE中的高20位,低12位为0)
    第9-11位未被CPU使用,可保留给OS使用
    第8位可忽略;
    第7位用于设置Page大小,0表示4KB;
    第6位恒为0;
    第5位用于表示该页是否被使用过;
    第4位设置为1,表示不对该页进行缓存;
    第3位是否使用write through缓存写策略;
    第2位表示该页的访问需要的特权级;
    第1位表示是否允许读写;
    第0位为该PDE的存在位。
    在这里插入图片描述

  • 页表项PTE中的诶个组成部分含义:
    高20位与PDE相似,用于表示该PTE指向的物理页的物理地址;
    第9-11位保留给OS使用;
    第7-8位恒为0;
    第6位表示该页是否为dirty,即是否需要在swap out的时候写回外存;
    第5位表示是否被访问;
    第3-4位恒为0
    第2位表示访问该页需要的特权级;
    第1位表示是否允许读写;
    第0位表示存在位。
    在这里插入图片描述
    b.如果ucore执行过程中访问内存,出现了页访问异常,请问硬件要做哪些事情?
    答:
    1)将发生错误的线性地址保存在cr2寄存器中
    2)在中断栈中依次压入EFLAGS,CS,EIP,以及页访问异常码error code,如果page fault是发生在用户态,则还需要先压入ss和esp,并且切换到内核栈;
    3)根据中断描述符表查询到对应page fault的ISR,跳转到对应的ISR处执行,接下来将由软件进行page fault处理。

4.练习3:释放某虚地址所在的页并取消对应二级页表项的映射(需要编程)
当释放一个包含某虚地址的物理内存页时,需要让对应此物理内存页的管理数据结构Page做相关的清除处理,使得此物理内存页成为空闲;另外还需要把表示虚地址与物理地址对应关系的二级页表项清除。请仔细查看和理解page_remove_pte函数中的注释。补全在kern/mm/pmm.c中的page_remove_pte函数。page_remove_pte函数的调用关系如下图所示:
在这里插入图片描述
① 设计实现过程
确保传入的二级页表项是存在的,再获取页表项对应物理页的page结构;
减少该物理页的引用计数,如果该物理页的引用计数变为0,说明不存在任何虚拟页指向该物理页,对该物理页进行释放;
将PTE的存在位设为0,清除该映射关系;
刷新TLB表,确保TLB中的缓存不会有错误的映射关系
代码实现如下:
在这里插入图片描述
② 回答如下问题:
a.数据结构page的全局变量(其实是一个数组)的每一项与页表中的页目录项和页表项有无对应关系?如果有,其对应关系是什么?
答:
存在对应关系。由于页表项中存放着对应的物理页的物理地址,因此可以通过这个物理地址来获取到对应的page数组的对应项。具体做法为,将物理地址除以一个页的大小,然后乘上一个page结构的大小获得偏移量,再使用page数组的基址加上偏移量,可以得到对应的page项地址。

b.如果希望虚拟地址与物理地址相等,则需要如何修改lab完成?
答:
在完全启动了ucore后,虚拟地址和线性地址相等,都等于物理地址加上0xc0000000,如果需要虚拟地址和物理地址相等,可以考虑更新gdt,更新段映射,使得“虚拟地址=线性地址-0xc0000000”,这样就可以实现虚拟地址和物理地址相等。

四、实验结果

在lab2目录下执行make grade指令,得到输出结果如图:
在这里插入图片描述

五、实验心得

本次实验主要是关于物理内存管理,虽然这部分课还没上,但因为我组负责的小班讲述的内容就是物理内存管理,故本次实验理解和实现的难度得到了一定的下降。
本次实验巩固了我对物理内存管理的理解,更重要的是提高了动手操作的能力,加深了对物理内存、虚拟地址以及两者之间协作工作的理解。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值