映射完整物理地址

刚才我们看到,页表中映射了内核代码区域。那如果内核要访问其他的区域呢?内核又能够访问多大的内存空间呢?现在我们就去探索一下。

找到代码

据我所知,相关的秘密就在这个函数之中了。

init_mem_mapping()
	/* the ISA range is always mapped regardless of memory holes */
	init_memory_mapping(0, ISA_END_ADDRESS);

	...

	/*
	 * If the allocation is in bottom-up direction, we setup direct mapping
	 * in bottom-up, otherwise we setup direct mapping in top-down.
	 */
	if (memblock_bottom_up()) {
		unsigned long kernel_end = __pa_symbol(_end);

		/*
		 * we need two separate calls here. This is because we want to
		 * allocate page tables above the kernel. So we first map
		 * [kernel_end, end) to make memory above the kernel be mapped
		 * as soon as possible. And then use page tables allocated above
		 * the kernel to map [ISA_END_ADDRESS, kernel_end).
		 */
		memory_map_bottom_up(kernel_end, end);
		memory_map_bottom_up(ISA_END_ADDRESS, kernel_end);
	} else {
		memory_map_top_down(ISA_END_ADDRESS, end);
	}

上面这两个函数都最后调用kernel_physical_mapping_init()来实际把映射关系写入了页表。

做个实验

具体代码分析就不在这看了。做个小实验,看一下映射后的效果。

该代码就是打印了两层的页表,显示的是物理地址。实验的结果是:

首先我们验证了init_level4_pgt的最后一项确实是init_level3_pgt。其次我们看到,映射前后页表的差异。映射后多了第272项,一共有五个表项。

增加内存

刚才虚拟机配置的内存是4G,现在我们配置成6G看看。

怎么样,是不是多了两项?

对了,现在配置的页表,每个pud映射的是1G,所以你增加了2G就增加了两个表项了。

嗯,我知道你在问为什么原来4G的时候是5个而不是4个表项? 你猜?

映射关系

和之前一样,我们再来计算一下页表的映射关系。

这说明了虚拟地址0xFFFF 8800 0000 0000和物理地址0x0是对应的。

再来看一下这个定义

有了这两个概念再来物理地址转换虚拟地址的函数

怎么样,是不是这下能看懂了?当然了,代码中本来就是这么写的。我只是把结果先展示给大家,再来反推。

不是如来

想当年齐天大圣一个跟斗十万八千里都没有跳出如来佛祖的掌心,所以我也不知道佛祖他的手掌究竟是有多大。不过我们的页表覆盖的内存大小倒是有限制的。

首先地址空间是有限的,现在地址是用64bit表示,所以怎么着也不会超过这个范围。

其次我们在64bit中之用了48bit,至少从4.9的内核看是这样的。

然后我们在看,__PAGE_OFFSET的定义,一下子又把2^48劈成了两半,剩下的还不到一半了。

之前我就在想,那超过了怎么办,会不会把内核的映射空间给冲掉?后来发现自己想多了,人有这么一个定义

也就是最大只能是2^46物理内存,所以这剩下来的小于2^47空间还是够的~

思考:这个变量是在哪里被使用到从而保证不超过2^46大小?

其实呢,内核中还有一个描述内存布局的文档可以证明这一点。Documentation/x86/x86_64/mm.txt

虽然其中还有不少不是很了解,不过可以看到中间有一块64 TB的空间用来直接映射物理内存。而64 TB == 2^ 46。这就是linux内核在64位上现在能够映射的最大物理内存空间了。

PS:感觉快不够用了啊

页表容貌

来看看映射完物理地址后的页表吧。

这里写图片描述

这次最关键的变化就是init_level4_pgt[272]这一项以及之后的内容。在这里映射了系统的整个物理地址。

细心的朋友可能已经注意到了,这次改写的是init_level4_pgt,而不是之前的early_level4_pgt了。

内核文档

另外内核文档中也有非常详尽的页表映射关系

好,可以休息一下了~

Last updated

Was this helpful?