基本原理
内存空间如何映射是计算机原理和操作系统原理最基本也是最关键的要点之一。只有明白系统是如何排布和映射内存空间的,才能深入理解计算机原理和操作系统特性。
- 物理地址空间是通过内存总线实现的,空间中的一部分会安排各种片内设备的特殊功能寄存器(SFR);一部分会安排存储器,存储代码和数据;剩余的都是空洞,CPU如果访问的话会触发总线错误。
- 物理地址上也可能挂载部分ROM空间。这部分空间一般是用来存放BootLoader或主系统代码的。
- 虚拟地址空间是通过MMU实现的,CPU传递给MMU虚拟地址,MMU将虚拟地址转化为物理地址。
- CPU在MMU初始化之前使用的是物理地址且是没经过cache的,之后CPU使用虚拟地址,可以通过cache加速也可以不经过cache访问。
- 对于DMA则只能使用物理地址且是不经过cache的。
- SylixOS中对于不支持MMU的处理器架构,只设置物理地址空间。对于支持MMU的处理器架构只创建并设置一个虚拟地址空间。
- SylixOS通过两个内存初始化映射表(结构体数组)_G_physicalDesc[]和_G_virtualDesc[]来分别描述物理内存空间和虚拟内存空间。这两个表位于
bsp/bspMpu.h
文件中。 - 无论是物理地址空间还是虚拟地址空间,各个分区之间是不能重叠的,但物理地址空间和虚拟地址空间之间除了平板映射的分区外,其他段是可以重叠错位的。
- 这些分区 要求至少是页对齐的,一般一个页大小是4KB。
- 一个32位的体系结构其物理地址空间和虚拟地址空间都是32位的(4GB)。64位处理器也类似,只是空间大小变为了64位。
分区描述
物理地址空间描述
- TEXT分区:用于存放代码和常数,会提前平板映射到虚拟地址空间。
- DATA分区:用于存放需要初始化(.data)和不需要初始化(.bss)的全局静态变量,内核栈(.stack)和内核堆(.heap)。会被提前平板映射到虚拟地址空间。
-
DMA分区:用于DMA数据传输,CPU和DMA设备都可以访问。系统不会提前映射该段,但会保留平板映射的虚拟地址空间。当使用
API_CacheDmaMalloc
函数时,会在该区域分配一段连续的非缓存的物理地址空间,同时将这部分物理地址空间平板映射到虚拟地址空间。当释放该空间时也会取消虚拟地址空间的映射,使得内存使用更加安全。因为CPU和DMA设备都会访问这段内存,为了防止数据的不一致性,这段空间就必须要配置为非cache的平板映射。 - APP分区:这部分用于动态加载app使用,不会提前进行映射。
- VECTOR分区:硬件向量表,有些体系结构要求向量表的位置是固定的,这部分需要提前映射,但不一定是平板映射。
-
BOOTSFR分区:启动时需要用到的特殊功能寄存器。即在系统初始化完vmm模块之前(调用
API_VmmLibPrimaryInit
函数之前)需要使用的外设寄存器空间才需要提前进行平板映射,其他外设可以在vmm初始化完成后通过API_VmmIoRemap
函数进行动态映射。 -
BUSPOOL分区:总线地址池,不进行提前映射。BootLoader初始化时会将PCI域内的空间映射到CPU域内的一段空洞上,此后CPU访问该段内存空间即是访问PCI域内的对应空间,类似于一般设备的特殊功能寄存器。通过
API_VmmIoRemap
可将需要的部分动态映射到vDEV空间,供程序直接使用。
虚拟地址空间描述
- 对于不支持MMU的处理器架构,不需要配置虚拟内存空间。 因为物理地址空间的TEXT, DATA, VECTOR, BOOTSFR, DMA段已提前进行了平板映射,所以这五个部分的虚拟内存空间已经就被分配好了,不需要再配置。 需要配置的有两个分区vDEV和vAPP。
-
vDEV分区用于映射BUSPOOL分区和BOOTSFR分区未包含的外设,不需要平板映射,需要使用
API_VmmIoRemap
函数时进行动态按需映射。vDEV分区的空间要大于实际外设寄存器的空间,因为一个外设的物理地址段可能会映射出多个虚拟地址段。 - vAPP分区是应用程序执行时占用的虚拟地址空间,加载APP时,APP的代码和数据会被动态链接到这部分虚拟地址空间。
- vAPP分区的实际空间来源于物理地址空间的APP分区,但空间大小要远大于物理地址空间的APP分区。
- vDEV 分区最多一个,vAPP分区可以有多个。
- 对于多核系统,每个core中都有私有的MMU和L1cache,所以同一时刻不同的核心可以使用不同的虚拟内存空间。不过对于SylixOS只有一个虚拟地址空间,多个核也就是使用的同一个虚拟地址空间了。