跳过正文
  1. 博客/
  2. 随笔/
  3. 编程/

内存分页设计

·3 分钟· ·
随笔 编程 MIT6.828
目录

引言
#

前面已经通过lab1的这篇博文了解了内存分页的实现细节,接下来就谈谈如何具体实现内存分页

物理载体
#

通过了解KERNBASE对操作系统的影响这篇博文我们知道,其实内存分页就是完成对物理存在的一种分割和隔离,所以我们在完成内存分页系统设计之前必须要构建一个载体,完成对物理存在的一种表示。

在xv6中声明一个动态数组来代表物理内存,每一个值代表一块4k的内存页。我们主要通过offset - base得到偏移倍数,每个偏移量为4K,也就是通过(offset - base ) << 12 得到物理地址,我们看一下这个数组成员:PageInfo结构体

struct PageInfo {
  
	struct PageInfo *pp_link;
  
	uint16_t pp_ref;
  
};
  

主要存在两个值:一个为下一个可用的地址指针,一个为引用次数。

引用次数比较好理解,但是这个pp_link有什么用呢。其实你可用把这个结构体看做成一个由链表组成的堆栈,我们只需要保留栈顶值(page_free_list),由于它保存下一个值地址,这样通过不断的push、pop,就能维持一个可用物理内存栈。

二级指针的妙用
#

由于前面的博客原理已经介绍的很详细了,我就不再累赘了,在这里我提一下源码中二级指针的妙用,虽然它只有短短几行,但是运行的结果却是让人大开眼界,体会到指针的神奇威力。

这段代码出现在kern/pmap.ccheck_page_free_list函数中

if (only_low_memory) {
  
	// Move pages with lower addresses first in the free
  
	// list, since entry_pgdir does not map all pages.
  
	struct PageInfo *pp1, *pp2;
  
	struct PageInfo **tp[2] = { &pp1, &pp2 };
  
	for (pp = page_free_list; pp; pp = pp->pp_link) {
  
		int pagetype = PDX(page2pa(pp)) >= pdx_limit;
  
		*tp[pagetype] = pp;
  
		tp[pagetype] = &pp->pp_link;
  
	}
  
	*tp[1] = 0;
  
	*tp[0] = pp2;
  
	page_free_list = pp1;
  
}
  

主要的作用是将“栈底”的元素移到“栈顶”,首先它使用了两个一级指针(pp1、pp2),还有两个二级指针分别指向(pp1、pp2)

首先int pagetype = PDX(page2pa(pp)) >= pdx_limit;判断物理地址是否为大于4M还是小于4M,我们把物理内存页分成两组

  • 小于4M A组
  • 大于4M B组

对于小于4M的组,分两种情况

  1. 第一个小于4M的内存页(page1)
  1. *tp[0] (也就是pp1) 存贮了pp的值,也就是pp1 = page1
  2. tp[0] 存贮了pp -> link 的地址(这个没有什么用)
  1. A组第二个以及以后的内存页(page2)
  1. 上一个地址的值等于pp(没什么用)
  2. tp[0] 存贮了下一个空闲地址的值

对于B组来说也是一样的,最重要的是for循环结束后实现的交换

	*tp[1] = 0; 
  

B组最后一个的pp_link地址地址设置为NULL,也就相当于把他放到栈底

	*tp[0] = pp2;
  

A组最后一个变成pp_link地址设置pp2,也就是B组的第一个接到了A组的最后面去了

	page_free_list = pp1;
  

栈顶变成A组第一个,通过这样的“乾坤大挪移”术就将A组部分移到B组前面去了,也就实现了先使用低地址的物理内存的作用

总结
#

理解内存分页必须要了解背后的原理,了解了原理看具体实现的时候才能事半功倍。

引用
#

相关文章

内存分页
·2 分钟
随笔 编程 MIT6.828
引言 # 本来自己查了很多资料,想自己写出来,结果下笔的时候发现别人已经把我想写的部分全部写出来了,而且比我想的还要具体,所以我就不写了,把链接放出了,顺便我补充一些
引导和操作系统的交互
·3 分钟
随笔 编程 MIT6.828
引言 # 本来自己查了很多资料,想自己写出来,结果下笔的时候发现别人已经把我想写的部分全部写出来了,而且比我想的还要具体,所以我就不写了,把链接放出了,顺便我补充一些
什么是操作系统
·8 分钟
随笔 编程 MIT6.828
引言 # 本文是基于mit6.828 的lab1对操作系统的思考,网上有不少关于lab1的博客,大部分都是介绍如何完成lab1的问题,介绍的比较详细的有这个博客,在这里我就不从问题出发,建议大家看完上面的博客在看我这篇博文,我这篇博文就是从把我遇到的疑惑提炼出知识点,然后再把这些知识点串起来
从CS寄存器看段的前世今生
·2 分钟
随笔 编程 MIT6.828
引言 # Intel作为作为微处理器的航头老大,一直引导CPU的进步发展,也正是因为Intel是一个有着历史包袱的企业,所以站在现代CPU看起来,有一些非常奇葩的设计遗留下来,这些设计一开始是为了兼容,慢慢的将这种兼容又发展成新的功能,把“包袱”转换成“亮点”,段设计就是其中的一个很重要的代表,要想搞懂这个设计在不同的CPU的如何保持兼容和强化,我们必须要慢慢的把CPU的历史给捋顺。
mit6.828课程总结
·2 分钟
随笔 编程 MIT6.828
引言 # 一开始想直接做一个操作系统,但是万事开头难,学习操作系统需要太多基础知识了,所以就按照网上推荐先学习mit6.828的课程,先把xvf6操作系统搞懂,然后在来实现自己的操作系统,下面就是学习这个课程的体会,按照各个lab的顺序,介绍自己的心得体会
AVL树实现原理
·2 分钟
随笔 编程
本篇博客主要基于这篇博客的扩展,建议阅读前先阅读这篇博文,这篇博文详细介绍AVL树的实现原理,完整代码在github的avl.go文件中 浅谈"树"这种数据结构 Github 可视化页面 引言 # AVL树是在对二叉搜索树的一种优化,通过构造一棵高度平衡的二叉搜索树从而实现提高空间利用率,所以在了解如何实现之前,必须了解如何构造一棵二叉搜索树,你可以阅读我的这篇博客了解如何构建一棵二叉搜索树,虽然我是用Go来实现的,但是不必了解太多Go方面的知识,我在博客中尽量使用图片的方式来介绍实现原理