日期:2014-05-16 浏览次数:20693 次
谢谢大家。
boot/head.s
_pg_dir: // 页目录将会存放在这里。因为这句话出现head.s第一个有效代码的位置,因为head.s移动到内存物理0的位置,所以页目录的位置存放在0x0000处
org 1000h // 从偏移0x1000 处开始是第1 个页表
pg0:
org 2000h // 从偏移0x2000 处开始是第2 个页表
pg1:
org 3000h // 从偏移0x3000 处开始是第3 个页表
pg2:
org 4000h // 从偏移0x4000 处开始是第4 个页表
pg3:
org 5000h //这句话主要是让下面的代码在第4个页表占用的内存外,因为第4个页表要占用0x4000-0x5000所以这些位置不能存放代码。
问题,页表可以在内存的任意位置吗?
错,页表可以在内存中通过分级,而不存储在一起,但是每一个页表的起始地址必须在4KB边界上,先看下图页目录的存储结构
原因一:我们看到页目录中用来表示页表地址只有10位置,但是现在要表示一个32位页表项的其实地址肯定是做不到,但是我们发现每一个页目录有1024个表,每一个4个字节,正好是占12位(2^10*2^2=2*12),这样的话,如果从4KB的边界开始存放页表,其实不用存储后面的地址,
原因二:从2KB边界开始存放,一个页目录对应的页表项可以用一个页面存储,不必分到两个页面,方便内存的分页管理。
下面的几句代码是对页目录和页表项所在的内存单元清零。主要是避免脏数据对以后代码进行页面转换的时候的影响,给所有的页表项赋首地址的。
setup_paging:
movl $1024*5,%ecx //一个页目录,4个页表项,每一个1024项,
//设置的循环的次数,即使填充次数,
xorl %eax,%eax //stosl使用的参数
xorl %edi,%edi // 页目录从0x000 地址开始。即使页表和页目录的首地址,
cld;rep;stosl //cld:清除EFALGS中方向的标志位置,rep 循环,循环次数有ecx决定, stosl:将eax的值保存到ES:EDI指向的地址中,由于没有设置标志 EDI 每次自增4
//7 = 111b,可知道设置了,第0、1、2位,分表示存在、用户可读写
//下面主要的功能使用来填充页目录项的
//填充页目录,所管理页表项的地址,即使页目录所管理第1个页表的值,在这//里即使 pg0的地址,+7表示页表项的属性,因为后12位不表示地址,因为每//一个页表项占4个自己,所以第2个页目录的地址是pg_dir+4,第2个是页目录//的地址是pg_dir+4,
,
movl $pg0+7,pg_dir
movl $pg1+7,pg_dir+4
movl $pg2+7,pg_dir+8
movl $pg3+7,pg_dir+12
//下面填写页表项的内容呀,首先从最后一个开始填写的,即是pg3页目录的最//后1个页表项的地址
movl $pg3+4092,%edi //计算pg3页目录的最后1个页表项的地址,最后
//1个页表位置在pg3+4KB-4B的位置,所以位置是//pg3+4096-4
movl $0xfff007,%eax //设置最后一个页表项的地址,16M-4K+7,其中
//其中16M-4KB表示地址,7表示存在,用户可读写
std //设置方向位,使用stosl是edi值递减4
1: stosl &n