【Note】《Linux 内核深度解析:基于 ARM64 架构的 Linux 4.x 内核》第四章:中断、异常与系统调用

发布于:2025-07-11 ⋅ 阅读:(22) ⋅ 点赞:(0)

《Linux 内核深度解析:基于 ARM64 架构的 Linux 4.x 内核》第四章:中断、异常与系统调用

中断与异常机制是连接硬件与内核逻辑的重要纽带,系统调用则是用户空间访问内核服务的主要入口。本章围绕 ARM64 架构上的这些机制,全面分析其实现原理、初始化流程与运行时行为。


一、ARM64 异常模型概览

1.1 异常级别(Exception Levels)

ARM64 架构定义了四个异常级别(EL):

异常级别 描述 用途
EL3 Secure Monitor TrustZone 安全世界
EL2 Hypervisor 虚拟化层(KVM)
EL1 Kernel 操作系统内核
EL0 User 应用程序(用户态)

Linux 内核运行在 EL1,用户进程在 EL0,在某些系统中 KVM 使用 EL2。


二、异常类型与分类

ARM64 支持多种类型的异常,每种类型都对应一个特定的异常向量入口:

异常类型 描述 触发来源
Synchronous 同步异常,如 page fault、svc 执行指令后立即触发
IRQ 普通中断 外设中断,标记为 IRQ
FIQ 快速中断(ARMv8 可选) 高优先级外设
SError 系统错误异常,如总线错误 通常为硬件引发,不可恢复

三、异常向量表实现

ARM64 下异常向量表通过寄存器 VBAR_EL1 设置,指向异常向量基地址。该表必须 2048 字节对齐,分为四组,每组对应一个异常级别进入当前级别的场景(例如 EL0 → EL1, EL1 → EL1):

3.1 异常向量表布局

// arch/arm64/kernel/entry.S

ENTRY(vectors)
    // 0x000: EL1t: 同步异常
    b el1_sync
    // 0x080: EL1t: IRQ 异常
    b el1_irq
    ...
    // 0x200: EL0t: 同步异常(用户发起 syscall)
    b el0_sync
    ...
END(vectors)
  • 每个向量入口都是一个固定大小的跳转指令,最终跳到具体处理函数。
  • 早期启动阶段由 __cpu_setup() 设置 VBAR_EL1 = vectors

四、中断架构初始化流程(IRQ Subsystem)

Linux 的中断处理体系在 kernel/irq/ 中实现,架构无关,ARM64 架构通过 irqchip 子系统进行集成。

4.1 GICv3 中断控制器支持

ARM64 SoC 多使用 GICv2/GICv3/ITS 作为中断控制器,主要组件:

  • Distributor (GICD):中断控制与分发中心,配置目标 CPU、触发方式
  • Redistributor (GICR):为每个 CPU 核提供中断上下文
  • ITS:GICv3 扩展,支持 MSI(PCI 中断)

驱动代码位于 drivers/irqchip/irq-gic-v3.c

  • gic_of_init():通过设备树初始化中断控制器
  • gic_cpu_init():为每个 CPU 配置 GICR 和启用中断
  • __gic_v3_do_irq():在中断发生后调用的汇编路径,跳入 C 处理

4.2 中断号与触发配置

  • 内核抽象的中断号是逻辑编号(Linux IRQ Number),通过设备树 interrupts 属性绑定;
  • 支持 level(电平触发)和 edge(边缘触发);
  • request_irq() 用于驱动层注册中断回调。

五、中断处理路径详解

5.1 IRQ 异常入口

// arch/arm64/kernel/entry.S
el1_irq:
    kernel_entry 1
    bl  asm_do_IRQ
    kernel_exit 1

5.2 中断分发流程

// arch/arm64/kernel/irq.c
asmlinkage void asm_do_IRQ(struct pt_regs *regs)
{
    irq_enter();                            // 开启抢占计数
    generic_handle_irq(read_irq_number()); // 调用中断控制器分发中断
    irq_exit();                             // 清理抢占标记
}
  • 中断控制器根据 IRQ Number 定位具体 handler,并调用 __handle_irq_event_percpu() → 驱动层 irq_handler_t
  • 若启用软中断(tasklet/workqueue),部分中断在 softirq 阶段延迟执行。

六、系统调用机制(Syscall)

系统调用是用户态访问内核功能的桥梁。ARM64 使用 SVC(Supervisor Call)指令从 EL0 切换到 EL1。

6.1 系统调用入口

// arch/arm64/kernel/entry.S

el0_sync:
    kernel_entry 0
    mrs x8, esr_el1           // 获取异常原因
    cmp x8, #ESR_ELx_EC_SVC64
    b.eq el0_svc              // 若为 SVC,进入系统调用处理
  • ESR_EL1[31:26] 是 Exception Class (EC);

    • 0x150b010101)为 64 位 SVC 系统调用。
  • 系统调用号通常放在 x8 寄存器,参数 x0 ~ x5

6.2 syscall 调度表

// arch/arm64/kernel/sys.c
DEFINE_SYSCALL_TABLE(sys_call_table)

long syscall_trace_enter(struct pt_regs *regs)
{
    syscall_fn_t fn = sys_call_table[regs->syscallno];
    ...
    ret = fn(regs->regs[0], regs->regs[1], ..., regs->regs[5]);
}

系统调用表定义在 arch/arm64/kernel/sys.c,每个系统调用号映射到对应函数,最终统一调用。

6.3 示例:用户调用流程

用户程序:

write(1, "hello\n", 6);

Glibc 封装后调用:

mov x8, #__NR_write
svc #0

EL0 → EL1 跳转后,内核通过 syscall 表找到 sys_write() 并执行。


七、异常上下文保存与 pt_regs

ARM64 在异常入口处,使用 kernel_entry 0/1 宏保存现场:

.macro kernel_entry el, regsize = 64
    stp x29, x30, [sp, #-16]!       // 保存调用者帧地址
    ...
    mov x29, sp                     // 设置新的帧地址
    mrs x0, sp_el0
    ...
.endm

内核构建一个 struct pt_regs(定义在 arch/arm64/include/asm/ptrace.h):

struct pt_regs {
    u64 regs[31];      // x0 ~ x30
    u64 sp;            // 堆栈指针
    u64 pc;            // 程序计数器
    u64 pstate;        // 状态寄存器
};

这些信息供后续内核分析系统调用来源、异常上下文、调试等使用。


八、信号处理与异常返回

当用户进程收到信号时,内核会构建信号帧并设置 pc 跳转到用户注册的 handler 地址。常见流程:

  1. 捕获信号:软中断/中断上下文检查 do_signal()
  2. 构建信号栈帧,保存原上下文到用户栈;
  3. 修改 pt_regs 中的 PC 为 handler 地址;
  4. handler 执行后使用 sigreturn 恢复上下文。

总结

模块 关键点
异常级别(EL) 用户 EL0,内核 EL1,支持从 EL0 向上触发异常
异常向量表 VBAR_EL1 指向的向量,入口在 entry.S
中断控制器 GICv3 架构,支持 IRQ 分发,支持 CPU 热插拔
中断处理流程 汇编入口 → IRQ 分发器 → 驱动注册的 request_irq 回调
系统调用路径 EL0 发起 SVC,EL1 解析 syscall number 调用 syscall 表
pt_regs 上下文结构 用于保存/恢复寄存器、状态寄存器、异常返回

本章介绍的从硬件中断到系统调用的所有通道,是内核调度、IO、调试、异常恢复等机制的基础。下一章我们将进入调度系统与 CPU 运行时行为,探索 Linux 的多核调度策略与任务切换实现。


常用源码路径参考:

  • arch/arm64/kernel/entry.S:异常入口
  • arch/arm64/kernel/irq.c:IRQ 异常处理
  • drivers/irqchip/irq-gic-v3.c:GIC 中断控制器驱动
  • arch/arm64/include/asm/ptrace.h:pt_regs 定义
  • kernel/irq/handle.c:中断分发器
  • arch/arm64/kernel/sys.c:系统调用表与 handler

网站公告

今日签到

点亮在社区的每一天
去签到