编辑
2025-04-30
记录知识
0
请注意,本文编写于 58 天前,最后修改于 54 天前,其中某些信息可能已经过时。

目录

中断向量表
初始化中断向量表
gic-v3初始化
查看中断向量表
总结

在《RTEMS初始化-bootcard调用流程》中就已经简单初始化中断向量表的过程,但其目的是为了梳理bootcard的调用流程,本文基于RTEMS的中断管理逻辑来分析RTEMS的中断管理功能,从而更清晰的了解RTEMS的中断管理

中断向量表

中断向量表的填充在aarch64-exception-default.S中,里面会实现全局变量bsp_start_vector_table_begin的值,根据aarch64的定义中断有如下基本点

  • 向量表大小是2k
  • 每个中断向量表按照128字节对齐

image.png

所以我们可以看到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;

gic-v3初始化

初始化共两个函数,我们逐步解析

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;

这里功能描述如下

image.png

这是distributor寄存器,其中开启了

  • non-secure和secure下开启 优先级路由
  • non-secure和secure下开启 group1的中断分发
  • 开启group0的中断分发 这里group0代表el3的中断组
    group1 secure代表trustOS或EL2上的中断组。 group1 non-secure代表VMM或OS的中断组

也就是说这里开启了中断优先级路由和中断分发

对于dist->icdicer[id / 32] = 0xffffffff 这里对应寄存器GICD_ISENABLER,写1先禁用所有中断

对于dist->icdipr[id] = priority 这里对于寄存器GICD_IPRIORITYR,写入实际的优先级

对于dist->icdiptr[id] = targets; 这里对于寄存器GICD_ITARGETSR,写入中断处理目标寄存器(发给哪个CPU)

其他还有寄存器如下

  • ICC_SRE: 中断使能寄存器
  • ICC_PMR: 中断优先级屏蔽寄存器
  • ICC_BPR: 中断优先级分组寄存器

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的中断初始化过程,接下来我们从中断触发的角度继续了解中断管理