在《RTEMS初始化-bootcard调用流程》中就已经简单初始化中断向量表的过程,但其目的是为了梳理bootcard的调用流程,本文基于RTEMS的中断管理逻辑来分析RTEMS的中断管理功能,从而更清晰的了解RTEMS的中断管理
中断向量表的填充在aarch64-exception-default.S
中,里面会实现全局变量bsp_start_vector_table_begin的值,根据aarch64的定义中断有如下基本点
所以我们可以看到rtems填入中断的方式如下
curr_el_sp0_sync: .dword _AArch64_Exception_default .balign 0x80 curr_el_sp0_irq: JUMP_HANDLER JUMP_TARGET_SP0 .balign 0x80 curr_el_sp0_fiq: JUMP_HANDLER JUMP_TARGET_SP0 .balign 0x80 curr_el_sp0_serror: JUMP_HANDLER JUMP_TARGET_SP0 .balign 0x80 curr_el_spx_sync: .dword _AArch64_Exception_default .balign 0x80 curr_el_spx_irq: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 curr_el_spx_fiq: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 curr_el_spx_serror: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch64_sync: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch64_irq: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch64_fiq: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch64_serror: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch32_sync: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch32_irq: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch32_fiq: JUMP_HANDLER JUMP_TARGET_SPx .balign 0x80 lower_el_aarch32_serror: JUMP_HANDLER JUMP_TARGET_SPx
可以看到,上述代码和arm64 spec描述完全一致
这部分内容在《RTEMS初始化-bootcard调用流程》提过,这里基于gic-v3再简单描述一下。
bsp_start bsp_interrupt_initialize bsp_interrupt_facility_initialize arm_interrupt_facility_set_exception_handler AArch64_set_exception_handler AArch64_get_vector_base_address char *vbar = VBAR_EL1 char *cvector_address = vbar + VECTOR_ENTRY_SIZE * exception + VECTOR_POINTER_OFFSET;
初始化共两个函数,我们逐步解析
gicv3_init_dist(ARM_GIC_DIST); gicv3_init_cpu_interface(_SMP_Get_current_processor());
对于init dist,如下
static void gicv3_init_dist(volatile gic_dist *dist) { uint32_t id_count = gicv3_get_id_count(dist); uint32_t id; dist->icddcr = GIC_DIST_ICDDCR_ARE_NS | GIC_DIST_ICDDCR_ARE_S | GIC_DIST_ICDDCR_ENABLE_GRP1S | GIC_DIST_ICDDCR_ENABLE_GRP1NS | GIC_DIST_ICDDCR_ENABLE_GRP0; for (id = 0; id < id_count; id += 32) { /* Disable all interrupts */ dist->icdicer[id / 32] = 0xffffffff; /* Set G1NS */ dist->icdigr[id / 32] = 0xffffffff; dist->icdigmr[id / 32] = 0; } for (id = 0; id < id_count; ++id) { gic_id_set_priority(dist, id, PRIORITY_DEFAULT); } for (id = 32; id < id_count; ++id) { gic_id_set_targets(dist, id, 0x01); } }
对于icddcr,对于GICD_CTLR寄存器,设置如下
dist->icddcr = GIC_DIST_ICDDCR_ARE_NS | GIC_DIST_ICDDCR_ARE_S | GIC_DIST_ICDDCR_ENABLE_GRP1S | GIC_DIST_ICDDCR_ENABLE_GRP1NS | GIC_DIST_ICDDCR_ENABLE_GRP0;
这里功能描述如下
这是distributor寄存器,其中开启了
也就是说这里开启了中断优先级路由和中断分发
对于dist->icdicer[id / 32] = 0xffffffff
这里对应寄存器GICD_ISENABLER,写1先禁用所有中断
对于dist->icdipr[id] = priority
这里对于寄存器GICD_IPRIORITYR,写入实际的优先级
对于dist->icdiptr[id] = targets;
这里对于寄存器GICD_ITARGETSR,写入中断处理目标寄存器(发给哪个CPU)
其他还有寄存器如下
volatile gic_redist *redist = gicv3_get_redist(cpu_index);
redistributor寄存器地址
在gdb中,我们可以查看中断向量表基地址为bsp_start_vector_table_begin,如下
0x6d000 <bsp_start_vector_table_begin>
对于中断的入口函数,其地址是entry + 0x78。 因为向量表的offset就是0x78,如下
#define VECTOR_POINTER_OFFSET 0x78
如果是sp0_irq,那么其地址是0x6dc98,0x6dc98是入口地址_AArch64_Exception_interrupt_nest
(gdb) x curr_el_sp0_irq + 0x78 0x6d0f8 <curr_el_sp0_irq_get_pc+112>: 0x000000000006dc98 (gdb) x 0x000000000006dc98 0x6dc98 <_AArch64_Exception_interrupt_nest>:
如果是spx_irq,那么其地址是0x6ddac,0x6ddac是入口地址_AArch64_Exception_interrupt_no_nest
(gdb) x curr_el_spx_irq + 0x78 0x6d2f8 <curr_el_spx_irq_get_pc+112>: 0x000000000006ddac (gdb) x 0x000000000006ddac 0x6ddac <_AArch64_Exception_interrupt_no_nest>:
对于未设置入口的sp0,其宏定义如下
.macro JUMP_TARGET_SP0 .dword .print_exception_dump_sp0 .endm
以curr_el_sp0_fiq为例也就是.print_exception_dump_sp0 其他类似
(gdb) x curr_el_sp0_fiq + 0x78 0x6d178 <curr_el_sp0_fiq_get_pc+112>: 0x000000000006d844 (gdb) x 0x000000000006d844 0x6d844 <.print_exception_dump_sp0>:
对于未设置入口的spx,其宏定义如下
.macro JUMP_TARGET_SPx .dword .print_exception_dump_spx .endm
以curr_el_spx_fiq为例也就是.print_exception_dump_spx,值得注意的是.print_exception_dump_spx的地址等于bsp_start_vector_table_end 其他类似
(gdb) x curr_el_spx_fiq + 0x78 0x6d378 <curr_el_spx_fiq_get_pc+112>: 0x000000000006d800 (gdb) x 0x000000000006d800 0x6d800 <bsp_start_vector_table_end>:
这里讲清楚了rtems中的中断向量表和gic-v3的中断初始化过程,接下来我们从中断触发的角度继续了解中断管理