assembly 内核在添加新代码时中断(从不运行)

ubbxdtey  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(181)

我尝试在用户空间和内核空间之间的边界添加一些逻辑,特别是在ARM架构上。
arch/arm/kernel/entry-common.S中实现的vector_swi例程就是一个这样的边界。现在,我的大部分代码都是用C函数编写的,我想在vector_swi的开头调用它。
因此,我做了以下工作:

ENTRY(vector_swi)
        sub     sp, sp, #S_FRAME_SIZE
        stmia   sp, {r0 - r12}                  @ Calling r0 - r12
 ARM(   add     r8, sp, #S_PC           )
 ARM(   stmdb   r8, {sp, lr}^           )       @ Calling sp, lr
 THUMB( mov     r8, sp                  ) 
 THUMB( store_user_sp_lr r8, r10, S_SP  )       @ calling sp, lr
        mrs     r8, spsr                        @ called from non-FIQ mode, so ok.
        str     lr, [sp, #S_PC]                 @ Save calling PC
        str     r8, [sp, #S_PSR]                @ Save CPSR
        str     r0, [sp, #S_OLD_R0]             @ Save OLD_R0
        zero_fp

#ifdef CONFIG_BTM_BOUNDARIES
        bl btm_entering_kernelspace    @ <--- My function
#endif

当函数的内容如下所示时,一切都正常:

static int btm_enabled = 0;
asmlinkage inline void btm_entering_kernelspace(void)
{
        int cpu;
        int freq;
        struct acpu_level *level;
        if(!btm_enabled) {
                return;
        }
        cpu = smp_processor_id();
        freq = acpuclk_krait_get_rate(cpu);
        (void) cpu;
        (void) freq;
        (void) level;
}

然而,当我添加一些额外的代码时,内核进入崩溃-重新启动循环。

static int btm_enabled = 0;
asmlinkage inline void btm_entering_kernelspace(void)
{
        int cpu;
        int freq;
        struct acpu_level *level;
        if(!btm_enabled) {
                return;
        }
        cpu = smp_processor_id();
        freq = acpuclk_krait_get_rate(cpu);
        (void) cpu;
        (void) freq;
        (void) level;
        // --------- Added code ----------
        for (level = drv.acpu_freq_tbl; level->speed.khz != 0; level++) {
                if(level->speed.khz == freq) {
                        break;
                }
        }
}

虽然第一React是指责添加的代码的逻辑,但请注意,由于btm_enabled0,因此任何代码都不应执行。
我已经通过添加sysfs条目打印出变量的值(删除了添加的代码),进行了两次和三次检查,以确保btm_enabled0
有人能解释一下这是怎么回事吗?我做错了什么?

92dk7w1h

92dk7w1h1#

第一个版本可能会编译成一个返回指令,因为它没有副作用。第二个版本需要加载btm_enabled,并在此过程中覆盖一个或两个系统调用参数。
当从汇编语言调用C函数时,需要确保可能被修改的寄存器不包含所需的信息。
若要解决您的特定问题,您可以将程式码更新为:

#ifdef CONFIG_BTM_BOUNDARIES
        stmdb   sp!, {r0-r3, r12, lr}  @ <--- New instruction
        bl btm_entering_kernelspace    @ <--- My function
        ldmia   sp!, {r0-r3, r12, lr}  @ <--- New instruction
#endif

新指令将寄存器r 0-r3、r12和lr存储到堆栈上,并在函数调用后恢复它们。这些寄存器是C函数唯一允许修改的寄存器,在这里保存r12是不必要的,因为它的值没有被使用,但这样做可以按照ABI的要求保持堆栈8字节对齐。

相关问题