快速连接
👉👉👉【精选】ARMv8/ARMv9架构入门到精通-目录 👈👈👈
1、注册一个中断
注册中断很简单,itr_add和itr_enable就可以了
struct itr_handler temp_irq = {
50, //中断号
0, //flag
temp_itr_handler, //handler
&temp_data[0], //paramaters
{NULL} //link
};
itr_add(&temp_irq);
itr_enable(50);
2、调用到中断处理函数
在secure中断产生后,PE跳转到optee的中断向量表中的irq offset:
el1_irq_sp0:
store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3
b elx_irq
check_vector_size el1_irq_sp0
调用native_intr_handler函数
LOCAL_FUNC elx_irq , :
#if defined(CFG_ARM_GICV3)
native_intr_handler irq
#else
foreign_intr_handler irq
#endif
END_FUNC elx_irq
native_intr_handler调用thread_nintr_handler_ptr,也就是在平台中注册的handler函数
/* The handler of native interrupt. */
.macro native_intr_handler mode:req
/*
* Update core local flags
*/
ldr w1, [sp, #THREAD_CORE_LOCAL_FLAGS]
lsl w1, w1, #THREAD_CLF_SAVED_SHIFT
.ifc \mode\(),fiq
orr w1, w1, #THREAD_CLF_FIQ
.else
orr w1, w1, #THREAD_CLF_IRQ
.endif
orr w1, w1, #THREAD_CLF_TMP
str w1, [sp, #THREAD_CORE_LOCAL_FLAGS]
/* load tmp_stack_va_end */
ldr x1, [sp, #THREAD_CORE_LOCAL_TMP_STACK_VA_END]
/* Keep original SP_EL0 */
mrs x2, sp_el0
/* Switch to SP_EL0 */
msr spsel, #0
mov sp, x1
/*
* Save registers on stack that can be corrupted by a call to
* a C function
*/
/* Make room for struct elx_nintr_rec */
sub sp, sp, #ELX_NINTR_REC_SIZE
/* Store x4..x18 */
store_xregs sp, ELX_NINTR_REC_X(4), 4, 18
/* Store lr and original sp_el0 */
stp x30, x2, [sp, #ELX_NINTR_REC_LR]
bl thread_check_canaries
adr x16, thread_nintr_handler_ptr
ldr x16, [x16]
blr x16
/*
* Restore registers
*/
/* Restore x4..x18 */
load_xregs sp, ELX_NINTR_REC_X(4), 4, 18
/* Load lr and original sp_el0 */
ldp x30, x2, [sp, #ELX_NINTR_REC_LR]
/* Restore SP_El0 */
mov sp, x2
/* Switch back to SP_EL1 */
msr spsel, #1
/* Update core local flags */
ldr w0, [sp, #THREAD_CORE_LOCAL_FLAGS]
lsr w0, w0, #THREAD_CLF_SAVED_SHIFT
str w0, [sp, #THREAD_CORE_LOCAL_FLAGS]
mrs x0, spsr_el1
/* Restore x2..x3 */
load_xregs sp, THREAD_CORE_LOCAL_X2, 2, 3
b_if_spsr_is_el0 w0, 1f
/* Restore x0..x1 */
load_xregs sp, THREAD_CORE_LOCAL_X0, 0, 1
/* Return from exception */
eret
1: b eret_to_el0
.endm
平台的gic中段函数注册,在arch/arm/plat-xxx/main.c中
static const struct thread_handlers handlers = {
.std_smc = tee_entry_std,
.fast_smc = tee_entry_fast,
.nintr = main_fiq,
#if defined(CFG_WITH_ARM_TRUSTED_FW)
.cpu_on = cpu_on_handler,
.cpu_off = pm_do_nothing,
.cpu_suspend = pm_do_nothing,
.cpu_resume = pm_do_nothing,
.system_off = pm_do_nothing,
.system_reset = pm_do_nothing,
#else
.cpu_on = pm_panic,
.cpu_off = pm_panic,
.cpu_suspend = pm_panic,
.cpu_resume = pm_panic,
.system_off = pm_panic,
.system_reset = pm_panic,
#endif
};
如果使用的是gic,在平台的handler函数中,会直接调用gic中的gic_it_handle
static void main_fiq(void)
{
gic_it_handle(&gic_data);
}
我们在看gic_it_handle函数,也是非常的简单,
void gic_it_handle(struct gic_data *gd)
{
uint32_t iar;
uint32_t id;
iar = gic_read_iar(gd); //------------------------从gic中读取中断号
id = iar & GICC_IAR_IT_ID_MASK;
if (id < gd->max_it)
itr_handle(id); //--------------------调用itr_add注册的中断处理函数
else
DMSG("ignoring interrupt %" PRIu32, id);
gic_write_eoir(gd, iar); //--------------------取消中断active(或者叫清除gic中的中断标记)
}
调用gic_it_add注册的中断处理函数
void itr_handle(size_t it)
{
struct itr_handler *h = find_handler(it); //----------------------- 找到itr_add注册时添加的handler
if (!h) {
EMSG("Disabling unhandled interrupt %zu", it);
itr_chip->ops->disable(itr_chip, it);
return;
}
if (h->handler(h) != ITRR_HANDLED) { //-----------------------执行handler
EMSG("Disabling interrupt %zu not handled by handler", it);
itr_chip->ops->disable(itr_chip, it);
}
}
关注"Arm精选"公众号,备注进ARM交流讨论区。