ZBLOG

cpu进入中断handler之前 会做哪些事情

当 CPU 进入中断处理程序(Interrupt Handler)之前,硬件和操作系统会协同完成一系列关键操作,以确保上下文正确保存并安全切换到中断上下文。以下是 ARMv7架构(以 Linux 内核为例)的详细流程:


1. 硬件自动完成的操作

(1) 模式切换与状态保存

  • 切换处理器模式
    根据中断类型(如 IRQ、FIQ),CPU 自动切换到对应的异常模式(如 IRQ Mode)。
  • 保存返回地址
    • PC(当前被中断的指令地址)→ LR_<mode>(如 LR_irq)。
    • 注意:ARM 架构的返回地址可能是 PC+4PC+8,取决于具体子架构。
  • 保存状态寄存器
    • CPSRSPSR_<mode>(保存中断前的处理器状态)。

(2) 禁用中断(可选)

  • 自动关闭同级/低优先级中断
    某些架构会默认关闭中断(如 ARMv7 进入 IRQ Mode 后可能禁用进一步 IRQ)。

2. 软件(OS/Kernel)的关键操作

Linux 内核在正式执行中断处理函数前,通常会通过汇编入口代码完成以下步骤:

(1) 保存被中断任务的上下文

@ arch/arm/kernel/entry-armv.S
__irq_svc:
    sub     lr, lr, #4              @ 修正 LR_irq (ARMv7 IRQ返回地址调整)
    srsdb   sp!, #SVC_MODE          @ 保存 LR_irq和SPSR_irq到SVC栈
    stmfd   sp!, {r0-r12}           @ 保存通用寄存器
  • 寄存器压栈顺序:通常为 R0-R12, SP, LR, PC, CPSR
  • 栈选择
    若从用户态触发中断,内核会切换到线程的内核栈;若在内核态则复用当前内核栈。

(2) 识别中断源

  • 读取中断控制器寄存器:如 GIC(Generic Interrupt Controller)的 ICC_IAR1_EL1(ARMv8)。
  • 获取中断号:确定是哪个外设触发了中断。

(3) 调用全局中断处理函数

// arch/arm/kernel/irq.c
handle_domain_irq(domain, hwirq, regs);
  • 参数传递:包括中断号、设备信息、保存的寄存器上下文等。

3. ARMv8/AArch64的区别

在 ARMv8中,流程类似但寄存器命名和异常级别不同:

// arch/arm64/kernel/entry.S
el1_irq:
    kernel_entry el=1                @ Save context to EL1 stack
    bl      irq_handler             @ Call C handler
    kernel_exit el=1                @ Restore context
  • 共用通用寄存器:不再分组 X0-X30,但会保存到异常级别的栈中。
  • 使用 SP_ELx:每个异常级别有独立的栈指针。

4. x86架构对比

以 Linux on x86为例:

// arch/x86/entry/entry_64.S
interrupt_entry:
    swapgs                            @ Switch to kernel GS base (if from user)
    pushq   %rax                      @ Save registers...
    call    do_IRQ                    @ Call generic handler
  • 硬件压栈:x86会在触发中断时自动将部分上下文压入内核栈。
  • 区分用户/内核态堆栈:通过 TSS (Task State Segment)切换。

关键总结表

操作类型 ARMv7 (e.g., Cortex-A9) ARMv8 (e.g., Cortex-A72) x86_64
模式切换 IRQ Mode → SVC Mode EL0 → EL1 Ring3 → Ring0
返回地址计算 LR = PC + offset (depends on ISA) ELR_ELx = PC + offset RIP pushed to stack
状态保存位置 SPSR_ SPSR_ELx RFLAGS pushed to stack
上下文存储方式 Banked SP/LR +手动存 R0-R12 SP_ELx +手动存 X0-X30 Hardware auto-push部分寄存器

调试建议

  1. 查看反汇编代码:
    
    objdump -D vmlinux > disasm.txt        # Linux内核反汇编
    
  2. 跟踪寄存器的变化:
    使用 QEMU+GDB 单步调试观察 CPSR、SP、LR等寄存器的变化。


    内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=8146

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?