17. OP-TEE中的中断处理(三)------系统IRQ事件的处理

本文详细介绍了在OP-TEE中SecureWorld态下IRQ事件的处理流程。包括中断响应、foreign_intr_handler宏的作用、SMC指令触发后的Monitor态处理及返回SecureWorld态的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   

  

IRQ事件的处理一般会用在ROS端,但是当CPU为是secure world态时,系统产生了IRQ事件,而该事件又不能被暴力的作为无用事件而轻易丢弃,系统还是需要有响应并执行相关操作的。那针对该种情况,在在OP-TEE文件当,针对这种情况的处理方式和逻辑图如下,本文将从介绍secure world态下对IRQ事件的处理逻辑:

1. OP-TEE中对IRQ事件的响应

  在系统初始化的时候,系统会调用thread_init_vbar函数来初始化secure world态的中断向量表并将中断向量的地址保存到VBAR寄存器中。所以在secure world态中产生了IRQ事件的时候,系统将会通过VBAR寄存器获取到中断向量表地址,然后命中写入的IRQ事件处理函数thread_irq_handler函数并逐步执行解析IRQ事件并处理之,整个处理过程的流程图如下图所示:

1.1 thread_irq_handler函数

  在《15. OP-TEE中的中断处理(一)------中断配置和向量表的配置》介绍了在secure world态中中断向量表的初始化,thread_vect_table即为secure world态的中断向量,当IRQ事件发生时,系统将调用thread_irq_handler函数来对IRQ事件进行处理,该函数定义在optee_os/core/arch/arm/kernel/thread_a32.S文件中,其内容如下:

LOCAL_FUNC thread_irq_handler , :
UNWIND(	.fnstart)
UNWIND(	.cantunwind)
#if defined(CFG_ARM_GICV3)
	native_intr_handler	irq
#else
	foreign_intr_handler	irq
#endif
UNWIND(	.fnend)
END_FUNC thread_irq_handler

  由于没有使能GICV3,所以最终会调用foreign_intr_handler宏来对IRQ事件进行处理。

1.2 foreign_intr_handler宏

  foreign_intr_handler宏将suspend系统当前正在执行的thread并进行相关的设置后调用smc指令出发smc时间,将cpu状态切换到monitor态进行进一步处理。

.macro foreign_intr_handler mode:req
	.ifc	\mode\(),irq
	/*
	 * Disable FIQ if the foreign interrupt is sent as IRQ.
	 * IRQ mode is set up to use tmp stack so FIQ has to be
	 * disabled before touching the stack. We can also assign
	 * SVC sp from IRQ sp to get SVC mode into the state we
	 * need when doing the SMC below.
	 * If it is sent as FIQ, the IRQ has already been masked by hardware
	 */
	cpsid	f
	.endif
	sub	lr, lr, #4
	push	{lr}
	push	{r12}

	.ifc	\mode\(),fiq
	bl	thread_save_state_fiq
	.else
	bl	thread_save_state
	.endif

	mov	r0, #THREAD_FLAGS_EXIT_ON_FOREIGN_INTR
	mrs	r1, spsr
	pop	{r12}
	pop	{r2}
	blx	thread_state_suspend	//suspend当前系统中thread
	mov	r4, r0		/* Supply thread index */

	/*
	 * Switch to SVC mode and copy current stack pointer as it already
	 * is the tmp stack.
	 */
	mov	r0, sp
	cps	#CPSR_MODE_SVC
	mov	sp, r0

	ldr	r0, =TEESMC_OPTEED_RETURN_CALL_DONE
	ldr	r1, =OPTEE_SMC_RETURN_RPC_FOREIGN_INTR
	mov	r2, #0
	mov	r3, #0
	/* r4 is already filled in above */
	smc	#0	//调用smc,出发smc事件将CPU状态切换到monitor执行进一步的处理
	b	.	/* SMC should not return */
.endm

1.3 monitor态下的smc处理

  当系统触发smc之后,cpu进入到monitor态,并进入到monitor态下的smc处理函数sm_smc_entry,当执行smc之后相当于产生了类似软中断的操作,而该为何执行smc之后CPU会执行sm_smc_entry函数请阅读《16. OP-TEE中的中断处理(二)------系统FIQ事件的处理》中的1.1章节。sm_smc_entry函数定义在optee_os/core/arch/arm/sm/sm_a32.S文件中,其内容如下:

LOCAL_FUNC sm_smc_entry , :
UNWIND(	.fnstart)
UNWIND(	.cantunwind)
	srsdb	sp!, #CPSR_MODE_MON
	push	{r0-r7}

	clrex		/* Clear the exclusive monitor */

	/* Find out if we're doing an secure or non-secure entry */
	read_scr r1
	tst	r1, #SCR_NS
	bne	.smc_from_nsec

	/*
	 * As we're coming from secure world (NS bit cleared) the stack
	 * pointer points to sm_ctx.sec.r0 at this stage. After the
	 * instruction below the stack pointer points to sm_ctx.
	 */
	sub	sp, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)

	/* Save secure context */
/* 保存secure world的context */
	add	r0, sp, #SM_CTX_SEC
	bl	sm_save_modes_regs

	/*
	 * On FIQ exit we're restoring the non-secure context unchanged, on
	 * all other exits we're shifting r1-r4 from secure context into
	 * r0-r3 in non-secure context.
	 */
/* 配置好传递到non-secure world的参数 */
	add	r8, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)
	ldm	r8, {r0-r4}
	mov_imm	r9, TEESMC_OPTEED_RETURN_FIQ_DONE
	cmp	r0, r9
	addne	r8, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
	stmne	r8, {r1-r4}

	/* Restore non-secure context */
/* 加载non-secure world态的context */
	add	r0, sp, #SM_CTX_NSEC
	bl	sm_restore_modes_regs

/* 返回到non-secure world态 */
.sm_ret_to_nsec:
	/*
	 * Return to non-secure world
	 */
	add     r0, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R8)
	ldm	r0, {r8-r12}

	/* Update SCR */
	read_scr r0
	orr	r0, r0, #(SCR_NS | SCR_FIQ) /* Set NS and FIQ bit in SCR */
	write_scr r0

	add	sp, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
	b	.sm_exit	//退出smc操作,切换到non-secure world态

.smc_from_nsec:
	/*
	 * As we're coming from non-secure world (NS bit set) the stack
	 * pointer points to sm_ctx.nsec.r0 at this stage. After the
	 * instruction below the stack pointer points to sm_ctx.
	 */
	sub	sp, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)

	bic	r1, r1, #(SCR_NS | SCR_FIQ) /* Clear NS and FIQ bit in SCR */
	write_scr r1

	add	r0, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R8)
	stm	r0, {r8-r12}

	mov	r0, sp
	bl	sm_from_nsec
	cmp	r0, #0
	beq	.sm_ret_to_nsec

	/*
	 * Continue into secure world
	 */
	add	sp, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)

.sm_exit:
	pop	{r0-r7}
	rfefd	sp!
UNWIND(	.fnend)
END_FUNC sm_smc_entry

1.4 返回到secure world态中继续执行

  当monitor态将IRQ事件传递到了non-secure world后并将CPU的状态切换到non-secure world态之后,ROS将根据具体得到的参数执行具体的IRQ事件的处理。当完成IRQ事件处理自后,会调用smc重新切回到monitor态,然后恢复secure world中被中断的thread状态继续执行。


 




 

### 中断处理概述 中断机制使得CPU可以在遇到紧急事件时暂时停止当前的任务,转向处理这些突发事件。当中断被触发后,处理器保存当前状态并跳转到指定位置执行一段专门用于应对该类事件的代码——即中断服务子程序(ISR),待ISR完成后恢复之前的工作[^1]。 对于更复杂的环境如Linux操作系统或者安全运行环境(OP-TEE),其中断管理涉及更多层次的设计与实现,不仅限于硬件层面还包括软件调度等方面的内容[^2]。 ### 完整的中断处理过程 #### 1. 中断请求阶段 当外设检测到了某个条件满足(比如定时器溢出、串口接收到数据等),就会向CPU发出信号表示有事情要报告给它知道;此时如果此类型的中断已经被使能,则可以引起后续动作的发生。 #### 2. 中断响应阶段 一旦确认了存在有效的未决中断,CPU会在完成当前指令之后立即采取行动:先将必要的寄存器压栈以保护现场;接着更新PC指针指向对应的异常向量表地址处获取目标函数入口地址. #### 3. 执行中断服务例程 (Interrupt Service Routine, ISR) 进入具体的ISR逻辑部分,在这里编写者定义如何具体地去回应所发生的特殊状况。这可能涉及到读取某些I/O端口的状态位来判断是什么原因造成了此次中断,并据此做出适当反应,例如清除标志位、调整计数器数值或是启动其他任务等等操作。 #### 4. 返回原工作点继续执行 最后一步就是从中断模式退出恢复正常运作流程前要做的一些清理收尾性质的事情,像弹出先前存储起来的重要信息以便能够无缝衔接回原先被打断的位置上继续往下走。 ```c void __attribute__((interrupt)) Timer_ISR(void){ // 清除定时器中断标志 TIFR |= (1 << TOV0); // 用户自定义功能... } ``` 上述C语言风格的例子展示了怎样创建一个简单的定时器中断服务程序[^3]。需要注意的是真正的OS级ISR可能会更为复杂一些因为它还需要考虑同步互斥等问题以及与其他系统的交互接口设计等因素影响下的性能优化考量。 ### Linux外部中断初始化实例 下面给出了一段针对ARM架构下GPIO引脚作为外部中断源配置的相关片段: ```c static struct irqaction my_irq = { .handler = gpio_irq_handler, .flags = IRQF_TRIGGER_RISING | IRQF_SHARED, .name = "my_gpio_irq", }; // 注册IRQ handler if (request_irq(gpio_to_irq(GPIO_PIN), &my_irq, IRQF_SHARED, "my_gpio_irq", NULL)){ printk(KERN_ERR "Failed to request GPIO interrupt\n"); return -EINVAL; } // 启用IRQ line enable_irq(gpio_to_irq(GPIO_PIN)); ``` 这段代码实现了对外部中断线的基本设置,包括但不限于关联用户提供的回调函数(handler)、设定触发方式(flags)还有命名(name)[^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值