在生活中,我们使用了很多CPU,但是通常都只是移植,这个问题在Linux当中尤为突出。因此,很多底层系统工程师尴尬的连ARMv7体系结构都不知道。首先,ARMv7和ARMv8是arm的一种标准而不是一块芯片,arm的cortex系列cpu都是采用的这两个体系结构。ARMv7是指32位的arm cpu芯片,ARMv8是指64位的arm cpu芯片。在ARMv7中,常用模式来表示当前所处的状态,而ARMv8则改成了异常等级来描述当前的状态(淘汰了以前的mode)。本篇简单分析armv7。
下面我简单看看armv7的系统框架图(该图来自于《cortex_A_series_PG.pdf》):
从图中可以看到,一个ARMv7的核可能包含以下部分:1、cpu processor:这就是我们常说的CPU;2、cache: 高速缓存; 3、scu:缓存同步单元等。
注:一个CPU里面,可能存在1到多个cluster,每个cluster包含1到多个processor。在每个cluster里面processor都是从0开始编号的。
注:在armv7 cortext-m当中没有cache和mmu。
ARMv7理论上说拥有9个模式(3个特权等级PL0-PL2),但通常都说是7个模式,逻辑图如下:
当我们说成是7个的时候,通常是省略了MON和HYP这两个,其中MON主要用于trust OS(安全OS),而HYP主要用于hypervisor(虚拟化)。Usr模式,通常是我们说的用户态;FIQ模式,为快速中断模式;IRQ模式,为我们平时使用的中断模式(FIQ优先级高于IRQ)。SVC模式,内核操作系统常用的模式;ABT模式,访问存储异常模式;UND模式,运行未定义指令;SYS模式,目前大部分系统都未使用。
下图为芯片运行时候的逻辑效果图:
如上可见,hypervisor上可以运行多个OS,每个OS就是一个系统如Linux系统,但是hypervisor只能运行在unsecure模式下,而trust OS主要运行在secure模式下面。hypervisor的权限比SVC的权限更高,可以管控SVC模式和USR模式。
下图为不同模式下寄存器的使用情况:
从上图,我们可以知道R0-R7,PC是所有模式下共享的。而其他寄存器则是在不同模式下都可能有备份,其中典型代表是CPSR程序状态寄存器、LR链接寄存器和SP栈寄存器。因此,每个模式都 有一个栈寄存器,当操作系统发生模式切换的时候,CPU硬件会自动转换内部所使用的栈寄存器。
寄存器的含义:参考《32位ARM寄存器和栈使用浅析》章节
浮点处理单元和NEON处理单元这里不做说明。
高速L1缓存cache: 参考《ARMv7 L1 cache详解》章节
内存管理单元MMU: 参考《ARMv7多进程基础之MMU篇》章节
中断控制器参考:《ARM中断控制器-GICv2》 章节
异常处理:参考《ARMv7 异常处理》章节
ARMv7运行模式,虽然ARMv7有多个模式,但是操作系统只工作在SVC和USR模式:SVC处于内核态,USR处于用户态。至于其他的异常模式,Linux只是简单的略过。比如中断模式irq,Linux只有很短的汇编代码在irq模式运行,主要是保存上下文,然后就立马切换到了SVC模式,也就是说我们平时用request_irq注册中断的函数 都是工作在SVC模式下的,而不是真正的irq模式。
ARMv7在USR模式下,只能通过系统中断,异常或者系统调用才能进入到SVC模式。而SVC模式下,可以随意切换到USR模式(通过协处理器完成)。
ARMv8运行状态下,操作系统工作于EL1异常模式下,用户态工作于EL0异常模式,hypervisor工作于EL2模式下,secure工作于EL3模式下。同样处于EL0模式下,只能通过中断,系统调用或者异常来提权到EL1模式,EL1模式只能通过HVC指令到达hypervisor的EL2异常。
注:ARMv8的寄存器和ARMv7有很大的差异,中断向量表也发生了变化。