MIT6.828学习之Lab2:Memory Management

a physical memory allocator for the kernel。
Your allocator will operate in units of 4096 bytes(以4M一页为单位)。record which physical pages are free and which are allocated, and how many processes are sharing each allocated page. You will also write the routines to allocate and free pages of memory. (分配和释放内存页代码得自己写)。

virtual memory maps the virtual addresses used by kernel and user software to addresses in physical memory.
The x86 hardware’s memory management unit (MMU) performs the mapping when instructions use memory, consulting a set of page tables(根据一组页表执行映射)

memlayout.h describes the layout of the virtual address space that you must implement by modifying pmap.c.(虚拟地址空间结构)
memlayout.h and pmap.h define the PageInfo structure(记录哪些页空闲) that you’ll use to keep track of which pages of physical memory are free
kclock.c and kclock.h manipulate the PC’s battery-backed clock and CMOS RAM hardware, in which the BIOS records the amount(数量) of physical memory the PC contains, among other things.

遇到的第一个问题居然是怎么fetch远端MIT6.828/lab2的内容,详细操作在此可能有点傻。。。

Part 1: Physical Page Management

实验过程点这里
下面这张图就是我对这一部分的理解:
在这里插入图片描述第一部分主要是实现对物理页的管理,主要是补全物理页的初始化函数page_init(),分配函数page_alloc,释放函数page_free。

首先将物理内存分为npages(后面实验可以知道是0.5M)个物理页,并且为这0.5M个物理页分配一个PageInfo结构体数组pages(包含0.5M个,一一对应)

然后就是对所有物理页按要求进行初始化操作,也就是改成内存最初的分配情况。主要是修改pages数组,如果物理页已分配就令对应结构体的pp_ref=1,pp_link=NULL,否则,就将结构体插入到page_free_list的表头

具体的分配情况见上方的图,实现是通过page_init()函数

page_alloc()函数就是将page_free_list表头的结构体取出,令pp_link=NULL,这就是将该结构体指向的物理页分配好了(注:alloc不是引用,所以不用改引用值pp_ref)。

相对应page_free()就是将要free的物理页对应的结构体插入page_free_list的表头就行,注意只有该页引用值pp_ref==0且pp_link==NULL才能free

Part 2: Virtual Memory

实验过程点这里
这部分主要还是要理解这张图,理解分段分页机制
在这里插入图片描述感谢__七把刀__的图
首先得区分Virtual, Linear, and Physical Addresses

在x86中,所有的内存引用都会被解释为虚拟地址,然后由MMU(内存管理单元)来转换成物理地址从而找到对应的物理页。所以所有的C指针都是虚拟地址。

虚拟地址由a segment selector 和 an offset两部分组成,经过segment translation转成线性地址,再经过page translation变成物理地址(指向某个物理页的首地址)

在lab2里面可以暂时不要管段翻译,可以看成整个系统是一个段的,即其段基址是0,段范围(limit)是0xffffffff.整个系统就被分成了一个段,所以系统可以看成是纯分页形式的。在分页中,地址的转化也比较简单,JOS被设计成0-256M的物理地址映射到以0xf0000000开始的256M虚拟地址,所以从物理地址转化虚拟地址比较方便简单。
谢谢fang92

所以第二部分的主要任务就是要非常清晰线性地址与物理地址的互相转换过程,从而完成物理地址与虚拟地址之间的映射关系(其实就是将物理页的物理基地址赋给虚拟地址在页表中的表项,并设好权限位)

由第一部分我们可以知道,物理页地址由PageInfo结构体数组pages保存,而物理页的管理是通过二级页表机制pgdir+pgtable实现。

线性地址va由dir | table | offset三个字段组成,分别是10bit、10bit、12bit,其中dir=PDX(va)是页目录表pgdir中的索引值,table=PEX(va)是页表pgtable中的索引值。

那么得先找到虚拟地址va对应在页表中的表项,由pgdir_walk()完成。pgdir[PDX(va)]内取出对应二级页表的物理基地址(20bit),补全到32bit然后转成虚拟地址得到pgtable(页表首地址),pgtable[PEX(va)]就是va在页表中的表项了,&pgtable[PEX(va)]就是该表项的地址,是个内核虚拟地址(前面说了,x86所有地址引用都得是虚拟地址)。

找到表项后,想建立物理地址与虚拟地址的映射只需将物理地址的物理基地址存到表项内并设好权限值即可。同样取消映射只需将表项内容清零即可,由page_insert()page_remove()实现。建立或取消映射都会改变该物理页的引用值pp_ref,减为0时应当把物理页free掉。

之前我在想既然有虚拟地址-KERNBASE=物理地址,那为什么还需要有虚拟内存与分页转换这么多此一举。首先下面列出了虚拟内存的好处,其次应该只有[KERNBASE,4GB]才符合这段映射,最后分页机制下可能减去KERNBASE得不到物理地址(但是页目录表项取出二级页表物理基地址转成虚拟地址就是加上KERNBASE实现的,所以这个理由保留意见)。

虚拟内存主要的好处是:

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

Part 3:Kernel Address Space

实验过程点这里

1.JOS处理器的32位线性地址空间分为两部分,内核控制ULIM分割线以上的部分,为内核保留大约256MB(0xf000000-0xffffffff)的虚拟地址空间,用户环境控制下方部分,约3.72G(0x0-0xef800000)。

2.用户环境将没有对以上ULIM内存的任何权限,只有内核能够读写这个内存;[UTOP,ULIM],内核和用户环境都可以读取但不能写入这个地址范围,此地址范围用于向用户环境公开某些只读内核数据结构
UTOP以下的地址空间供用户环境使用;用户环境将设置访问此内存的权限。

3.主要映射了三个区域:

第一个是 [UPAGES, UPAGES+PTSIZE)映射到 pages 结构体数组存储的物理地址 [pages, pages+4M)。 其中UPAGES=0xef000000, PTSIZE=1024 * 4K
第二个是 [KSTACKTOP-KSTKSIZE, KSTACKTOP) 映射到[bootstack,bootstack+32KB)处。 其中KSTACKTOP=0xf0000000,KSTKSIZE=8 * 4K
第三个则是映射整个内核的虚拟空间[KERNBASE, 2*32-KERNBASE)到 物理地址 [0,256M)。其中KERNBASE=0xf0000000
映射完成后,会将cr3寄存器的内容从entry_pgdir替换为kern_pgdir,完成新的页目录地址装载,以保证新的映射生效。
谢谢__七把刀__

4.内核和用户环境放在相同的地址空间(物理页跟虚拟地址的格式完全一样?),主要通过permission bit来保护内核内存。

存留疑问

实验到目前为止,到底操作了哪部分空间,是物理空间0-256M吗?

虚拟空间[KERNBASE,4G)映射在物理地址[0,256M)上,故这段虚拟地址-KERNBASE=物理地址,按照物理空间的初试化情况来看,0~4k,the IO hole, kernel(本身代码), kern_pgdir,pages都应该在物理空间[0,256M)里。那为什么后面又说pages存在[UPAGES,UPAGES+PTSIZE],那UPAGES=0xef000000,根本无法减去KERNBASE,这是为什么?

参考

为什么pgdir_walk()函数里pte存的是pgtable对应物理页的物理地址+KERNBASE转成的虚拟地址。按照分页机制,这个虚拟地址应该会对应另外一个物理页,难道pgtable那个物理页的物理地址只做一个基址吗?

*pde = page2pa(new_PT) | PTE_P | PTE_U |PTE_W | PTE_AVAIL;
pte = (pte_t *)KADDR(PTE_ADDR(*pde));

_kaddr(const char *file, int line, physaddr_t pa)
{
   if (PGNUM(pa) >= npages)
   	_panic(file, line, "KADDR called with invalid pa %08lx", pa);
   return (void *)(pa + KERNBASE);
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值