浅谈LINUX中断的注册及执行流程(一)

前言

本文章的目的仅为记录学习过程中的学习心得,不作为任何参考依据。

异常处理

当arm产生异常时,会跳转到对应的向量表中去执行,在linux下,以4.9版本为例,异常向量的入口在arch/arm64/kernel/entry.S 中

/*
 * Exception vectors.
 */
	.pushsection ".entry.text", "ax"

	.align	11
ENTRY(vectors)
	ventry	el1_sync_invalid		// Synchronous EL1t
	ventry	el1_irq_invalid			// IRQ EL1t
	ventry	el1_fiq_invalid			// FIQ EL1t
	ventry	el1_error_invalid		// Error EL1t

	ventry	el1_sync			// Synchronous EL1h
	ventry	el1_irq				// IRQ EL1h
	ventry	el1_fiq_invalid			// FIQ EL1h
	ventry	el1_error_invalid		// Error EL1h

	ventry	el0_sync			// Synchronous 64-bit EL0
	ventry	el0_irq				// IRQ 64-bit EL0
	ventry	el0_fiq_invalid			// FIQ 64-bit EL0
	ventry	el0_error_invalid		// Error 64-bit EL0

#ifdef CONFIG_COMPAT
	ventry	el0_sync_compat			// Synchronous 32-bit EL0
	ventry	el0_irq_compat			// IRQ 32-bit EL0
	ventry	el0_fiq_invalid_compat		// FIQ 32-bit EL0
	ventry	el0_error_invalid_compat	// Error 32-bit EL0
#else
	ventry	el0_sync_invalid		// Synchronous 32-bit EL0
	ventry	el0_irq_invalid			// IRQ 32-bit EL0
	ventry	el0_fiq_invalid			// FIQ 32-bit EL0
	ventry	el0_error_invalid		// Error 32-bit EL0
#endif
END(vectors)

其中,ventry被定义为

 .macro	ventry	label
.align	7
b	\label
.endm

这是一段宏定义,意思是以不返回的形式跳转到label表示处。

这个表存在具体什么地址中呢,对于ARM V8架构来说(arm V7不是这个形式),下面是其异常向量表
在这里插入图片描述
从这张表我们可以知道,这些向量被分为两组,每一组又被分为两个子组:

异常等级有变化(准确来说是异常等级提高,从低等级进入到更高等级,Exception from Lower EL)

  1. 低等级是AArch32状态
  2. 低等级是AArch64状态

异常等级无变化

  1. 异常使用SP_ELx。
  2. 异常使用SP_EL0。

在linux下,内核态下产生中断,偏移地址为0x280;用户态下,偏移地址为0x480

这个表的基地址可以来设置寄存器VBAR_ELx(在linux中通常是VBAR_EL1)。
读写方式为

MRS <Xt>, VBAR_EL1
MSR VBAR_EL1, <Xt>

在这里插入图片描述

当内核中产生中断时,由于在ARM V8架构上,用户态运行在el0等级,此时产生中断,会陷入到内核态,即el1等级,因此其对应会执行el0_irq 函数

		.align	6
el0_irq:
	kernel_entry 0
el0_irq_naked:
	enable_dbg
#ifdef CONFIG_TRACE_IRQFLAGS
	bl	trace_hardirqs_off
#endif

	ct_user_exit
	irq_handler

#ifdef CONFIG_TRACE_IRQFLAGS
	bl	trace_hardirqs_on
#endif
	b	ret_to_user
ENDPROC(el0_irq)

代码最终会执行irq_handler处理函数,来处理用户态中断。ret_to_user用于返回用户态(前面讲到,发生中断后,从用户态切到了内核态)。再来看irq_handler函数

	.macro	irq_handler
ldr_l	x1, handle_arch_irq
mov	x0, sp
irq_stack_entry
blr	x1
irq_stack_exit
.endm

这也是一个宏定义,调用handle_arch_irq,handle_arch_irq在\arch\arm64\kernel\irq.c文件中被赋值。

void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
{
	if (handle_arch_irq)
		return;

	handle_arch_irq = handle_irq;
}

显而易见,该函数是在linux启动过程中只想特定的函数地址的这也符合linux的特点,任何驱动都可以通过指针去定义。后面的初始化以及中断注册,留给后面慢慢讲。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值