Чтение регистров Armv8-A с помощью devmem из оболочки GNU / Linux

Я хочу прочитать значения некоторых регистров 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

Часть, в которой я не уверен, использует смещение как прямой физический адрес. Если это реальный адрес, зачем вызывать смещение, а не адрес. Если это смещение, каков базовый адрес? Я на 99% уверен, что это неправильная процедура, но как мне узнать базовый адрес, к которому нужно добавить смещение? Я искал техническое справочное руководство Armv8 и документы A53 MPCore безрезультатно. Они подробно объясняют содержимое регистров, но, похоже, предполагают, что вы читаете их из ASM, используя метку ID_AA64ISAR0_EL1.

Обновление:

Я нашел это:

Регистр базового адреса конфигурации, 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

P.S .: Это было очень проницательно, еще раз спасибо!

Обновление 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");

person smoothware    schedule 05.02.2020    source источник
comment
Не могли бы вы поделиться кодом?   -  person Michał Leon    schedule 10.05.2021
comment
@ MichałLeon По сути, это просто пустой модуль ядра Linux с двумя добавленными функциями из ответа и вызовом их в main (). Попробую найти код позже, он должен быть где-то еще ...   -  person smoothware    schedule 18.05.2021
comment
Это было бы прекрасно.   -  person Michał Leon    schedule 18.05.2021
comment
Все, что я смог найти, это фрагмент файла C, больше не нужно иметь под рукой рецепт bitbake.   -  person smoothware    schedule 20.05.2021
comment
Большое спасибо, хватит! Мне в личку за кредит (настоящее имя не обязательно).   -  person Michał Leon    schedule 22.05.2021
comment
Любая заслуга относится к ответу на этот вопрос или некоторому руководству о том, как создать модуль ядра Linux в Yocto. Ничего нового здесь особо не делал.   -  person smoothware    schedule 26.05.2021


Ответы (1)


Отказ от ответственности: я не эксперт по Aarch64, но в настоящее время изучаю архитектуру и немного читал.

Вы не можете читать ID_AA64ISAR0_EL1, ID_ISAR5_EL1 или ID_ISAR5 из приложения пользовательского режима, работающего с EL0: суффикс _EL1 означает, что для чтения этих двух регистров требуется запуск по крайней мере с EL1.

Возможно, вам будет полезно прочитать псевдокод в документации по arm здесь и здесь. В случае ID_ISAR5, например, псевдо -code очень явный:

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

Одним из простых способов чтения этих регистров было бы написать крошечный загружаемый модуль ядра, который вы могли бы вызвать из своего пользовательского приложения: поскольку ядро ​​Linux работает с EL1, оно прекрасно может читать эти три регистра.

См., Например, эту статью для хорошего введения в загружаемые модули ядра Linux.

И вполне вероятно, что приложение, работающее с EL0, не может получить доступ к регистрам с отображением памяти, доступным только с EL1, поскольку это, очевидно, нарушит схему защиты.

Фрагменты кода C, необходимые для чтения этих регистров в состоянии Aarch64, будут (протестированы с помощью

Обновление №1: набор инструментов GCC не понимает все имена системных регистров Arm, но, тем не менее, может правильно кодировать инструкции доступа к системным регистрам, если указано, какие именно значения полей coproc, opc1, CRn, CRm и opc2 связаны с этим регистром.

В случае ID_AA64ISAR0_EL1 значения, указанные в архитектуре Arm®, регистрируют Armv8, для архитектуры Armv8-A профиль документ являются:

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

Тогда псевдоним системного регистра будет s[coproc]_[opc1]_c[CRn]_c[CRm]_[opc2], то есть s3_0_c0_c6_0 в случае ID_AA64ISAR0_EL1.

person Frant    schedule 05.02.2020
comment
devmem использует устройство / dev / mem для сопоставления физических адресов, что возможно с правами root (которые у меня есть). У меня уже есть минимальный модуль ядра hello world (который в настоящее время ничего не делает). Но мне нужно было бы выяснить, как использовать встроенную сборку (для инструкции MRS) или использовать существующую оболочку, о которой я не знаю. - person smoothware; 05.02.2020
comment
@smoothware: Понятно, я соответственно увеличил свой ответ. - person Frant; 05.02.2020
comment
@smoothware: Согласны ли вы, что arm спроектировал архитектуру Aarch64 таким образом, чтобы ID_AA64ISAR0_EL1 и ID_ISAR5_EL1 не могли быть прочитаны пользовательскими приложениями, запущенными на EL0, даже с привилегиями root, и, следовательно, разрешение пользователю root использовать /dev/mem для доступа к ним противоречило бы их схеме защиты? приложение Linux, работающее с UID 0, все еще работает на Aarch64 EL0 (я полагаю). - person Frant; 05.02.2020
comment
@smoothware: документация по модели исключений очень интересно читать ИМХО. - person Frant; 05.02.2020
comment
спасибо, я попробую это в ближайшее время. Не могли бы вы объяснить, почему вы указываете s3_0_c0_c6_0 в качестве регистра вместо ID_AA64ISAR0_EL1, как указано в моей документации? И как вы придумали использовать этот ярлык? Заранее спасибо! - person smoothware; 05.02.2020
comment
@smoothware Я могу ответить на свой вопрос, оба типа ярлыков работают. - person smoothware; 05.02.2020
comment
Позвольте нам продолжить это обсуждение в чате. - person Frant; 05.02.2020