《Linux内核深度解析》第4章 异常与中断学习
[复制链接]
在ARM64和MIPS这些精简指令集计算机(RISC)体系结构中,中断系统调用和其他打断程序正常执行流的事件统称为异常,这是广义的异常。
异常级别,4个异常级别0-3
异常分为同步异常和异步异常
同步异常是试图执行指令时产生的异常,或是作为指令的执行结果生成的异常。
同步异常包括:
(1)系统调用,例如异常级别0使用SVC指令陷入异常级别1
(2)数据中止,即访问数据时的页错误异常,虚拟地址没有映射到物理地址,或者没有写权限
(3)指令中止,即取指令时的页错误异常,虚拟地址没有映射到物理地址,或没有执行权限
(4)栈指针或指令地址没有对齐
(5)没有定义的指令
(6)调试异常
异步异常,不是由正在执行的指令生成的,和正在执行的指令没有关联
- 中断
- 快速中断
- 系统错误
异步异常感觉更像是MCU里面的一些异常,中断类似于STM32的NVIC中断
系统错误也是类似于STM32的一些HARDFAULT、总线fault或者NMI等
LINUX的异常和MCU也是一样,有一些异常向量表。
异常处理的流程
- 把当前的处理器状态保存在寄存器SPSR_EL1程序状态寄存器中
- 把返回地址保存在寄存器ELR_EL1异常链接寄存器中
- 把处理器状态的DAIF这4个异常掩码位都设置为1.禁止这4种异常
- 如果是同步异常或系统错误异常,把生成异常的原因保存在寄存器ESR_EL1异常症状寄存器中
- 如果是同步异常,把错误地址保存在寄存器FAR_EL1错误地址寄存器中
- 根据向量基准地址寄存器异常类型和生成异常的异常级别额计算出异常向量的虚拟地址,执行异常向量。
这段异常处理流程,其实和CORTEX M3的异常处理流程也是有类似的
LINUX中断处理
第一层处理函数是中断描述符的成员handle_irq()
第二层处理函数是设备驱动程序注册的处理函数。中断描述符由一个中断处理链表(irq_desc.action),每个中断处理描述符(irq_action)保存设备驱动程序注册的处理函数。因为多个设备可以共享同一个硬件中断号,所以中断处理链表可能挂载多个中断处理描述符。
源码在kerne/irq/irqdesc.c函数文件里
用来存用户注册的中断处理函数,一个中断可以有多个处理函数 ,当一个中断有多个处理函数,说明这个是共享中断,所谓共享中断就是一个中断的来源有很多,这些来源共享同一个引脚。所以在irq_desc结构体中的action成员是个链表,以action为表头,若是一个以上的链表就是共享中断
struct irq_desc {
struct irq_data irq_data;
unsigned int __percpu *kstat_irqs;------IRQ的统计信息
irq_flow_handler_t handle_irq;--------(1)
struct irqaction *action; -----------(2)
unsigned int status_use_accessors;-----中断描述符的状态,参考IRQ_xxxx
unsigned int core_internal_state__do_not_mess_with_it;----(3)
unsigned int depth;----------(4)
unsigned int wake_depth;--------(5)
unsigned int irq_count; ---------(6)
unsigned long last_unhandled;
unsigned int irqs_unhandled;
raw_spinlock_t lock;-----------(7)
struct cpumask *percpu_enabled;-------(8)
#ifdef CONFIG_SMP
const struct cpumask *affinity_hint;----和irq affinity相关,后续单独文档描述
struct irq_affinity_notify *affinity_notify;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_t pending_mask;
#endif
#endif
unsigned long threads_oneshot; -----(9)
atomic_t threads_active;
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;--------该IRQ对应的proc接口
#endif
int parent_irq;
struct module *owner;
const char *name;
} ____cacheline_internodealigned_in_smp
在Linux内核中,中断处理流程通常涉及多个函数,其中handle_irq_event_percpu是处理中断事件的关键函数之一。该函数通过调用在request_irq中注册的中断处理程序(ISR)来处理中断事件。具体来说,当CPU接收到一个中断时,会调用handle_irq_event函数,该函数进一步调用handle_irq_event_percpu来处理每个CPU上的中断事件
中断描述符的初始化的接口kerne/irq/irqdesc.c函数文件里,在这个文件里有两个Irq的初始化,越往下看越复杂,完全超出了我的能力了,不做内核开发方向的,看这些真的很费劲很难。
|