从 GNU/Linux shell 中使用 devmem 读取 Armv8-A 寄存器

smo*_*are 5 cpu-registers base-address memory-mapping cortex-a armv8

我想读取一些Cortex-A53寄存器的值,例如

  • D_AA64ISAR0_EL1 (AArch64)
  • ID_ISAR5 (Aarch32)
  • ID_ISAR5_EL1 (Aarch64)

不幸的是,我缺乏一点嵌入式/组装经验。文档显示

访问 ID_AA64ISAR0_EL1: MRS 、 ID_AA64ISAR0_EL1 ;将ID_AA64ISAR0_EL1读入Xt ID_AA64ISAR0_EL1[31:0]可以通过内部存储器映射接口和外部调试接口访问,偏移量0xD30。

我决定在我的目标上使用 devmem2(因为 busybox 不包含 devmem 小程序)。以下读取寄存器的过程是否正确?

devmem2 0xD30
Run Code Online (Sandbox Code Playgroud)

我不确定的部分是使用“偏移量”作为直接物理地址。如果它是实际地址,为什么要调用“offset”而不是“address”。如果是偏移量,基地址是多少?我 99% 确定这不是正确的过程,但我如何知道要添加偏移量的基地址?我搜索了Armv8技术参考手册和A53 MPCore文档没有结果。详细解释了寄存器内容,但似乎假设您使用标签 ID_AA64ISAR0_EL1 从 ASM 读取它们。

更新:

我找到了这个:

配置基地址寄存器,EL1 CBAR_EL1 的特性包括: 用途 保存内存映射 GIC CPU 接口寄存器的物理基地址。

但它只是重复了我的问题,如何读取另一个寄存器?

更新 2: 第一个更新似乎仅与 GIC 相关,与我试图读取的配置寄存器无关(我认为我误解了信息)。

对于手头的具体问题(检查加密扩展可用性),人们可以简单地 cat /proc/cpuinfo 并查找 aes/sha 等。

更新3:

我现在正在调查http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0176c/ar01s04s01.html,以及 SoC 特定的基地址,因此可以在SoC 的参考手册。

更新4:

感谢这个很好的答案,我似乎能够通过我的内核模块读取数据:

[ 4943.461948] ID_AA64ISA_EL1 : 0x11120
[ 4943.465775] ID_ISAR5_EL1     : 0x11121
Run Code Online (Sandbox Code Playgroud)

PS: 这篇文章非常有见地,再次感谢!

更新5: 根据要求源代码:

/******************************************************************************
 *
 *   Copyright (C) 2011  Intel Corporation. All rights reserved.
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; version 2 of the License.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *****************************************************************************/

#include <linux/module.h>
#include <linux/types.h>

/*****************************************************************************/

// read system register value ID_AA64ISAR0_EL1 (s3_0_c0_c6_0).
static inline uint64_t system_read_ID_AA64ISAR0_EL1(void)
{
    uint64_t val;
    asm volatile("mrs %0, ID_AA64ISAR0_EL1" : "=r" (val));
    return val;
}

// read system register value ID_ISAR5_EL1 (s3_0_c0_c2_5).
static inline uint64_t system_read_ID_ISAR5_EL1(void)
{
    uint64_t val;
    asm volatile("mrs %0, s3_0_c0_c2_5" : "=r" (val));
    return val;
}

/*****************************************************************************/

int init_module(void)
{
    printk("ramdump Hello World!\n");
    printk("ID_AA64ISAR0_EL1 : 0x%llX\n", system_read_ID_AA64ISAR0_EL1());
    printk("ID_ISAR5_EL1     : 0x%llX\n", system_read_ID_ISAR5_EL1());
    return 0;
}

void cleanup_module(void)
{
    printk("ramdump Goodbye Cruel World!\n");
}

MODULE_LICENSE("GPL");
Run Code Online (Sandbox Code Playgroud)

Fra*_*ant 3

免责声明:我不是 Aarch64 专家,但我目前正在学习该架构并阅读了一些内容。

\n\n

您不能读取ID_AA64ISAR0_EL1ID_ISAR5_EL1也不能从ID_ISAR5运行于 的用户模式应用程序中读取EL0_EL1后缀意味着至少EL1需要运行 at 才能读取这两个寄存器。

\n\n

阅读此处此处的arm 文档中的伪代码可能会对您有所帮助。\n例如,对于ID_ISAR5,伪代码非常明确:

\n\n
if PSTATE.EL == EL0 then\n    UNDEFINED;\nelsif PSTATE.EL == EL1 then\n    if EL2Enabled() && !ELUsingAArch32(EL2) && HSTR_EL2.T0 == \'1\' then\n        AArch64.AArch32SystemAccessTrap(EL2, 0x03);\n    elsif EL2Enabled() && ELUsingAArch32(EL2) && HSTR.T0 == \'1\' then\n        AArch32.TakeHypTrapException(0x03);\n    elsif EL2Enabled() && !ELUsingAArch32(EL2) && HCR_EL2.TID3 == \'1\' then\n        AArch64.AArch32SystemAccessTrap(EL2, 0x03);\n    elsif EL2Enabled() && ELUsingAArch32(EL2) && HCR.TID3 == \'1\' then\n        AArch32.TakeHypTrapException(0x03);\n    else\n        return ID_ISAR5;\nelsif PSTATE.EL == EL2 then\n    return ID_ISAR5;\nelsif PSTATE.EL == EL3 then\n    return ID_ISAR5;\n
Run Code Online (Sandbox Code Playgroud)\n\n

读取这些寄存器的一种简单方法是编写一个可以从用户模式应用程序调用的小型可加载内核模块:由于 Linux 内核运行在EL1,因此它完全能够读取这三个寄存器。

\n\n

例如,请参阅这篇文章,了解 Linux 可加载内核模块的精彩介绍。

\n\n

运行于 的应用程序很可能EL0无法访问只能从 访问的内存映射寄存器EL1,因为这显然会破坏保护方案。

\n\n

在 Aarch64 状态下读取这些寄存器所需的 C 代码片段为(使用gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu进行测试):

\n\n
#include <stdint.h>\n\n// read system register value ID_AA64ISAR0_EL1 (s3_0_c0_c6_0).\nstatic inline uint64_t system_read_ID_AA64ISAR0_EL1(void)\n{\n    uint64_t val;\n    asm volatile("mrs %0, s3_0_c0_c6_0" : "=r" (val));\n    return val;\n}\n\n// read system register value ID_ISAR5_EL1 (s3_0_c0_c2_5).\nstatic inline uint64_t system_read_ID_ISAR5_EL1(void)\n{\n    uint64_t val;\n    asm volatile("mrs %0, s3_0_c0_c2_5" : "=r" (val));\n    return val;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

更新#1:\nGCC 工具链无法识别所有 Arm 系统寄存器名称,但如果指定了与该寄存器关联的 coproc、opc1、CRn、CRm 和 opc2 字段的确切值,则仍然可以正确编码系统寄存器访问指令。

\n\n

在 的情况下,Arm\xc2 \ xae 架构寄存器 Armv8、Armv8-A 架构配置文件文档ID_AA64ISAR0_EL1中指定的值为

\n\n

coproc=0b11, opc1=0b000, CRn=0b0000, CRm=0b0110,opc2=0b000

\n\n

系统寄存器别名将为s[coproc]_[opc1]_c[CRn]_c[CRm]_[opc2],即s3_0_c0_c6_0的情况ID_AA64ISAR0_EL1

\n