之前调了在Bootloader下bring up secondary cpu, arch是armv7, gic v2,记录下。

Hardware logic

+----------+       +------------+        +-------------+        +------------+       +----+
|soc timer |--1--> |soc int ctrl| --2--->|arm gic dist | -|-3a->|arm gic cpu0| -4a-> |cpu0|
+----------+ +------------+ +-------------+ | +------------+ +----+
|
| +------------+ +----+
|-3b->|arm gic cpu1| -4b-> |cpu1|
+------------+ +----+

首先外设timer中断上报中断控制器,这个timer和中断控制器应该是SoC自己的东东, 各自都应该有个中断状态可以看到中断是不是已经产生了。

下来就是ARM的gic,我调的是v2, 一般都有id寄存器可以确认gic版本。gic分成gic dist和gic cpu interface,dist就是负责forwarding转发中断到cpu interface上, 如上图转发中断到gic cpu0 or gic cpu1 or both,都可以控制。

而gic cpu interface就是负责把中断上报给cpu core里,cpu core里都有各自的arch local interrupt,使能就可以看到了。

整个过程需要确认状态调试。

GIC Debug

gic这块的初始化配置主要分为dist和cpu两块。

dist是全局的,一般放到cpu0上先初始化一下就可以了, gic cpu因为是per cpu, 所以在每个cpu上都要配置一下。

gic的中断分为两块,0-31个中断是per cpu,32-max是全局中断, 一般对于SoC来说, 需要自定义也就是分配中断号,都是从32号开始,所以看kernel代码会有个base是32。

对于dist把中断转发给那个cpu interface,有个寄存器可以配, 就是每个中断你要分配给哪个或哪些cpu了,比如gicv2里max cpu是8个,那就需要用8个bit来表示8个cpu,分别是cpu0-cpu7, 要想把某个中断分给cpu0,那就是0x1, 要分给cpu1就是0x2,分给cpu0也分给cpu1,那就是0x3了。

对于gic是否有中断上来, 有个寄存器可以查看这个状态,就是中断响应寄存器(GICC_IAR,应该是这个名字),也就是中断服务处理里获取中断号的寄存器。如果这个一直是1023,那么你就要查查状态了。手册里面有写,基本上就是有没有使能gic中断之类,即使code使能了, 也要打印出来确认!

在没有装stack和vector之前,可以先disable cpu core的local interrupt,这样你在cpu上应该能看到GICC_IAR的中断号,只有看到了,才说明gic的调试过了,否则继续debug。soc timer int状态确认, soc int contr interrupt status确认,gic dist中断使能确认,target cpu转发确认…

exception vector table

上面调试过了,下面就要来调试cpu1的向量表安装了,注意这个时候mmu cache的都是禁用的。

说到向量表, 必须要提到它的位置,一般有两种,低地址和高地址之分。例如cortex a7有个重要的配置就是系统控制寄存器,它有个bit13就是来控制这个向量表在低还是在高。

我的问题是打开cpu1的local interrupt enable后就死了。这个时候的调试,mmu关闭,cache关闭,除了svc stack其他模式 stack没有安装,cpu0的处理也关闭了, 最好禁用cpu0的local资源,比如local arch irq最好了。cpu1尽量保持和cpu0的start up code一致, 其实cpu1启动时刚开始执行的就是一个svc stack安装,下来就是vector安装。

这时到底是死在哪里了,唯一怀疑就是向量表没响应导致的死机,仔细看了看arm arch手册,cortex rpm手册啊,arm develop手册,最后看到了向量表位置可以控制,就是前面提到的,赶紧打开看看,发现cpu0和cpu1的sys ctrl果然不同,一看bit13 cpu0是0,而cpu1是1, 这不就是了嘛, 改成0后刚才在中断处理加的汇编打印果然有了:] cpu1 stack和cpu0一样就可以了,