Raspberry Pi 4裸机操作系统开发教程(13): 中断处理机制详解

Raspberry Pi 4裸机操作系统开发教程(13): 中断处理机制详解

rpi4-osdev Tutorial: Writing a "bare metal" operating system for Raspberry Pi 4 rpi4-osdev 项目地址: https://gitcode.com/gh_mirrors/rp/rpi4-osdev

中断机制概述

在嵌入式系统开发中,中断(Interrupt)是一种至关重要的机制。它允许硬件设备在需要处理器注意时主动发出信号,而不是让处理器不断轮询检查设备状态。这种机制极大地提高了CPU的利用效率。

以蓝牙通信为例,在没有中断的情况下,我们不得不让一个CPU核心持续轮询检查是否有数据到达,这显然是对计算资源的浪费。通过中断机制,我们可以让硬件在数据到达时主动通知CPU,从而释放CPU去处理其他任务。

系统定时器:最简单的中断设备

系统定时器是理解中断机制的理想起点。Raspberry Pi 4内置的系统定时器可以配置为定期触发中断,例如每秒一次。这种定时中断是实现多任务调度(如时间片轮转)的基础。

在本教程中,我们将重点学习如何配置系统定时器并处理其产生的中断。

代码结构解析

项目代码结构保持了良好的模块化设计:

  • boot/: 启动代码,与第12部分相同
  • include/: 头文件,从第11部分复用
  • lib/: 实用库,从第11部分复用
  • kernel/: 本教程新增的核心代码

主要关注kernel.c文件,它基于第10部分的多核代码进行了修改,现在使用核心0和1,并通过两个定时器中断驱动四个进度条的显示。

中断处理流程详解

1. 异常向量表初始化

中断实际上是异常(Exception)的一种特定类型。当发生异常(如除以零)或中断时,CPU需要知道跳转到哪个地址执行处理程序。这些地址存储在异常向量表中。

irqentry.S中定义的vectors表包含了各个向量条目,每个条目都是跳转到特定处理程序的指令。irq_init_vectors()函数(在utils.S中实现)负责设置向量基地址寄存器(VBAR_EL1):

irq_init_vectors:
    adr x0, vectors
    msr vbar_el1, x0
    ret

2. 中断控制器配置

中断控制器是硬件与CPU之间的中介,管理哪些中断可以传递给CPU。我们通过以下函数控制中断:

void enable_interrupt_controller() {
    REGS_IRQ->irq0_enable_0 = SYS_TIMER_IRQ_1 | SYS_TIMER_IRQ_3;
}

void disable_interrupt_controller() {
    REGS_IRQ->irq0_enable_0 = 0;
}

这里我们启用了定时器1和3的中断,它们将用于驱动不同速度的进度条。

3. 中断掩码管理

为确保关键代码段不被中断打断,CPU提供了中断掩码功能。相关汇编函数如下:

.globl irq_enable
irq_enable:
    msr daifclr, #2  // 清除中断掩码
    ret

.globl irq_disable
irq_disable:
    msr daifset, #2  // 设置中断掩码
    ret

.globl irq_barrier
irq_barrier:
    dsb sy           // 数据同步屏障
    ret

irq_barrier确保在启用中断前,所有之前的配置操作都已完成。

4. 定时器初始化

RPi4的系统定时器包含一个自由运行的计数器(每时钟周期加1)和四个比较寄存器。当计数器值等于某个比较寄存器值时,相应中断线被触发。

定时器初始化代码如下:

void timer_init() {
    uint64_t cntfrq;
    asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq));
    
    // 设置定时器1(慢速)
    REGS_TIMER->timer[1] = REGS_TIMER->counter_lo + (cntfrq / 10);
    
    // 设置定时器3(快速,是定时器1速度的4倍)
    REGS_TIMER->timer[3] = REGS_TIMER->counter_lo + (cntfrq / 40);
}

这里我们配置定时器1每1/10秒触发一次中断,定时器3每1/40秒触发一次。

5. 中断处理程序

当IRQ发生时,CPU跳转到handle_el1_irq处理程序:

handle_el1_irq:
    kernel_entry    // 保存寄存器状态
    bl handle_irq   // 调用C语言处理函数
    kernel_exit     // 恢复寄存器状态

kernel_entrykernel_exit宏确保处理程序不会破坏被中断代码的上下文。

C语言处理函数handle_irq()识别中断源并调用相应子处理程序:

void handle_irq() {
    unsigned int irq = REGS_IRQ->irq0_pending_0;
    
    if (irq & SYS_TIMER_IRQ_1) {
        handle_timer_1();  // 处理定时器1中断
    }
    
    if (irq & SYS_TIMER_IRQ_3) {
        handle_timer_3();  // 处理定时器3中断
    }
}

定时器处理函数完成两件事:

  1. 更新比较寄存器以安排下一次中断
  2. 清除中断状态标志
  3. 更新进度条显示

实际应用效果

通过这套机制,我们实现了:

  • 核心0和1各自运行主任务
  • 定时器1以基础速度更新进度条
  • 定时器3以4倍速度更新另一个进度条

所有这一切都无需任何轮询操作,充分展示了中断机制在提高系统效率方面的优势。

定时器中断驱动的进度条效果

总结

本教程详细讲解了在Raspberry Pi 4裸机环境下实现中断处理的完整流程,包括:

  1. 异常向量表设置
  2. 中断控制器配置
  3. 中断掩码管理
  4. 系统定时器编程
  5. 中断处理程序实现

掌握这些基础知识后,开发者可以将其扩展到其他硬件设备的中断处理,构建更高效、更复杂的嵌入式系统。

rpi4-osdev Tutorial: Writing a "bare metal" operating system for Raspberry Pi 4 rpi4-osdev 项目地址: https://gitcode.com/gh_mirrors/rp/rpi4-osdev

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陶淑菲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值