ARM64异常漫谈一:异常向量表

前言


ARMV8的异常向量表较ARMV7的异常向量表有了很大的变动,但是实际上换汤不换药,做事情的方式变了,但是做的事情还是一样的。本文会详细介绍一下ARMV8的异常向量表。

异常routing

下面是异常发生时,exception level切换表:
ARM64异常漫谈一:异常向量表_第1张图片我们举两个例子来说明下:
第一个红色框的内容表示:在此种配置下,EL0和EL1状态下产生的异步异常,会导致CPU进入EL1。
第一个红色框的内容表示:在此种配置下,EL0和EL1状态下产生的异步异常,会导致CPU进入EL1,而EL2状态下产生的异常,不会导致exception level切换。
Linux内核只支持EL0和EL1,EL0对应用户态,EL1对应内核态,当CPU运行在用户态时,产生的异步异常会导致CPU切换到EL1,当CPU运行在内核态时,产生的异步异常不会导致exception level的切换。

中断向量表


闲话不多说,我们先来看一下ARMV8异常向量表的定义:
ARM64异常漫谈一:异常向量表_第2张图片这张表告诉我们以下几点事实:

  • 实际上有四张表,每张表有四个异常入口,分别对应同步异常,IRQ,FIQ和出错异常。
  • 如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL0,那么使用第一张异常向量表。
  • 如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL1/2/3,那么使用第二张异常向量表。
  • 如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH64模式,那么使用第三张异常向量表。
  • 如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH32模式,那么使用第四张异常向量表。
  • 另外我们还可以看到的一点是,每一个异常入口不再仅仅占用4bytes的空间,而是占用0x80 bytes空间,也就是说,每一个异常入口可以放置多条指令,而不仅仅是一条跳转指令。

Linux内核异常向量表

ENTRY(vectors)
	kernel_ventry	el1_sync_invalid		// Synchronous EL1t
	kernel_ventry	el1_irq_invalid			// IRQ EL1t
	kernel_ventry	el1_fiq_invalid			// FIQ EL1t
	kernel_ventry	el1_error_invalid		// Error EL1t

	kernel_ventry	el1_sync			// Synchronous EL1h
	kernel_ventry	el1_irq				// IRQ EL1h
	kernel_ventry	el1_fiq_invalid			// FIQ EL1h
	kernel_ventry	el1_error			// Error EL1h

	kernel_ventry	el0_sync			// Synchronous 64-bit EL0
	kernel_ventry	el0_irq				// IRQ 64-bit EL0
	kernel_ventry	el0_fiq_invalid			// FIQ 64-bit EL0
	kernel_ventry	el0_error			// Error 64-bit EL0

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

首先我们要知道,用户态即EL0使用SP_EL0,内核态即EL1使用SP_EL1,再结合前两节的内容,我们可以得出如下结论:

  • 第一张异常向量表是用不到的,因为EL0使用SP_EL0,但是EL0发生异常会routing到EL1。
  • 第二章异常向量表用于CPU运行在EL1即内核态时,发生异常,因为EL1使用SP_EL1,并且exception level不会发生切换。
  • 第三张向量表用于CPU运行在EL0即用户态AARCH32时,发生异常。
  • 第四张向量表用于CPU运行在EL0即用户态AARCH64时,发生异常。

我们下一篇文章会继续分析异常处理逻辑。

参考文档:

DDI0487C_a_armv8_arm.pdf

你可能感兴趣的:(ARM64异常漫谈)