在 ARMv7 架构的单核 CPU 系统中,完全禁用 coretime 时钟中断(通常是 ARM 私有定时器中断)需要谨慎操作,因为这会导致调度器无法工作,系统可能失去响应。以下是实现方法及注意事项:
方法 1:通过 GIC 屏蔽中断(推荐)
ARM 的时钟中断(通常是 PPI 中断号 30)通过 GIC(Generic Interrupt Controller)管理:
cpp
#include <linux/irq.h>
// 获取时钟中断号(通常是30)
#define TIMER_IRQ 30
// 屏蔽中断
void disable_timer_irq(void)
{
struct irq_desc *desc = irq_to_desc(TIMER_IRQ);
if (desc) {
raw_spin_lock_irq(&desc->lock);
irq_settings_set_disabled(desc); // 标记为禁用
desc->irq_data.chip->irq_mask(&desc->irq_data); // 硬件屏蔽
raw_spin_unlock_irq(&desc->lock);
}
}
// 恢复中断
void enable_timer_irq(void)
{
struct irq_desc *desc = irq_to_desc(TIMER_IRQ);
if (desc) {
raw_spin_lock_irq(&desc->lock);
desc->irq_data.chip->irq_unmask(&desc->irq_data);
irq_settings_clr_disabled(desc);
raw_spin_unlock_irq(&desc->lock);
}
}
方法 2:直接操作定时器寄存器
通过 ARM CP15 协处理器控制私有定时器:
cpp
// 禁用定时器中断
static void disable_arm_private_timer(void)
{
u32 ctrl;
// 读控制寄存器 (CP15 c14)
asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (ctrl));
ctrl &= ~(1 << 2); // 清除中断使能位
asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (ctrl));
}
// 恢复定时器中断
static void enable_arm_private_timer(void)
{
u32 ctrl;
asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (ctrl));
ctrl |= (1 << 2); // 设置中断使能位
asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (ctrl));
}
关键注意事项
-
系统稳定性风险:
-
禁用时钟中断后,调度器 (
scheduler_tick()
) 停止工作 -
无抢占发生,当前任务将独占 CPU
-
时间相关功能(
jiffies
、gettimeofday
)停止更新
-
-
必要操作前准备:
cpplocal_irq_save(flags); // 保存中断状态并禁用所有中断 preempt_disable(); // 禁用内核抢占 disable_timer_irq(); // 禁用时钟中断
-
恢复操作:
cppenable_timer_irq(); // 先恢复时钟中断 preempt_enable(); // 启用抢占 local_irq_restore(flags); // 恢复中断状态
-
最大禁用时间:
-
典型时钟中断周期 1-10ms
-
禁用时间不应超过 100ms,否则可能触发看门狗或导致系统不稳定
-
-
替代方案建议:
cpp// 临时禁用抢占(更安全) preempt_disable(); // 执行关键操作 preempt_enable();
典型使用场景
-
极短时延关键操作:
cppunsigned long flags; local_irq_save(flags); disable_timer_irq(); // 执行时间敏感操作(< 100us) asm volatile("nop; nop; ..."); enable_timer_irq(); local_irq_restore(flags);
-
低功耗状态进入前:
cppdisable_timer_irq(); wfi(); // 进入WFI状态 enable_timer_irq(); // 被其他中断唤醒后执行
调试与验证
-
检查中断状态:
bashcat /proc/interrupts | grep arch_timer
- 禁用后计数器应停止增长
-
监控系统状态:
bashperf stat -e irq_vectors:local_timer_entry
-
内核日志确认:
dmesg
bash[ 123.456] Disabled arch_timer interrupt
重要警告
-
避免在用户空间进程中使用 - 仅限内核模块或核心代码
-
禁用期间不可调用任何调度相关函数 (如
schedule()
,msleep()
) -
禁止在中断上下文中使用此操作
-
多核系统中需配合
get_cpu()
/put_cpu()
处理 CPU 亲和性
如非必要,建议使用 preempt_disable()
或 local_irq_disable()
替代完全禁用时钟中断,以保持系统基本功能运作。