操作系统ucorelab2.docx
《操作系统ucorelab2.docx》由会员分享,可在线阅读,更多相关《操作系统ucorelab2.docx(11页珍藏版)》请在冰豆网上搜索。
操作系统ucorelab2
操作系统
实验报告
题目:
物理内存管理
一、内容
本次实验包含三个部分。
首先了解如何发现系统中的物理内存;然后了解如何建立对物理内存的初步管理,即了解连续物理内存管理;最后了解页表相关的操作,即如何建立页表来实现虚拟内存到物理内存之间的映射,对段页式内存管理机制有一个比较全面的了解。
本实验里面实现的内存管理还是非常基本的,并没有涉及到对实际机器的优化,比如对cache的优化等。
如果大家有余力,尝试完成扩展练习。
练习1:
实现first-fit连续物理内存分配算法(需要编程)
在实现firstfit内存分配算法的回收函数时,要考虑地址连续的空闲块之间的合并操作。
提示:
在建立空闲页块链表时,需要按照空闲页块起始地址来排序,形成一个有序的链表。
可能会修改default_pmm.c中的default_init,default_init_memmap,default_alloc_pages,default_free_pages等相关函数。
请仔细查看和理解default_pmm.c中的注释。
请在实验报告中简要说明你的设计实现过程。
请回答如下问题:
你的firstfit算法是否有进一步的改进空间
练习2:
实现寻找虚拟地址对应的页表项(需要编程)
通过设置页表和对应的页表项,可建立虚拟内存地址和物理内存地址的对应关系。
其中的get_pte函数是设置页表项环节中的一个重要步骤。
此函数找到一个虚地址对应的二级页表项的内核虚地址,如果此二级页表项不存在,则分配一个包含此项的二级页表。
本练习需要补全get_pte函数inkern/mm/pmm.c,实现其功能。
请仔细查看和理解get_pte函数中的注释。
get_pte函数的调用关系图如下所示:
请在实验报告中简要说明你的设计实现过程。
请回答如下问题:
请描述页目录项(PagDirectorEntry)和页表(PageTableEntry)中每个组成部分的含义和以及对ucore而言的潜在用处。
如果ucore执行过程中访问内存,出现了页访问异常,请问硬件要做哪些事情?
练习3:
释放某虚地址所在的页并取消对应二级页表项的映射(需要编程)
当释放一个包含某虚地址的物理内存页时,需要让对应此物理内存页的管理数据结构Page做相关的清除处理,使得此物理内存页成为空闲;另外还需把表示虚地址与物理地址对应关系的二级页表项清除。
请仔细查看和理解page_remove_pte函数中的注释。
为此,需要补全在kern/mm/pmm.c中的page_remove_pte函数。
page_remove_pte函数的调用关系图如下所示:
二、目的
理解基于段页式内存地址的转换机制
理解页表的建立和使用方法
理解物理内存的管理方法
三、实验流程
本次实验主要完成ucore内核对物理内存的管理工作。
参考ucore总控函数kern_init的代码,可以清楚地看到在调用完成物理内存初始化的pmm_init函数之前和之后,是已有lab1实验的工作,好像没啥修改。
其实不然,ucore有两个方面的扩展。
首先,bootloader的工作有增加,在bootloader中,完成了对物理内存资源的探测工作(可进一步参阅附录A和附录B),让ucorekernel在后续执行中能够基于bootloader探测出的物理内存情况进行物理内存管理初始化工作。
其次,bootloader不像lab1那样,直接调用kern_init函数,而是先调用位于lab2/kern/init/entry.S中的kern_entry函数。
kern_entry函数的主要任务是为执行kern_init建立一个良好的C语言运行环境(设置堆栈),而且临时建立了一个段映射关系,为之后建立分页机制的过程做一个准备(细节在3.5小节有进一步阐述)。
完成这些工作后,才调用kern_init函数。
四、实验过程与结果分析
练习1:
实现first-fit连续物理内存分配算法(需要编程)
在实现first-fit内存分配算法的回收函数时,要考虑地址连续的空闲块之间的合并操作。
提示:
在建立空闲页块链表时,需要按照空闲页块起始地址来排序,形成一个有序的链表。
可能会修改default_pmm.c中的default_init,default_init_memmap,default_alloc_pages,default_free_pages等相关函数。
请仔细查看和理解default_pmm.c中的注释。
请在实验报告中简要说明你的设计实现过程。
请回答如下问题:
你的firstfit算法是否有进一步的改进空间
关键数据结构和变量:
first_fit分配算法需要维护一个查找有序(地址按从小到大排列)空闲块(以页为最小单位的连续地址空间)的数据结构,而双向链表是一个很好的选择。
libs/list.h定义了可挂接任意元素的通用双向链表结构和对应的操作,所以需要了解如何使用这个文件提供的各种函数,从而可以完成对双向链表的初始化/插入/删除等。
kern/mm/memlayout.h中定义了一个free_area_t数据结构,包含成员结构
list_entry_tfree_list;//thelistheader空闲块双向链表的头unsignedintnr_free;//空闲块的总数(以页为单位)
显然,我们可以通过此数据结构来完成对空闲块的管理。
而default_pmm.c中定义的free_area变量就是干这个事情的。
kern/mm/pmm.h中定义了一个通用的分配算法的函数列表,用pmm_manager表示。
其中init函数就是用来初始化free_area变量的,first_fit分配算法可直接重用default_init函数的实现。
init_memmap函数需要根据现有的内存情况构建空闲块列表的初始状态。
何时应该执行这个函数呢?
通过分析代码,可以知道:
kern_init-->pmm_init-->page_init-->init_memmap-->pmm_manager->init_memmap
所以,default_init_memmap需要根据page_init函数中传递过来的参数(某个连续地址的空闲块的起始页,页个数)来建立一个连续内存空闲块的双向链表。
这里有一个假定page_init函数是按地址从小到大的顺序传来的连续内存空闲块的。
链表头是free_area.free_list,链表项是Page数据结构的base->page_link。
这样我们就依靠Page数据结构中的成员变量page_link形成了连续内存空闲块列表。
structPage{
intref;//pageframe'sreferencecounter
uint32_tflags;//arrayofflagsthatdescribethestatusofthepageframeunsignedintproperty;//thenumoffreeblock,usedinfirstfitpmmanagerlist_entry_tpage_link;//freelistlink
};
page的数据结构:
default_init_memmap(structPage*base,size_tn){
structPage*p=base;
for(;p!
=base+n;p++){
p->flags=p->property=0;
set_page_ref(p,0);
}
base->property=n;
SetPageProperty(base);
nr_free+=n;
list_add(&free_list,&(base->page_link));
}
default_init_memmap函数讲根据每个物理页帧的情况来建立空闲页链表,且空闲页块应该是根据地址高低形成一个有序链表。
根据上述变量的定义,default_init_memmap可大致实现如下:
练习2:
实现寻找虚拟地址对应的页表项(需要编程)
通过设置页表和对应的页表项,可建立虚拟内存地址和物理内存地址的对应关系。
其中的get_pte函数是设置页表项环节中的一个重要步骤。
此函数找到一个虚地址对应的二级页表项的内核虚地址,如果此二级页表项不存在,则分配一个包含此项的二级页表。
本练习需要补全get_pte函数inkern/mm/pmm.c,实现其功能。
请仔细查看和理解get_pte函数中的注释。
get_pte函数的调用关系图如下所示:
图1get_pte函数的调用关系图
请在实验报告中简要说明你的设计实现过程。
请回答如下问题:
请描述页目录项(PagDirectorEntry)和页表(PageTableEntry)中每个组成部分的含义和以及对ucore而言的潜在用处。
如果ucore执行过程中访问内存,出现了页访问异常,请问硬件要做哪些事情?
(1)高20位表示下一级页表(或物理页表)的基址(4k对齐),后12位为标记为,分别为从低位起第0~6位为ucore内核占用,表示指向下一级页表的某些特性。
(2)如果ucore执行过程中访问内存,出现了页访问异常,那么便会触发缺页中断。
缺页中断的具体执行步骤在lab3中可以学习知道。
练习3:
释放某虚地址所在的页并取消对应二级页表项的映射(需要编程)
练习
当释放一个包含某虚地址的物理内存页时,需要让对应此物理内存页的管理数据结构Page做相关的清除处理,使得此物理内存页成为空闲;另外还需把表示虚地址与物理地址对应关系的二级页表项清除。
请仔细查看和理解page_remove_pte函数中的注释。
为此,需要补全在kern/mm/pmm.c中的page_remove_pte函数。
page_remove_pte函数的调用关系图如下所示:
图2page_remove_pte函数的调用关系图
请在实验报告中简要说明你的设计实现过程。
请回答如下问题:
数据结构Page的全局变量(其实是一个数组)的每一项与页表中的页目录项和页表项有无对应关系?
如果有,其对应关系是啥?
如果希望虚拟地址与物理地址相等,则需要如何修改lab2,完成此事?
鼓励通过编程来具体完成这个问题
删除页目录表项对应的pte:
staticinlinevoid
page_remove_pte(pde_t*pgdir,uintptr_tla,pte_t*ptep){
if(*ptep&PTE_P){//页表项存在
structPage*page=pte2page(*ptep);//找到页表项
if(page_ref_dec(page)==0){//只被当前进程引用
free_page(page);//释放页
}
*ptep=0;//该页目录项清零
tlb_invalidate(pgdir,la);
//修改的页表是进程正在使用的那些页表,使之无效
}
}
五、实验体会和思考题
通过上图,我们可以看到ucore在显示其entry(入口地址)、etext(代码段截止处地址)、edata(数据段截止处地址)、和end(ucore截止处地址)的值后,探测出计算机系统中的物理内存的布局(e820map下的显示内容)。
接下来ucore会以页为最小分配单位实现一个简单的内存分配管理,完成二级页表的建立,进入分页模式,执行各种我们设置的检查,最后显示ucore建立好的二级页表内容,并在分页模式下响应时钟中断。
ucore内核对物理内存的管理工作:
bootloader(对物理内存资源进行探测)->kern_entry(为执行kern_init建立一个良好的C语言环境(设置堆栈),而且建立一个临时的段映射关系,为之后分页做准备)->kern_init(完成一些输出并对lab1结果进行检验)->pmm_init(完成物理内存的管理)->pic_init(异常相关的初始化函数)|idt_init(执行中断的初始化函数)
具体步骤:
为了完成物理内存管理,这里首先需要探测可用的物理内存资源;了解到物理内存位于什么地方,有多大之后,就以固定页面大小来划分整个物理内存空间,并准备以此为最小内存分配单位来管理整个物理内存,管理在内核运行过程中每页内存,设定其可用状态(free的,used的,还是reserved的),这其实就对应了我们在课本上讲到的连续内存分配概念和原理的具体实现;接着ucorekernel就要建立页表,启动分页机制,让CPU的MMU把预先建立好的页表中的页表项读入到TLB中,根据页表项描述的虚拟页(Page)与物理页帧(PageFrame)的对应关系完成CPU对内存的读、写和执行操作。
这一部分其实就对应了我们在课本上讲到内存映射、页表、多级页表等概念和原理的具体实现。
代码分析:
内存管理相关的总体控制函数是pmm_init函数,它完成的主要工作包括:
1.初始化物理内存页管理器框架pmm_manager;
2.建立空闲的page链表,这样就可以分配以页(4KB)为单位的空闲内存了;
3.检查物理内存页分配算法;
4.为确保切换到分页机制后,代码能够正常执行,先建立一个临时二级页表;
5.建立一一映射关系的二级页表;
6.使能分页机制;
7.从新设置全局段描述符表;
8.取消临时二级页表;
9.检查页表建立是否正确;
10.通过自映射机制完成页表的打印输出(这部分是扩展知识)
附录(源代码及注释)