uMIPS CPU地址空间简介(整理自《See MIPS Run》和CPU文档):
注:首先需要明确的是CPU物理地址空间不仅仅包括RAM物理内存的空间,还包括CPU内部的一些总线、寄存器的编址。
一个MIPS CPU可以运行在两种优先级别上, 用户态和核心态。MIPS CPU从核心态到用户态的变化并不是CPU工作不一样,而是对于有些操作认为是非法的。在用户态,任何一个程序地址的xx是1的话,这个地址是非法的,对 其存取将会导致异常处理。另外,在用户态下,一些特殊的指令将会导致CPU进入异常状态。
在32位CPU下,程序地址空间划分为4个大区域。每个区域有一个传统的名字。对于在这些区域的地址,各自有不同的属性:
kuseg: 虚拟空间0x0000 0000 - 0x7FFF FFFF (低端2G):这些地址是用户态可用的地址。在有MMU的机器里,这些地址将一概被MMU作转换,除非MMU的设置被建立好,否则这2G地址是不可用的。 对于没有MMU的机器,存取这2G地址的方法依具体机器相关,你的CPU具体厂商提供的手册将会告诉你关于这方面的信息。如果想要你的代码在有或没有 MMU的MIPS处理器之间有兼容性,尽量避免这块区域的存取。
kseg0: 虚拟空间0x8000 0000 - 0x9FFF FFFF(512M): 这些地址映射到物理地址简单的通过把{zg}位清零,然后把它们映射到物理地址低段512M(0x0000 0000 - 0x1FFF FFFF)。因为这种映射是很简单的,通常称之为“非转换的”地址区域。几乎全部的对这段地址的存取都会通过快速缓存(cache)。因此在cache设 置好之前,不能随便使用这段地址。通常一个没有MMU的系统会使用这段地址作为其绝大多数程序和数据的存放位置。对于有MMU的系统,操作系统核心会存放 在这个区域。
kseg1: 虚拟空间0xA000 0000 - 0xBFFF FFFF(512M): 这些地址通过把{zg}3位清零的方法来映射到相应的物理地址上,与kseg0映射的物理地址一样。但kseg1是非cache存取的。kseg1是{wy}的在 系统重启时能正常工作的地址空间。这也是为什么重新启动时的入口向量是0xBFC0 0000。这个向量相应的物理地址是0x1FC0 0000。你将使用这段地址空间去存取你的初始化ROM。大多数人在这段空间使用I/O寄存器。如果你的硬件工程师要把这段地址空间映射到非低段512M 空间,你得劝说他。
kseg2: 虚拟空间0xC000 0000 - 0xFFFF FFFF (1G): 这段地址空间只能在核心态下使用并且要经过MMU的转换。在MMU设置好之前,不能存取这段区域。除非你在写一个真正的操作系统,一般来说你不需要使用这 段地址空间。
综上可以看到,MIPS32 CPU下面的不经过MMU转换的内存窗口只有kseg0和kseg1 的512M的大小,而且这两个内存窗口映射到同一512M的物理地址空间。其余的3G虚拟地址空间需要经过MMU转换成物理地址,这个转换规则是由CPU 厂商实现的。还句话说,在MIPS32 CPU下面访问高于512M的物理地址空间,必须通过MMU地址转换。
在核心态下(CPU启动时),CPU可以作任何事情。在用户态下,2G之上的地址空间是非法的,任何存取将会导致系统异常处理。注意的是,如果一个 CPU有MMU,这意味着所有的用户地址在真正访问到物理地址之前必须经过MMU的转换, 从而使得OS可以防止用户程序随便乱用。对於一个没有内存映射的OS,MIPS CPU的用户态其实是多余的。在核心态下,CPU可以存取低段地址空间,这个存取也是通过MMU的转换。
下面来谈谈MIPS64 CPU的虚拟地址空间。
64位CPU的地址空间的{zd1}2G和{zg}2G区域是和32位情况下一样的,64位扩展的地址部分在这两者之间。64位下那些大块的不需要MMU转换 的窗口可以克服kseg0和kseg1 512M的局限,但是32位下我们可以通过对MMU编程来同样达到这一点。
/***************************************************************************************/
uMIPS CPU内存管理与TLB(整理自《See MIPS Run》):
早期的MIPS CPU定位于支持运行在UNIX工作站与服务器上的应用程序,因此内存管理硬件被构想为一个最小化的能帮助BSD UNIX——一个经过完善设计并拥有充分多虚拟存储需求的操作系统的典型——提供内存管理功能的硬件。我们将从MIPS的设计起点开始,面对着一个 unix类型的操作系统以及它的虚存系统的众多需求。我们将会展示一下MIPS的硬件是如何满足这些需求的。结尾时,我们会讨论一下在不能像通常一样使用 内存管理硬件的嵌入式系统中,您可以采取的几种使用方式。
UNIX内存管理工作的本质是为了能运行众多不同的任务(即multitasking—— 多进程),并且每个任务各自拥有自己的内存空间。如果这个工作圆满完成,那么各任务的命运将彼此独立开来(操作系统自身也因此得以保护):一个任务自身崩 溃或者错误的做某些事不会影响整个系统。显然,对一个使用分布终端来运行学生们程序的大学而言,这是一个很有用的特性;然而不仅如此,甚至是要求最严格的 商业系统环境也需要能够在运行的同时支持实验软件或原型软件一并进行调试和测试。
MMU并不仅仅为了建立巨大而完备的虚拟存储系统,小的嵌入式程序也能在重定位和更有效的内存分配里受益。如果能把应用程序观念上的地址映射到任何 可获得的物理地址,系统在不同时刻运行不同程序就会更加容易。
嵌入式应用中常常会明确的运用多进程机制,但几乎没有多少嵌入式操作系统使用隔离的地址空间。或许这归咎于这种机制在嵌入式CPU以及它们上面的操 作系统上用处不大并且带来不稳定性,因而显得不那么重要。