ARM64 kernel中判定一个虚拟地址是否有对应的物理地址(是否可以访问)的方法

最近在做一个panic事后的处理时,需要读取寄存器信息,然后找到对应的物理地址。

然后发现Linux中,已经有实现的类似的功能,现在拿过来做地址有效性判定,感觉还是很不错的。

#include <asm/esr.h>
#include <asm/sysreg.h>
#include <asm/system_misc.h>

static int check_addr_valid(unsigned long ptr)
{
    unsigned long flags;
    unsigned long par;

    local_irq_save(flags);
    asm volatile("at s1e1r, %0" :: "r" (addr));
    isb();
    par = read_sysreg(par_el1);
    local_irq_restore(flags);

    if (par & SYS_PAR_EL1_F)
        return false;
    return true;
}

 具体可以看kernel实现:https://elixir.bootlin.com/linux/v5.4.108/source/arch/arm64/mm/fault.c#L254

 

后面还在 https://blog.csdn.net/weixin_42135087/article/details/106379970

看到optee中也有这样的方法,不仅能判定虚拟地址是否有效,还能根据虚拟地址得到物理地址的方法:

#include <linux/module.h>

#define BIT32(nr)        ((1 & 0xffffffff) << (nr))
#define BIT64(nr)        ((1 & 0xffffffffffffffff) << (nr))

#define PAR_F            BIT32(0)
#define PAR_PA_SHIFT        12
#define PAR_PA_MASK        (BIT64(36) - 1)

#define DEFINE_REG_READ_FUNC_(reg, type, asmreg)    \
static inline type read_##reg(void)            \
{                            \
    type val;                    \
                            \
    asm volatile("mrs %0, " #asmreg : "=r" (val));    \
    return val;                    \
}

#define DEFINE_U64_REG_READ_FUNC(reg) \
        DEFINE_REG_READ_FUNC_(reg, uint64_t, reg)

DEFINE_U64_REG_READ_FUNC(par_el1)

static inline void write_at_s1e1r(uint64_t va)
{
    asm volatile ("at    S1E1R, %0" : : "r" (va));
}

bool arm_va2pa_helper(void *va, uint64_t *pa)
{
    uint64_t par;
    uint64_t par_pa_mask;
    bool ret = false;

    local_irq_disable();
    write_at_s1e1r((uint64_t)va);
    isb();
    par = read_par_el1();
    par_pa_mask = PAR_PA_MASK;

    if (par & PAR_F)
        goto out;
    *pa = (par & (par_pa_mask << PAR_PA_SHIFT)) |
        ((uint64_t)va & ((1 << PAR_PA_SHIFT) - 1));

    ret = true;
out:
    local_irq_enable();;
    return ret;
}
EXPORT_SYMBOL(arm_va2pa_helper);

 这段代码在 https://elixir.bootlin.com/op-tee/latest/source/core/arch/arm/mm/core_mmu.c#L2048

 可以看到,对应的32bit ARM CPU也有实现。

posted @ 2021-03-31 11:17  smilingsusu  阅读(763)  评论(0编辑  收藏  举报