MIPS的存储管理模型
MIPS32中的存储器模型被划分为四个大块,如下表所示:
虚拟地址范围 | 命名 | 描述 |
---|---|---|
0x0000,0000~0x7fff,ffff(0~2G-1) | USEG | must be mapped (set page table and TLB)and set cache before use |
0x8000,0000~0x9fff,ffff(2G~2.5G-1) | KSEG0 | directly mapped(no need to set page table and TLB) but need to set cache before use |
0xa000,0000~0xbfff,ffff(2.5G~3G-1) | KSEG1 | directly mapped(no need to set page table and TLB) and never use cache |
0xc000,0000~0xffff,ffff(3G~4G-1) | KSEG2 | muse be mapped(set page table and TLB) and set cache before use |
下面在给出一个存储器管理模型图,又叫做虚拟内存映射图,该图和上面的表是一一对应关系。如下图所示:
这样的存储器管理模型和X86差距比较大,X86有实模式和保护模式之分,CPU刚启动时运行在实模式之下,直到设定了保护模式之后才能运行在保护模式下。在MIPS32中没有保护模式那么系统是如何启动的呢?
MIPS32中的 处理器启动向量 位于KSEG1中0xbfc0,0000。由于KSEG1是directly mapped的,所以直接对应了物理地址0x1fc0,0000。你可以在内核中一直使用0xa000,0000~0xbfff,ffff之间的虚拟地址来访问0~512M-1物理地址空间,在设置了KSEG0的cache之后,也可以使用0x8000,0000~0x9fff,ffff之间的虚拟地址来访问0~512M-1之间的物理地址空间,上面两片虚拟地址对应同一片物理地址空间。对于512M以上的物理地址空间只能由KSEG2和USEG通过页表访问。
x86处理器启动向量为0xffff,fff0;ARM处理器启动向量为0x0000,0000;MIPS处理器的启动向量为0xbfc0,0000。
虚拟内存映射图又叫做存储器管理模型、内存模型、内存地址策略等等。例如,Intel 的8086就是使用20位地址线的寻址策略,即16位段地址+16位偏移地址。
X86的存储器管理模型
待续
ARM的存储器管理模型
因为ARM公司只做ARM的内核,其他公司在获得ARM的内核后自行生产自己的SOC芯片 ,所以不同厂家生产的芯片,启动代码也不尽相同,但是启动代码大都实现以下功能:
- 中断向量表的定义
- 堆栈初始化
- 系统变量初始化
- 中断系统初始化
- 地址重映射
中断向量表
ARM要求中断向量表必须放置在从0地址开始,连续8x4字节的空间内(ARM720T和ARM9、ARM10也支持从0xFFFF0000开始的高地址向量表)。每当一个中断发生以后,ARM处理器便强制把PC指针置为向量表中对应中断类型的地址值。因为每个中断只占据向量表中1个字的存储空间,只能放置一条ARM指令,使程序跳转到存储器的其他地方,再执行中断处理。
各异常和中断向量在向量表中的位置如下:
地址 | 中断 | 描述 | 优先级 |
---|---|---|---|
0x00 | Reset | 复位 | 1 |
0x04 | Undef | 未定义指令中断 | 6 |
0x08 | SWI | SWI | 6 |
0x0C | Prefetch Abort | 预取指令中断 | 5 |
0x10 | Data Abort | 数据中止中断 | 2 |
0x14 | (Reserved) | 保留 | |
0x18 | IRQ | IRQ | 4 |
0x2C | FIQ | FIQ | 3 |
中断向量对应ARM处理器的7种运行模式。特权模式包括fiq、irq、svc、abt、und、sys,程序可以访问所有的系统资源,也可以任意切换处理器模式。异常模式包括fiq、irq、svc、abt、und。SWI指令用于产生软中断,ARM从用户模式变换到管理模式(供操作系统使用的一种保护模式)。在操作系统中表现为系统调用。
用户模式(usr) -- 正常程序执行模式 |-- |-- 快速中断模式(fiq) -- 用于高速数据传输和通道处理 特 | 异 | 外部中断模式(irq) -- 用于通常的中断处理 权--| 常--| 管理员模式(svc) -- 供操作系统使用的一种保护模式 模 | 模 | 数据访问中止模式(abt) -- 用于虚拟存储及存储保护 式 | 式 |-- 未定义指令中止模式(und) -- 用于支持通过软件仿真硬件的协处理器 |---------- 系统模式(sys) -- 用于运行特权级的操作系统任务
上面的中断向量表在代码中实现如下(startup.s):
AREA Boot ,CODE, READONLY ENTRY B ResetHandler B UndefHandler B SWIHandler B PreAbortHandler B DataAbortHandler B ;for reserved interrupt, stop here B IRQHandler B FIQHandler
其中关键字ENTRY是指定编译器保留这段代码,因为编译器可能会认为这是一段亢余代码而加以优化。链接的时候要确保这段代码被链接在0地址处,并且作为整个程序的入口。
地址重映射
地址转换器受控制寄存器MENMAP的控制,用户可以设置MENMAP实现对地址重映射的控制。这个地址转换器显然是通过内部硬件电路实现的。
虚拟地址和物理地址
对于底层软件工程师来说,很多时候都在和地址打交道。由于以前学习不够系统,各种技术资料专业术语不统一,以及现代SOC芯片的模块集成的复杂,在开发和阅读中,地址的概念可能比较混淆。下面以bcm5836芯片为例,说明其中需要使用到的各类地址的关系。其中重点是虚拟地址(Virtual Address VA)和物理地址(Physical Address PA)。
Virtual Address
在谈及CPU体系架构(ARM体系,MIPS体系,X86体系等等)时,通常会涉及到地址空间(address space)的概念。此时,需要了解的是该处理器核的地址线宽度,例如16位地址线,32位地址线,或者64位。此时,可能会给出一个内存映射图(memory map)。其实,这些就是上面几节所说的CPU存储器管理模型。
内存映射图给出的地址,是虚拟地址(virtual address)。因为这里的地址,表示的是CPU核在运算时使用的寻址的地址,也就是程序计数指针(PC)的值。该地址还会被经过一系列的转化(例如,MMU转化,丢弃最高位N根地址线等操作),才会变为实际对其他外围器件(这里的外围是指除CPU核之外,最常见的是内存,Flash等)进行寻址时使用的地址。
必须强调,对于软件开发,我们使用的地址都是虚拟地址。无论是在汇编代码中,还是在C语言代码中。如果涉及到一些物理地址的操作,我们也要将之转化为虚拟地址。例如:
romInit.s Line 1038 …… /* * Memory segments (32bit kernel mode addresses) */ #define KUSEG 0x00000000 #define KSEG0 0x80000000 #define KSEG1 0xa0000000 #define KSEG2 0xc0000000 #define KSEG3 0xe0000000 /* * Map an address to a certain kernel segment */ #define _KSEG0ADDR(a) (((a) & 0x1fffffff) | KSEG0) #define _KSEG1ADDR(a) (((a) & 0x1fffffff) | KSEG1) #define _KSEG2ADDR(a) (((a) & 0x1fffffff) | KSEG2) #define _KSEG3ADDR(a) (((a) & 0x1fffffff) | KSEG3) ……
“kernel segment”就是指MIPS的虚拟地址空间,宏_KSEG0ADDR(a)等就是将物理地址a(显然,物理地址有效范围只有512M)转化成为对应MIPS的虚拟地址空间段的虚拟地址。下面是BootROM中的一个实际应用。
romInit.s Line 1065 …… #define SB_ENUM_BASE 0x18000000 /* Enumeration space base */ …… board_draminit: SYSLED(LED_RED) /* Save return address */ move t6,ra # change v0 to t6 /* Scan for an SDRAM controller (a0) */ li a0, _KSEG1ADDR(SB_ENUM_BASE) ……
在对RAM的初始化的时候,就用到了物理地址到虚拟地址的转化。SB_ENUM_BASE定义在Sbconfig.h文件中。有关0x18000000物理地址的相关知识,参考下一节中的SOC的内存映射关系表,可以看到,这其实是SOC片上模块的起始地址,在下一节中将会讲到,这就是一个物理地址。
Physical Address
在SOC上,都有很多功能模块的集成,例如SDRAM控制模块,AD模块,GPIO模块等。这个时候,就涉及到各个模块的地址。通俗讲,就是CPU核是如何找到这些模块的呢,是如何配置这些模块相关寄存器,如何向这些模块存取数据?
这个时候,关系到SOC片上资源地址空间的划分问题。例如,对于芯片bcm5836来说,地址映射关系如下表:
每一个地址范围对应什么资源都是由上表确定的。在这里的地址,就是物理地址。
VA和PA的映射关系
首先,我们看bcm5836地址映射关系图。这是bcm5836这片SOC芯片上,虚拟地址到物理地址的映射关系图。
左边的虚拟地址分布,就是MIPS CPU架构的基本地址空间的情况,对于某一固定的CPU架构,一般是不会变化的。参考《See MIPS Run》P47。右边的物理地址分布,主要是由SOC芯片来决定的。对于采用同一MIPS CPU架构的不同SOC,可能不会相同。具体的分布,需要参考的是SOC的设计说明书。
下面图 2 5 TL-SL5428的FLASH和SDRAM虚拟物理地址映射,介绍的是采用harrier方案的交换机TL-SL5428中,有关VA和PA的映射关系图。需要对照上面两节的图表来分析。
上图中,需要说明的一点就是FLASH空间的映射关系。可以看到,从0xbfc0.0000到0xc000.0000的4M空间和从0xbc00.0000到0xbc80,0000的8M空间是由重合的。其实,我们可以翻过去看到,在图 2 3 bcm5836地址映射关系(2)中,有这么一段:
那上面这两行是什么意思呢?其实,就是说,物理地址从0x1fc0.0000到0x1fff.ffff的4M空间和从0x1c00.0000开始的32M空间,被flash控制模块映射到实际的flash器件的时候,是属于同一位置。其实,这里是MIPS CPU的虚拟地址转化成物理地址(在这里就是kseg1段去掉高位3根地址线)之后,flash控制模块又将物理地址映射到实际器件的时候,将某一部分物理地址进行了重合。 在开发过程中,常说,CPU上电之后的开始运行的地址是0xbfc0.0000(又叫做系统启动向量),所以我们bootrom的第一行代码就放在虚拟地址0xbfc0.0000所对应的物理地址处(对于软件开发,可能无需了解该地址。因为芯片设计的原因,可能有多个虚拟地址对应此处的同一个物理地址)。 如上所述,可能有多个虚拟地址对应此处的同一个物理地址。我们在使用windriver bench 进行bootrom烧写flash的时候,可以看到需要选择的flash的基地址为0xbc00.0000,结束地址为0xbc7f.ffff(一共8M)。其实,这个虚拟地址0xbc00.0000也是对应flash器件的起始地址。
其它地址
在开发过程中,还会遇到其它的一些关于地址的概念,下面列举出一些。其实,只要了解了虚拟地址和物理地址的关系,这些名字都是虚拟地址或者物理地址在特定环境下的别名。
- logical address
- running address
- compiling address