MIT6.828学习之Lab2_Part 1: Physical Page Management

任务:补全这五个函数

MIT6.828学习之Lab2_Part 1: Physical Page Management_第1张图片
在同学的帮助下,得到了这样一张图:
有这张图之后再来做这部分的练习就会轻松一些。
MIT6.828学习之Lab2_Part 1: Physical Page Management_第2张图片

虚拟内存主要的好处是:

  1. 让每个程序都以为自己独占计算机内存空间,概念清晰,方便程序的编译和装载。
  2. 通过将部分内存暂存在磁盘上,可以让程序使用比物理内存大得多的虚拟内存,突破物理内存的限制。
  3. 通过对不同进程设置不同页表,可以防止进程访问其他进程的地址空间。通过在不同进程之间映射相同的物理页,又可以提供进程间的共享
    谢谢仁兄

boot_alloc函数补全:

boot_alloc(n)是个简单的内存分配器,只有当JOS在建立他的虚拟内存系统的时候才使用。page_alloc()才是真的分配器。这个函数的核心思想就是维护一个静态变量nextfree,里面存放着下一个可以使用的空闲内存空间的虚拟地址。(我感觉除了修改nextfree值并没干什么)

    PGSIZE定义在inc/mmu.h中,大小为4096
    //实际作用就是将sz向上取整(对齐)成PGSIZE的倍数,如sz=5369,PGSIZE=4096,那么addr=8192
    #define PGROUNDUP(sz)  (((sz)+PGSIZE-1) & ~(PGSIZE-1))  
    //实际作用就是将sz向下取整成PGSIZE的倍数,如sz=5369,PGSIZE=4096,那么addr=4096
    #define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1)) 

boot_alloc函数补全:
在这里插入图片描述inc/memlayout.h中:
MIT6.828学习之Lab2_Part 1: Physical Page Management_第3张图片MIT6.828学习之Lab2_Part 1: Physical Page Management_第4张图片MIT6.828学习之Lab2_Part 1: Physical Page Management_第5张图片

mem_init()函数补全:

kern_pgdir = (pde_t *) boot_alloc(PGSIZE);分配了一个页的内存,这个页就是紧跟着操作系统内核之后,因为end指向the end of the kernel’s bss segment。
kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P;为页目录表添加第一个页目录表项。UVPT的定义是一段虚拟地址的起始地址,0xef400000,从这个虚拟地址开始,存放的就是这个操作系统的页表kern_pgdir,所以我们必须把它和页表kern_pgdir的物理地址映射起来

分配一块内存,用来存放一个struct PageInfo的数组。系统内核就是通过这个数组来追踪所有内存页的使用情况的:
在这里插入图片描述void * 型指针,任何类型的指针都可以直接赋值给它,无需进行强制类型转换

补充page_init()函数:

page_init() Initialize page structure and memery free list
paddr = PADDR(vaddr) 将vaddr转换成物理地址paddr?

由于 boot_alloc 返回的是内核虚拟地址 (kernel virtual address),一定要利用 PADDR 转为物理地址

MIT6.828学习之Lab2_Part 1: Physical Page Management_第6张图片

page_alloc()函数补全

page2kva 函数的作用就是通过物理页获取其内核虚拟地址。补全如下:
MIT6.828学习之Lab2_Part 1: Physical Page Management_第7张图片

page_free()函数补全

page_free()就好写多了,不过我还犯低级错误。。。真是太久没编程了
MIT6.828学习之Lab2_Part 1: Physical Page Management_第8张图片

改错

可以看到我的check_page_free_list(1)结果出错了
MIT6.828学习之Lab2_Part 1: Physical Page Management_第9张图片void assert( int expression );作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息
可以看到是nfree_basemem=0才出错的,是上面的for循环没有改变该值,也就是说,我分配的地址空间的basemem里一个free page都没有。所以我认为是我的page_init()函数出错了
MIT6.828学习之Lab2_Part 1: Physical Page Management_第10张图片
又查了下kern/pmap.h中的几个函数的定义:
page2kva
MIT6.828学习之Lab2_Part 1: Physical Page Management_第11张图片MIT6.828学习之Lab2_Part 1: Physical Page Management_第12张图片在这里插入图片描述
其中PTXSHIFT与PGSHIFT的值都是12

可以看到page2pa()pa2page()是将 &pages[i] 与 i页面物理首地址相互转换的函数(见最上面的地址空间图会比较清晰点)

果然经过我的仔细排查,我发现我的错误,

	size_t extend_alloced = PADDR(boot_alloc(0))/PGSIZE;
	}else if(i <= extend_alloced){
		pages[i].pp_ref = 1; 
		//this pages are already in ues inextended memory
	}

有一个这样的else if在,所有小于extend_alloced(extend memory被分配好的最后page的物理地址)的页都会被设为已分配,赶紧改

else if(i >= (EXTPHYSMEM / PGSIZE) && i <= extend_alloced)

改成这样后,倒是可以succeed,但是qemu却崩了
MIT6.828学习之Lab2_Part 1: Physical Page Management_第13张图片我发现应该是 check_page_alloc() 的时候出错了,那就是我的page_alloc()函数写错了,我一看,果然

if(page_free_list == NULL) //out of free memory
		return NULL;
		//one=NULL; 本来这么写的,这没意义呀,函数没停止,可不就后面会空指针转来转去出错么

改过来再运行,还是出错,这次明确告诉我page_free()函数写错了。。。
MIT6.828学习之Lab2_Part 1: Physical Page Management_第14张图片我仔细检查了一遍我的page_free()函数,我觉得就是没错,我再看下原因,发现是因为要free的page的ref值不等于0,而我想到确实在page_alloc()中我动过这个值,我alloc了页面one后还把one->pp_ref=1,去掉这个就可以check_page_alloc() succeed了,但是我认为这个是有必要加上才对,搞不懂了。。。
(个人感觉是ref=0标志着这个页可不可以被分配,像BIOS那些页就属于不能分配的,然后link=NULL才是标志这页分没分配完,因此ref不需随便改,link要时时记得改,只有当ref==0&&link==NULL代表该页可被分配且已被分配,该页才能被free)
上述个人感觉纯属瞎扯,首先函数上方的hint已经明确说了不要改pp_ref,还去改我是真瞎,其次,现在我知道了pp_ref是物理页到虚拟地址的映射次数,同一个物理页可以映射到多个虚拟地址,当没有映射时,pp_ref为0就可以free掉这个物理页,之后再有需要重新分配。所以修改pp_ref的关键时建立到虚拟地址的映射,操作是赋值页表项
在这里插入图片描述

你可能感兴趣的:(MIT6.828操作系统学习,MIT6.828,c语言)