为什么这个函数在Linux驱动程序中不是静态的

时间:2016-01-15 09:00:18

标签: c linux static linux-kernel

我有一些汇编代码封装在我的驱动程序代码的静态函数中。我的代码就像

static int _ARMVAtoPA(void *pvAddr)
{
__asm__ __volatile__(
    /* ; INTERRUPTS_OFF" */
    " mrs            r2, CPSR;\n" /* r2 saves current status */
    "CPSID  iaf;\n" /* Disable interrupts */

    /*In order to handle PAGE OUT scenario, we need do the same operation
      twice. In the first time, if PAGE OUT happens for the input address,
      translation abort will happen and OS will do PAGE IN operation
      Then the second time will succeed.
    */

    "mcr    p15, 0, r0, c7, c8, 0;\n "
    /*  ; get VA = <Rn> and run nonsecure translation
        ; with nonsecure privileged read permission.
        ; if the selected translation table has privileged
        ; read permission, the PA is loaded in the PA
        ; Register, otherwise abort information is loaded
        ; in the PA Register.
    */

    /* read in <Rd> the PA value */
     "mrc    p15, 0, r1, c7, c4, 0;\n"
    /* get VA = <Rn> and run nonsecure translation */
    " mcr    p15, 0, r0, c7, c8, 0;\n"

    /*  ; with nonsecure privileged read permission.
        ; if the selected translation table has privileged
        ; read permission, the PA is loaded in the PA
        ; Register, otherwise abort information is loaded
        ; in the PA Register.
    */
    "mrc    p15, 0, r0, c7, c4, 0;\n" /* read in <Rd> the PA value */

    /* restore INTERRUPTS_ON/OFF status*/
    "msr            cpsr, r2;\n" /* re-enable interrupts */

    "tst    r0, #0x1;\n"
    "ldr    r2, =0xffffffff;\n"

    /* if error happens,return INVALID_PHYSICAL_ADDRESS */
    "movne   r0, r2;\n"
    "biceq  r0, r0, #0xff;\n"
    "biceq  r0, r0, #0xf00;" /* if ok, clear the flag bits */
);
}

static unsigned long CpuUmAddrToCpuPAddr(void *pvCpuUmAddr)
{
    int phyAdrs;
    int mask = 0xFFF;  /* low 12bit */
    int offset = (int)pvCpuUmAddr & mask;
    int phyAdrsReg = _ARMVAtoPA((void *)pvCpuUmAddr);

    if (INVALID_PHYSICAL_ADDRESS != phyAdrsReg)
        phyAdrs = (phyAdrsReg & (~mask)) + offset;
    else
        phyAdrs = INVALID_PHYSICAL_ADDRESS;

    return phyAdrs;
}

如您所见,我尝试将虚拟地址从用户空间转换为物理地址。我从另一个项目移植此代码,除了我将_ARMVAtoPA函数修改为静态函数。

当我使用static int _ARMVAtoPA(void *pvAddr)时:

  • 这个转换函数(其中包含一堆汇编代码)总是返回 fffffff ,肯定是错误的情况。

当我使用int _ARMVAtoPA(void *pvAddr)时:

  • 此转换功能可以正常工作。

任何人都可以向我解释,为什么当我使用静态和非静态功能时结果会有所不同。

由于

1 个答案:

答案 0 :(得分:6)

ASM代码没有定义哪个寄存器包含函数参数pvAddr以及哪个寄存器保存返回值。只是假定编译器遵循mips ABI。

但如果函数是内联的(可能static可能),寄存器分配可能会改变,因此asm代码可能完全错误。

为了解决这个问题,你应该使用gcc扩展来为函数参数分配寄存器并返回值。并且还声明它将使用哪些寄存器进行无恢复,因此编译器可以在调用之后恢复寄存器,以防内联函数。