zoukankan      html  css  js  c++  java
  • 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也有实现。

  • 相关阅读:
    推销
    5132. 颜色交替的最短路径
    5130. 等价多米诺骨牌对的数量
    @babel/plugin-transform-runtime和@babel/preset-env的区别
    5128. 最深叶节点的最近公共祖先(二叉树)
    1094. 拼车
    1109. 航班预订统计(数组)
    5129. 表现良好的最长时间段(数组)
    path.resove 和 path.join
    【原生】 call、apply、bind 的基本使用方法,已经解析了某些源码
  • 原文地址:https://www.cnblogs.com/smilingsusu/p/14600585.html
Copyright © 2011-2022 走看看