从函数memory_map_init(void)谈起:QEMU中X86地址空间的理解


在QEMU V4.2的exec.c中有如下函数:

static void memory_map_init(void)
{
    system_memory = g_malloc(sizeof(*system_memory));

    memory_region_init(system_memory, NULL, "system", UINT64_MAX);
    address_space_init(&address_space_memory, system_memory, "memory");

    system_io = g_malloc(sizeof(*system_io));
    memory_region_init_io(system_io, NULL, &unassigned_io_ops, NULL, "io",
                          65536);
    address_space_init(&address_space_io, system_io, "I/O");
}

这里牵扯出一个重要的概念:地址空间
对于典型的X86 CPU,有两个地址空间,也就是上面函数中初始化的两个地址空间:

  • 内存地址空间 (address_space_memory)
  • I/O地址空间 (address_space_io)

关于内存地址空间:这里的内存地址空间中的“内存”算是直译了memory这个词,但是这里的内存包含的范围更广,包含了我们通常说的硬件--内存条DRAM。在内存地址空间中不仅仅包含了DRAM内存条,还包含了想BIOS ROM,PCI设备,芯片组等诸多设备。下面这个图可以说明:

例子1,假设说我们DRAM的大小是4GB,那么DRAM的地址范围就是0 ~ 4G,但是这个并不意味着在内存地址空间中的地址就是从0开始,到4G结束。(从QEMU中我们知道,例如4G大小的DRAM在内存地址空间是按照0 ~ 3G,3G ~ 4G这样的地址范围来分布的,DRAM被拆分成了两部分分布在内存地址空间中)

例子2,对于32位的x86 CPU,也就是说物理地址总线的范围是0 ~ 4G,但是从之前的描述中可以看到这0 ~ 4G的地址范围不可能全部给内存条(DRAM)用。
所以,即使内存条DRAM的大小是4GB也不能能完全的使用4GB。因为还有其他设备会占用地址。
所以这里的0 ~ 4G内存空间不单单是指“内存条DRAM”的空间,而是包括了诸多外设(如PCI-E显卡,网卡等高速设备,SATA控制器)上的内存空间。因为这些设备为了高速交换数据也是自带有内存的。x86独立编址方式就将这些设备中的“内存”和DRAM内存条一起放在了内存地址空间。(啰嗦了这么多,反正记住内存地址空间不止DRAM就行了,否则理解QEMU的内存虚拟化那里会有疑惑)

通过上面两个地址我们可以知道内存地址空间和内存条DRAM,以及其他设备内存的关系了。

参考:
https://www.cnblogs.com/wudibuzaijia/p/8479972.html
https://www.cnblogs.com/wudibuzaijia/p/8523161.html
https://www.cnblogs.com/yangxingsha/p/11551472.html
https://www.cnblogs.com/wudibuzaijia/p/8512712.html

原文地址:https://www.cnblogs.com/powerrailgun/p/14447359.html