做嵌入式底层的朋友都应该知道,在Linux当中,我们会发现存在多进程和多线程的概念,但是在以cortex-m系列为代表的单片机中却只有多任务的概念。通常,多任务和多线程其实是一个意思,只有进程和线程之间才会存在差异。那么是什么导致这种差异呢?单片机能不能跑多进程呢?今天,本篇主要是用于讲解导致这个差异的硬件模块:MMU(内存管理单元)。
通常,我们的ARMv7 Cortex-A 一般采用MMU来管理内存,而单片机所使用的ARMv7 Cortex-M则是采用MPU来管理内存。两者之间有明确的差异。MMU是支持虚拟内存的,而MPU则不支持虚拟内存,只支持简单的内存权限管理。我们可以理解为MPU就是MMU的阉割版(不知道这么理解合不合适)。然后多进程是建立在虚拟内存上的,因此,不支持MMU的芯片就不支持多进程,故单片机通常不支持多进程。下面我们详细聊聊什么是MMU。
在《cortex_A_series_PG.pdf》中有所描述:MMU是用于让进程可以工作在自己的私有内存空间的处理单元。MMU的一个关键技术在于 地址映射(虚拟地址到物理地址转换),这种地址转换对于应用程序是透明的,另外,MMU还管理了内存访问的权限,内存order,cache策略等等。在多进程的嵌入式系统当中,我们通常用MMU去映射一段内存,并授予访问该内存的权限和一些其他属性。
当MMU禁用的时候,所有的虚拟地址访问都是直接访问到对应数字上的物理内存上面(1:1) ( a flat mapping)(即VA=PA)。当MMU使能的时候,MMU则需要通过存放到TTB寄存器中的映射表来查询对应的物理地址(映射表我们可以看成是一个数组,虚拟地址是数组的索引,数组的内容就是物理地址)。如果MMU通过映射表查询到虚拟地址是未映射的(转换是通过映射表完成),那么CPU会产生一个abort异常,并提供详细的问题异常信息(比如0地址,通常我们不会在0(NULL)地址上设置映射关系,因此程序一旦访问0地址,就会触发page falut,从而产生segment fault)。
MMU允许操作系统使用多张虚拟映射表即一个进程一张映射表,转换过程大概如下: