You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM32 v7内核模块FIQ触发报Bad Mode内核崩溃问题求助

ARM32 v7 Linux 3.14 FIQ Handler触发Bad Mode崩溃排查求助

在ARM32 v7核心、Linux 3.14.x版本内核环境中,通过内核模块实现GPIO触发的FIQ handler,功能为每次触发FIQ时递增全局计数器static volatile int fiq_counter = 0;。已确认该GPIO引脚仅启用FIQ、未注册IRQ handler,模块加载成功且在/proc/interrupts中可见,但触发FIQ时内核触发Bad Mode崩溃。崩溃信息显示FIQ代码已被执行,现求助排查故障原因。

FIQ Handler汇编代码

asm(
    ".global wdog_fiq_handler_start\n"
    ".global wdog_fiq_handler_end\n"
    "wdog_fiq_handler_start:\n"

    /* Use FIQ-mode-specific register R8_fiq to manipulate the counter */
    "    ldr r9, [r8]\n"         // Load the current value of fiq_counter into r9 (FIQ banked register)
    "    add r9, r9, #1\n"       // Increment the counter
    "    str r9, [r8]\n"         // Store the incremented value back into fiq_counter
    "bx lr\n"

    "wdog_fiq_handler_end:\n"
); 

注册代码

void *fiqhandler_start;
    unsigned int fiqhandler_length;
    extern unsigned char wdog_fiq_handler_end, wdog_fiq_handler_start;
    fiqhandler_start = &wdog_fiq_handler_start;
    fiqhandler_length = &wdog_fiq_handler_end - &wdog_fiq_handler_start;

    if (claim_fiq(&fh)) {
        pr_err("wdogfiq : couldn't claim FIQ.\n");
        return;
    }
    set_fiq_handler(fiqhandler_start, fiqhandler_length);
    get_fiq_regs(&regs);
    regs.ARM_r8 = (unsigned long)&fiq_counter;
    set_fiq_regs(&regs);
    enable_fiq(88);  /* hwirq 88 corresponding to GPIO pin */

崩溃信息

[ 4145.425070] Internal error: Oops - bad mode: 0 [#1] SMP ARM
[ 4145.523357] Process swapper/0 (pid: 0, stack limit = 0x808c0240)
[ 4145.719365] Code: e320f000 e320f000 e320f000 e320f000 (e5989000)

经确认e5989000对应FIQ代码中的ldr r9, [r8]指令。


可能的故障原因及排查方向

1. FIQ模式专属R8寄存器未正确初始化

Linux内核的get_fiq_regs()和set_fiq_regs()操作的struct pt_regs结构体中,ARM_r8对应的是用户/系统模式的通用R8寄存器,而非FIQ模式下的banked专属R8寄存器。你通过regs.ARM_r8 = (unsigned long)&fiq_counter设置的是通用R8,而FIQ handler中访问的是FIQ模式的banked R8,其值未被初始化,导致ldr r9, [r8]访问非法地址,触发Bad Mode。

修复建议:
直接在FIQ handler中加载fiq_counter的虚拟地址,无需依赖寄存器传递:

asm(
    ".global wdog_fiq_handler_start\n"
    ".global wdog_fiq_handler_end\n"
    "wdog_fiq_handler_start:\n"
    "    ldr r8, =fiq_counter\n"  // 直接加载全局变量的虚拟地址
    "    ldr r9, [r8]\n"
    "    add r9, r9, #1\n"
    "    str r9, [r8]\n"
    "    bx lr\n"
    "wdog_fiq_handler_end:\n"
); 

同时确保fiq_counter全局可见:

static volatile int fiq_counter = 0;
EXPORT_SYMBOL(fiq_counter);

2. 内存地址访问权限异常

如果fiq_counter的虚拟地址在FIQ模式下无法被正常访问(比如页表映射异常、内存权限配置错误),也会触发ldr指令的访问异常。可以通过以下方式验证:

  • 打印&fiq_counter的虚拟地址,确认该地址在内核空间的映射状态;
  • 尝试将fiq_counter放置在已确认可访问的内存区域(比如内核静态内存区)。

3. FIQ硬件配置遗漏

部分ARMv7平台的GPIO FIQ除了内核层面的enable_fiq,还需要在GPIO控制器中配置触发方式(边沿/电平)、使能FIQ通道等硬件寄存器。即使/proc/interrupts中可见FIQ项,若硬件配置不全,可能导致异常进入时的状态错误,间接引发地址访问崩溃。

4. FIQ handler返回指令问题

虽然bx lr是ARM异常返回的标准指令,但需确认FIQ模式下的LR寄存器(LR_fiq)是否正确保存了返回地址。若异常入口时LR值异常,bx lr可能跳转到非法地址,但崩溃点在ldr指令,此可能性较低。


内容的提问来源于stack exchange,提问作者InsaneCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:47:07